Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
284
src/Framework/Search/SearchQueryBuilder.php
Normal file
284
src/Framework/Search/SearchQueryBuilder.php
Normal file
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Search;
|
||||
|
||||
/**
|
||||
* Fluent builder for search queries
|
||||
*/
|
||||
final class SearchQueryBuilder
|
||||
{
|
||||
private string $query = '*';
|
||||
|
||||
private array $filters = [];
|
||||
|
||||
private array $boosts = [];
|
||||
|
||||
private array $fields = [];
|
||||
|
||||
private array $highlightFields = [];
|
||||
|
||||
private int $limit = 20;
|
||||
|
||||
private int $offset = 0;
|
||||
|
||||
private SearchSortBy $sortBy;
|
||||
|
||||
private bool $enableHighlighting = true;
|
||||
|
||||
private bool $enableFuzzyMatching = false;
|
||||
|
||||
private float $minScore = 0.0;
|
||||
|
||||
public function __construct(
|
||||
private readonly SearchEngine $engine,
|
||||
private readonly string $entityType
|
||||
) {
|
||||
$this->sortBy = SearchSortBy::relevance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the search query string
|
||||
*/
|
||||
public function query(string $query): self
|
||||
{
|
||||
$this->query = $query;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a filter
|
||||
*/
|
||||
public function filter(string $field, SearchFilter $filter): self
|
||||
{
|
||||
$this->filters[$field] = $filter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple filters at once
|
||||
*/
|
||||
public function filters(array $filters): self
|
||||
{
|
||||
foreach ($filters as $field => $value) {
|
||||
if ($value instanceof SearchFilter) {
|
||||
$this->filters[$field] = $value;
|
||||
} else {
|
||||
$this->filters[$field] = SearchFilter::equals($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field boost
|
||||
*/
|
||||
public function boost(string $field, float $boost): self
|
||||
{
|
||||
$this->boosts[$field] = $boost;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restrict search to specific fields
|
||||
*/
|
||||
public function fields(array $fields): self
|
||||
{
|
||||
$this->fields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fields to highlight
|
||||
*/
|
||||
public function highlight(array $fields): self
|
||||
{
|
||||
$this->highlightFields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set result limit
|
||||
*/
|
||||
public function limit(int $limit): self
|
||||
{
|
||||
$this->limit = $limit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set result offset for pagination
|
||||
*/
|
||||
public function offset(int $offset): self
|
||||
{
|
||||
$this->offset = $offset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pagination (page-based)
|
||||
*/
|
||||
public function page(int $page, int $perPage = 20): self
|
||||
{
|
||||
$this->limit = $perPage;
|
||||
$this->offset = ($page - 1) * $perPage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by relevance (default)
|
||||
*/
|
||||
public function sortByRelevance(): self
|
||||
{
|
||||
$this->sortBy = SearchSortBy::relevance();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by a field
|
||||
*/
|
||||
public function sortBy(string $field, SearchSortDirection $direction = SearchSortDirection::ASC): self
|
||||
{
|
||||
$this->sortBy = SearchSortBy::field($field, $direction);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by multiple fields
|
||||
*/
|
||||
public function sortByMultiple(SearchSortField ...$fields): self
|
||||
{
|
||||
$this->sortBy = SearchSortBy::multiple(...$fields);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable highlighting
|
||||
*/
|
||||
public function highlighting(bool $enable): self
|
||||
{
|
||||
$this->enableHighlighting = $enable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable fuzzy matching
|
||||
*/
|
||||
public function fuzzy(bool $enable): self
|
||||
{
|
||||
$this->enableFuzzyMatching = $enable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set minimum score threshold
|
||||
*/
|
||||
public function minScore(float $minScore): self
|
||||
{
|
||||
$this->minScore = $minScore;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common filter shortcuts
|
||||
*/
|
||||
public function where(string $field, mixed $value): self
|
||||
{
|
||||
return $this->filter($field, SearchFilter::equals($value));
|
||||
}
|
||||
|
||||
public function whereIn(string $field, array $values): self
|
||||
{
|
||||
return $this->filter($field, SearchFilter::in($values));
|
||||
}
|
||||
|
||||
public function whereRange(string $field, mixed $min, mixed $max): self
|
||||
{
|
||||
return $this->filter($field, SearchFilter::range($min, $max));
|
||||
}
|
||||
|
||||
public function whereGreaterThan(string $field, mixed $value): self
|
||||
{
|
||||
return $this->filter($field, SearchFilter::greaterThan($value));
|
||||
}
|
||||
|
||||
public function whereLessThan(string $field, mixed $value): self
|
||||
{
|
||||
return $this->filter($field, SearchFilter::lessThan($value));
|
||||
}
|
||||
|
||||
public function whereContains(string $field, string $value): self
|
||||
{
|
||||
return $this->filter($field, SearchFilter::contains($value));
|
||||
}
|
||||
|
||||
public function whereStartsWith(string $field, string $value): self
|
||||
{
|
||||
return $this->filter($field, SearchFilter::startsWith($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return the search query
|
||||
*/
|
||||
public function build(): SearchQuery
|
||||
{
|
||||
return new SearchQuery(
|
||||
entityType: $this->entityType,
|
||||
query: $this->query,
|
||||
filters: $this->filters,
|
||||
boosts: $this->boosts,
|
||||
fields: $this->fields,
|
||||
highlightFields: $this->highlightFields,
|
||||
limit: $this->limit,
|
||||
offset: $this->offset,
|
||||
sortBy: $this->sortBy,
|
||||
enableHighlighting: $this->enableHighlighting,
|
||||
enableFuzzyMatching: $this->enableFuzzyMatching,
|
||||
minScore: $this->minScore
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and execute the search query
|
||||
*/
|
||||
public function search(): SearchResult
|
||||
{
|
||||
return $this->engine->search($this->build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute search and return only the first result
|
||||
*/
|
||||
public function first(): ?SearchHit
|
||||
{
|
||||
$result = $this->limit(1)->search();
|
||||
|
||||
return $result->hits[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count total results without retrieving them
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
$result = $this->limit(0)->search();
|
||||
|
||||
return $result->total;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user