Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
CompanyResearch
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
1 / 1
 extractDomain
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace App\Http\Models;
4
5/**
6 * CompanyResearch Model
7 *
8 * Caches deep-research output (via Gemini + Google Search grounding) for a
9 * given company domain. Used internally by the roleplay auto-populate flow
10 * so that repeated persona creation for the same company reuses the cached
11 * intelligence instead of re-scraping and re-querying the LLM.
12 *
13 * @property string $_id The unique identifier
14 * @property string $domain Normalized bare domain (e.g. "vengreso.com"), unique
15 * @property string $url Original URL that triggered the research
16 * @property string $status pending | processing | completed | failed
17 * @property string $research Deep research output from Gemini (structured text)
18 * @property string $scraped_content HTML-extracted homepage content
19 * @property string|null $error Error message if status is failed
20 * @property string $requested_by User ID who first triggered the research
21 * @property \Carbon\Carbon|null $created_at
22 * @property \Carbon\Carbon|null $updated_at
23 */
24class CompanyResearch extends Moloquent
25{
26    /**
27     * The database connection name.
28     *
29     * @var string
30     */
31    protected $connection = 'mongodb';
32
33    /**
34     * The MongoDB collection name.
35     *
36     * @var string
37     */
38    protected $collection = 'company_research';
39
40    /**
41     * The attributes that are mass assignable.
42     *
43     * @var array<int, string>
44     */
45    protected $fillable = [
46        'domain',
47        'url',
48        'status',
49        'research',
50        'scraped_content',
51        'error',
52        'requested_by',
53    ];
54
55    /**
56     * The attributes that should be cast.
57     *
58     * @var array<string, string>
59     */
60    protected $casts = [
61        'created_at' => 'datetime',
62        'updated_at' => 'datetime',
63    ];
64
65    /**
66     * Extract and normalize a domain from a URL string.
67     *
68     * Strips protocol, "www." prefix, path, query, and fragment to produce
69     * a bare, lowercase domain suitable for deduplication lookups.
70     *
71     * Examples:
72     *  - "https://www.Example.COM/about?q=1" => "example.com"
73     *  - "example.com"                       => "example.com"
74     *  - "http://WWW.Example.COM/path"       => "example.com"
75     *
76     * @param  string  $url  The raw URL or domain string
77     * @return string The normalized bare domain
78     */
79    public static function extractDomain(string $url): string
80    {
81        $url = trim($url);
82        if (! preg_match('#^https?://#i', $url)) {
83            $url = 'https://'.$url;
84        }
85        $host = parse_url($url, PHP_URL_HOST);
86
87        return $host ? strtolower(preg_replace('/^www\./i', '', $host)) : strtolower($url);
88    }
89}