Files
core/src/Search/ProductIndexer.php
T

64 lines
2.1 KiB
PHP
Raw Normal View History

<?php
namespace Modules\Core\Search;
2026-08-24 12:41:28 +03:00
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
2026-08-24 12:41:28 +03:00
use Lunar\Models\Currency;
use Lunar\Models\Product;
use Lunar\Search\ProductIndexer as BaseProductIndexer;
/**
2026-08-24 12:41:28 +03:00
* Extends Lunar's own indexer to add fields needed for storefront listing/filtering
* (Modules\Core\Catalog\ProductService) that aren't part of Lunar's default document:
* collection membership and a comparable price. Neither is filterable in Meilisearch
* until `php artisan lunar:meilisearch:setup` re-syncs index settings and the index is
* refreshed — see docs/product-listing.md.
*/
class ProductIndexer extends BaseProductIndexer
{
2026-08-24 12:41:28 +03:00
public function getFilterableFields(): array
{
return [
...parent::getFilterableFields(),
'brand',
'collections',
'price',
];
}
public function makeAllSearchableUsing(Builder $query): Builder
{
return parent::makeAllSearchableUsing($query)->with(['collections', 'variants.prices']);
}
public function toSearchableArray(Model $model): array
{
2026-08-24 12:41:28 +03:00
/** @var Product $model */
$data = parent::toSearchableArray($model);
2026-08-24 12:41:28 +03:00
$data['collections'] = $model->collections->pluck('id')->map(fn ($id) => (string) $id)->all();
$data['price'] = $this->cheapestPrice($model);
return $data;
}
2026-08-24 12:41:28 +03:00
/**
* The cheapest variant's base price (no customer group) in the default currency,
* as a float in major units — e.g. 19.99, not 1999. Null if the product has no
* variant with a price in that currency yet, so it's excluded from price filters
* rather than sorting to the bottom as if it were free.
*/
private function cheapestPrice(Product $model): ?float
{
$currency = Currency::getDefault();
$price = $model->variants
->flatMap(fn ($variant) => $variant->prices)
->filter(fn ($price) => $price->currency_id === $currency->id && $price->customer_group_id === null)
->min(fn ($price) => $price->price->value);
return $price !== null ? $price / (10 ** $currency->decimal_places) : null;
}
}