Feat: Displaying Draft Products, only when AppDebug = true
This commit is contained in:
@@ -254,7 +254,10 @@ class ProductService
|
|||||||
public function random(int $limit): array
|
public function random(int $limit): array
|
||||||
{
|
{
|
||||||
$raw = Product::search('')
|
$raw = Product::search('')
|
||||||
->options(['attributesToRetrieve' => ['id']])
|
->options([
|
||||||
|
'attributesToRetrieve' => ['id'],
|
||||||
|
'filter' => $this->filterBuilder->withVisibility(),
|
||||||
|
])
|
||||||
->raw();
|
->raw();
|
||||||
|
|
||||||
$ids = collect($raw['hits'] ?? [])->pluck('id')->shuffle()->take($limit)->values();
|
$ids = collect($raw['hits'] ?? [])->pluck('id')->shuffle()->take($limit)->values();
|
||||||
@@ -287,7 +290,7 @@ class ProductService
|
|||||||
private function findAllWhere(string $filter, int $limit = 1000): array
|
private function findAllWhere(string $filter, int $limit = 1000): array
|
||||||
{
|
{
|
||||||
$paginator = Product::search('')
|
$paginator = Product::search('')
|
||||||
->options(['filter' => $filter])
|
->options(['filter' => $this->filterBuilder->withVisibility($filter)])
|
||||||
->paginateRaw(perPage: $limit, page: 1);
|
->paginateRaw(perPage: $limit, page: 1);
|
||||||
|
|
||||||
return collect($this->localizer->hitsFrom($paginator))
|
return collect($this->localizer->hitsFrom($paginator))
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ use Modules\Core\Catalog\DTOs\ProductFilters;
|
|||||||
* out of ProductService (where it originated, scoped to browsing/filtering
|
* out of ProductService (where it originated, scoped to browsing/filtering
|
||||||
* without a search term) so ProductSearchService can apply the exact same
|
* without a search term) so ProductSearchService can apply the exact same
|
||||||
* filter semantics to a text query too, rather than reimplementing it.
|
* filter semantics to a text query too, rather than reimplementing it.
|
||||||
|
*
|
||||||
|
* Also the single place that composes the draft-visibility clause (see
|
||||||
|
* withVisibility()) — every Meilisearch `filter` string ProductService
|
||||||
|
* constructs, including the handful of ad-hoc ones that don't call build()
|
||||||
|
* at all (getById()/getBySlug()'s id lookup, random()'s id-only fetch),
|
||||||
|
* goes through this class so none of them can silently omit it the way a
|
||||||
|
* status filter was missing everywhere until now.
|
||||||
*/
|
*/
|
||||||
class ProductFilterBuilder
|
class ProductFilterBuilder
|
||||||
{
|
{
|
||||||
@@ -19,10 +26,10 @@ class ProductFilterBuilder
|
|||||||
* ProductService::priceRange() excludes 'price' so a price slider's own
|
* ProductService::priceRange() excludes 'price' so a price slider's own
|
||||||
* bounds don't shrink to whatever range is already selected on it.
|
* bounds don't shrink to whatever range is already selected on it.
|
||||||
*/
|
*/
|
||||||
public function build(?ProductFilters $filters, array $exclude = []): ?string
|
public function build(?ProductFilters $filters, array $exclude = []): string
|
||||||
{
|
{
|
||||||
if ($filters === null) {
|
if ($filters === null) {
|
||||||
return null;
|
return $this->withVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
$clauses = Collection::make([
|
$clauses = Collection::make([
|
||||||
@@ -36,6 +43,27 @@ class ProductFilterBuilder
|
|||||||
'inStockOnly' => $filters->inStockOnly ? 'in_stock = true' : null,
|
'inStockOnly' => $filters->inStockOnly ? 'in_stock = true' : null,
|
||||||
])->except($exclude)->filter();
|
])->except($exclude)->filter();
|
||||||
|
|
||||||
return $clauses->isEmpty() ? null : $clauses->join(' AND ');
|
return $this->withVisibility($clauses->isEmpty() ? null : $clauses->join(' AND '));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A draft product (status = 'draft', see Lunar\Filament\Resources\
|
||||||
|
* ProductResource's own status Select) is only ever visible while
|
||||||
|
* APP_DEBUG is true — a merchant/developer previewing an unfinished
|
||||||
|
* product locally or on a staging box, never a real storefront
|
||||||
|
* visitor. Every ProductService method that builds a Meilisearch
|
||||||
|
* `filter` string, build() included, calls this rather than passing
|
||||||
|
* $rawClause straight to Product::search() — the one seam that
|
||||||
|
* guarantees none of them can omit the visibility rule.
|
||||||
|
*
|
||||||
|
* Always returns a non-empty string (never null) — a bare
|
||||||
|
* 'status = "published"' is itself a complete, valid Meilisearch
|
||||||
|
* filter on its own when $rawClause is null.
|
||||||
|
*/
|
||||||
|
public function withVisibility(?string $rawClause = null): string
|
||||||
|
{
|
||||||
|
$visibility = config('app.debug') ? null : 'status = "published"';
|
||||||
|
|
||||||
|
return Collection::make([$visibility, $rawClause])->filter()->join(' AND ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user