Files
huginn/app/Livewire/Discover/Search.php
T
m105 4c0cc5a7f5 Add language filter to Discover
The CDX languages field (ISO 639 codes, e.g. "spa,eng") has been
captured on every page since the first ingestion command, but never
surfaced anywhere. Filters via FIND_IN_SET for an exact code match
rather than a LIKE substring match, since the column holds a
comma-separated list.

Verified against real data: lang=spa returns exactly the expected 47
sites (25+22 across two pages), a bogus code renders the empty state,
and lang=spa combined with tld=es correctly narrows to 20.
2026-07-22 23:11:30 +03:00

108 lines
3.8 KiB
PHP

<?php
namespace App\Livewire\Discover;
use App\Models\Site;
use Illuminate\Contracts\View\View;
use Illuminate\Pagination\LengthAwarePaginator;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;
/**
* The competitor-discovery search: "who sells honey with a .es domain?" — keyword
* matches a site's pages via MySQL fulltext (natural language mode, so free-text input
* never trips a boolean-mode syntax error), TLD filters the site's domain suffix,
* platform filters its detected server/powered-by/generator signature, language
* filters by the CDX-reported ISO 639 code of a page's content (e.g. "spa", "eng").
*/
#[Layout('components.layouts.app')]
class Search extends Component
{
use WithPagination;
#[Url(as: 'q', history: true)]
public string $keyword = '';
#[Url(as: 'tld', history: true)]
public string $tld = '';
#[Url(as: 'platform', history: true)]
public string $platform = '';
#[Url(as: 'lang', history: true)]
public string $language = '';
public function updatingKeyword(): void
{
$this->resetPage();
}
public function updatingTld(): void
{
$this->resetPage();
}
public function updatingPlatform(): void
{
$this->resetPage();
}
public function updatingLanguage(): void
{
$this->resetPage();
}
public function render(): View
{
$keyword = trim($this->keyword);
$tld = strtolower(trim(ltrim($this->tld, '.')));
$platform = trim($this->platform);
$language = strtolower(trim($this->language));
$hasQuery = $keyword !== '' || $tld !== '' || $platform !== '' || $language !== '';
// Without any filter this would just be the full site list — that's what the
// Sites page is for. Discover only returns results once you've asked it something.
if (! $hasQuery) {
$sites = new LengthAwarePaginator([], 0, 25, 1, ['path' => request()->url()]);
} else {
$sites = Site::query()
->when(
$keyword !== '',
fn ($query) => $query->whereHas(
'pages',
fn ($pageQuery) => $pageQuery->whereFullText(['title', 'description', 'keywords', 'content'], $keyword)
)
)
->when($tld !== '', fn ($query) => $query->where('domain', 'like', '%.'.$tld))
->when($platform !== '', function ($query) use ($platform) {
$query->where(function ($query) use ($platform) {
$query->where('server', 'like', '%'.$platform.'%')
->orWhere('powered_by', 'like', '%'.$platform.'%')
->orWhere('generator', 'like', '%'.$platform.'%');
});
})
->when(
$language !== '',
// languages is a comma-separated list of ISO 639 codes (e.g. "spa,eng") —
// FIND_IN_SET matches an exact code, not a LIKE substring match.
fn ($query) => $query->whereHas(
'pages',
fn ($pageQuery) => $pageQuery->whereRaw('FIND_IN_SET(?, languages)', [$language])
)
)
->withCount(['pages as matching_pages_count' => function ($pageQuery) use ($keyword) {
if ($keyword !== '') {
$pageQuery->whereFullText(['title', 'description', 'keywords', 'content'], $keyword);
}
}])
->orderByDesc('matching_pages_count')
->orderBy('domain')
->paginate(25);
}
return view('livewire.discover.search', ['sites' => $sites, 'hasQuery' => $hasQuery]);
}
}