Skip to content

Commit 3f8ce3b

Browse files
committed
fix: wip
1 parent f3aa291 commit 3f8ce3b

File tree

2 files changed

+173
-22
lines changed

2 files changed

+173
-22
lines changed

src/Fields/Concerns/CanSearch.php

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Fields\Concerns;
4+
5+
use Binaryk\LaravelRestify\Contracts\RestifySearchable;
6+
use Binaryk\LaravelRestify\Filters\MatchFilter;
7+
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
8+
9+
trait CanSearch
10+
{
11+
protected mixed $searchableColumn = null;
12+
13+
protected ?string $searchableType = null;
14+
15+
public function matchable(mixed $column = null, ?string $type = null): self
16+
{
17+
if ($column === false) {
18+
$this->searchableColumn = null;
19+
$this->searchableType = null;
20+
21+
return $this;
22+
}
23+
24+
if (is_callable($column)) {
25+
$this->searchableColumn = $column;
26+
$this->searchableType = 'custom';
27+
28+
return $this;
29+
}
30+
31+
if ($column instanceof MatchFilter) {
32+
$this->searchableColumn = $column;
33+
$this->searchableType = 'custom';
34+
35+
return $this;
36+
}
37+
38+
$this->searchableColumn = $column ?? $this->getAttribute();
39+
$this->searchableType = $type ?? $this->guessMatchType();
40+
41+
return $this;
42+
}
43+
44+
public function matchableCallback(callable $callback): self
45+
{
46+
return $this->matchable($callback, 'custom');
47+
}
48+
49+
public function matchableText(?string $column = null): self
50+
{
51+
return $this->matchable($column, RestifySearchable::MATCH_TEXT);
52+
}
53+
54+
public function matchableBool(?string $column = null): self
55+
{
56+
return $this->matchable($column, RestifySearchable::MATCH_BOOL);
57+
}
58+
59+
public function matchableBoolean(?string $column = null): self
60+
{
61+
return $this->matchableBool($column);
62+
}
63+
64+
public function matchableInteger(?string $column = null): self
65+
{
66+
return $this->matchable($column, RestifySearchable::MATCH_INTEGER);
67+
}
68+
69+
public function matchableInt(?string $column = null): self
70+
{
71+
return $this->matchableInteger($column);
72+
}
73+
74+
public function matchableDatetime(?string $column = null): self
75+
{
76+
return $this->matchable($column, RestifySearchable::MATCH_DATETIME);
77+
}
78+
79+
public function matchableDate(?string $column = null): self
80+
{
81+
return $this->matchableDatetime($column);
82+
}
83+
84+
public function matchableBetween(?string $column = null): self
85+
{
86+
return $this->matchable($column, RestifySearchable::MATCH_BETWEEN);
87+
}
88+
89+
public function matchableArray(?string $column = null): self
90+
{
91+
return $this->matchable($column, RestifySearchable::MATCH_ARRAY);
92+
}
93+
94+
public function isMatchable(RestifyRequest $request = null): bool
95+
{
96+
if (is_callable($this->searchableColumn)) {
97+
return true;
98+
}
99+
100+
return ! is_null($this->searchableColumn);
101+
}
102+
103+
public function getMatchColumn(RestifyRequest $request = null): mixed
104+
{
105+
if (! $this->isMatchable($request)) {
106+
return null;
107+
}
108+
109+
return $this->searchableColumn;
110+
}
111+
112+
public function getMatchType(RestifyRequest $request = null): ?string
113+
{
114+
if (! $this->isMatchable($request)) {
115+
return null;
116+
}
117+
118+
return $this->searchableType;
119+
}
120+
121+
protected function guessMatchType(): string
122+
{
123+
// Use field type detection from Field class if available
124+
if (method_exists($this, 'guessFieldType')) {
125+
$fieldType = $this->guessFieldType();
126+
127+
return match ($fieldType) {
128+
'boolean' => RestifySearchable::MATCH_BOOL,
129+
'number' => RestifySearchable::MATCH_INTEGER,
130+
'array' => RestifySearchable::MATCH_ARRAY,
131+
default => RestifySearchable::MATCH_TEXT,
132+
};
133+
}
134+
135+
// Fallback to attribute name patterns
136+
$attribute = $this->getAttribute();
137+
138+
if (! is_string($attribute)) {
139+
return RestifySearchable::MATCH_TEXT;
140+
}
141+
142+
$attribute = strtolower($attribute);
143+
144+
// Boolean patterns
145+
if (preg_match('/^(is_|has_|can_|should_|will_|was_|were_)/', $attribute) ||
146+
in_array($attribute,
147+
['active', 'enabled', 'disabled', 'verified', 'published', 'featured', 'public', 'private'])) {
148+
return RestifySearchable::MATCH_BOOL;
149+
}
150+
151+
// Number patterns
152+
if (preg_match('/_(id|count|number|amount|price|cost|total|sum|quantity|qty)$/', $attribute) ||
153+
in_array($attribute,
154+
['id', 'age', 'year', 'month', 'day', 'hour', 'minute', 'second', 'weight', 'height', 'size'])) {
155+
return RestifySearchable::MATCH_INTEGER;
156+
}
157+
158+
// Date patterns
159+
if (preg_match('/_(at|date|time)$/', $attribute) ||
160+
in_array($attribute,
161+
['created_at', 'updated_at', 'deleted_at', 'published_at', 'birthday', 'date_of_birth'])) {
162+
return RestifySearchable::MATCH_DATETIME;
163+
}
164+
165+
// Array patterns (JSON fields)
166+
if (preg_match('/_(json|data|metadata|config|settings|options|tags)$/', $attribute)) {
167+
return RestifySearchable::MATCH_ARRAY;
168+
}
169+
170+
// Default to text matching
171+
return RestifySearchable::MATCH_TEXT;
172+
}
173+
}

src/Services/Search/RepositorySearchService.php

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -142,28 +142,6 @@ public function prepareSearchFields(RestifyRequest $request, $query)
142142
$query->orWhere($query->getModel()->getQualifiedKeyName(), $search);
143143
}
144144

145-
foreach ($this->repository::searchables() as $key => $column) {
146-
$filter = $column instanceof Filter
147-
? $column
148-
: SearchableFilter::make()->setColumn(
149-
$model->qualifyColumn(is_numeric($key) ? $column : $key)
150-
);
151-
152-
$filter
153-
->setRepository($this->repository)
154-
->setColumn(
155-
$filter->column ?? $model->qualifyColumn(is_numeric($key) ? $column : $key)
156-
);
157-
158-
$filter->filter($request, $query, $search);
159-
160-
$this->repository::collectRelated()
161-
->onlySearchable($request)
162-
->map(function (BelongsTo $field) {
163-
return SearchableFilter::make()->setRepository($this->repository)->usingBelongsTo($field);
164-
})
165-
->each(fn (SearchableFilter $filter) => $filter->filter($request, $query, $search));
166-
}
167145
});
168146

169147
return $query;

0 commit comments

Comments
 (0)