142 lines
4.5 KiB
PHP
142 lines
4.5 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use Illuminate\Console\Command;
|
||
use Meilisearch\Client as MeilisearchClient;
|
||
|
||
/**
|
||
* Configure the Meilisearch artworks index:
|
||
* – sortable attributes (all fields used in category/discover sorts)
|
||
* – filterable attributes (used in search filters)
|
||
*
|
||
* Run after any schema / toSearchableArray change:
|
||
* php artisan meilisearch:configure-index
|
||
*/
|
||
class ConfigureMeilisearchIndex extends Command
|
||
{
|
||
protected $signature = 'meilisearch:configure-index {--index=artworks : Meilisearch index name}';
|
||
protected $description = 'Push sortable and filterable attribute settings to the Meilisearch artworks index.';
|
||
|
||
/**
|
||
* Fields that can be used as sort targets in Artwork::search()->options(['sort' => …]).
|
||
* Must match keys in Artwork::toSearchableArray().
|
||
*/
|
||
private const SORTABLE_ATTRIBUTES = [
|
||
'created_at',
|
||
'published_at_ts',
|
||
'missing_thumbnail_rank',
|
||
'trending_score_24h',
|
||
'trending_score_7d',
|
||
'favorites_count',
|
||
'downloads_count',
|
||
'awards_received_count',
|
||
'awards_score_7d',
|
||
'awards_score_30d',
|
||
'views',
|
||
'likes',
|
||
'downloads',
|
||
'ranking_score',
|
||
'engagement_velocity',
|
||
'shares_count',
|
||
'comments_count',
|
||
'heat_score',
|
||
];
|
||
|
||
/**
|
||
* Fields used in filter expressions (AND category = "…" etc.).
|
||
*/
|
||
private const FILTERABLE_ATTRIBUTES = [
|
||
'id',
|
||
'is_public',
|
||
'is_approved',
|
||
'is_mature',
|
||
'is_mature_effective',
|
||
'maturity_level',
|
||
'maturity_status',
|
||
'has_missing_thumbnails',
|
||
'category',
|
||
'content_type',
|
||
'published_as_type',
|
||
'tags',
|
||
'author_id',
|
||
'orientation',
|
||
'resolution',
|
||
];
|
||
|
||
public function handle(): int
|
||
{
|
||
$prefix = config('scout.prefix', '');
|
||
$indexName = $prefix . (string) $this->option('index');
|
||
$indexSettings = $this->configuredIndexSettings($indexName);
|
||
$sortableAttributes = $this->configuredSortableAttributes($indexSettings);
|
||
$filterableAttributes = $this->configuredFilterableAttributes($indexSettings);
|
||
|
||
/** @var MeilisearchClient $client */
|
||
$client = app(MeilisearchClient::class);
|
||
|
||
$index = $client->index($indexName);
|
||
|
||
$this->info("Configuring Meilisearch index: {$indexName}");
|
||
|
||
// ── Sortable attributes ───────────────────────────────────────────────
|
||
$this->line(' → Updating sortableAttributes…');
|
||
$task = $index->updateSortableAttributes($sortableAttributes);
|
||
$this->line(" Task uid: {$task['taskUid']}");
|
||
|
||
// ── Filterable attributes ─────────────────────────────────────────────
|
||
$this->line(' → Updating filterableAttributes…');
|
||
$task2 = $index->updateFilterableAttributes($filterableAttributes);
|
||
$this->line(" Task uid: {$task2['taskUid']}");
|
||
|
||
$this->info('Done. Meilisearch will process these tasks asynchronously.');
|
||
$this->warn('Re-index artworks if sortable attributes changed: php artisan artworks:search-rebuild');
|
||
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
/**
|
||
* @return array<string, mixed>
|
||
*/
|
||
private function configuredIndexSettings(string $indexName): array
|
||
{
|
||
$settings = config('scout.meilisearch.index-settings', []);
|
||
|
||
if (! is_array($settings)) {
|
||
return [];
|
||
}
|
||
|
||
$configured = $settings[$indexName] ?? [];
|
||
|
||
return is_array($configured) ? $configured : [];
|
||
}
|
||
|
||
/**
|
||
* @param array<string, mixed> $indexSettings
|
||
* @return list<string>
|
||
*/
|
||
private function configuredSortableAttributes(array $indexSettings): array
|
||
{
|
||
$configured = $indexSettings['sortableAttributes'] ?? null;
|
||
|
||
return is_array($configured) && $configured !== []
|
||
? array_values($configured)
|
||
: self::SORTABLE_ATTRIBUTES;
|
||
}
|
||
|
||
/**
|
||
* @param array<string, mixed> $indexSettings
|
||
* @return list<string>
|
||
*/
|
||
private function configuredFilterableAttributes(array $indexSettings): array
|
||
{
|
||
$configured = $indexSettings['filterableAttributes'] ?? null;
|
||
|
||
return is_array($configured) && $configured !== []
|
||
? array_values($configured)
|
||
: self::FILTERABLE_ATTRIBUTES;
|
||
}
|
||
}
|