anonymous//src/Searchable/Aggregator.php$0
last analyzed

Complexity

Total Complexity 0

Size/Duplication

Total Lines 1
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 1
ccs 0
cts 0
cp 0
c 0
b 0
f 0
wmc 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Scout Extended.
7
 *
8
 * (c) Algolia Team <[email protected]>
9
 *
10
 *  For the full copyright and license information, please view the LICENSE
11
 *  file that was distributed with this source code.
12
 */
13
14
namespace Algolia\ScoutExtended\Searchable;
15
16
use Algolia\ScoutExtended\Contracts\SearchableCountableContract;
17
use Algolia\ScoutExtended\Exceptions\ModelNotDefinedInAggregatorException;
18
use Illuminate\Database\Eloquent\Collection;
19
use Illuminate\Database\Eloquent\Model;
20
use Illuminate\Database\Eloquent\SoftDeletes;
21
use Illuminate\Support\Str;
22
use function in_array;
23
use Laravel\Scout\Events\ModelsImported;
24
use Laravel\Scout\Searchable;
25
26
abstract class Aggregator implements SearchableCountableContract
27
{
28
    use Searchable;
0 ignored issues
show
Bug introduced by
The trait Laravel\Scout\Searchable requires the property $queryCallback which is not provided by Algolia\ScoutExtended\Searchable\Aggregator.
Loading history...
29
30
    /**
31
     * The names of the models that should be aggregated.
32
     *
33
     * @var string[]
34
     */
35
    protected $models = [];
36
37
    /**
38
     * The model being queried, if any.
39
     *
40
     * @var \Illuminate\Database\Eloquent\Model|null
41
     */
42
    protected $model;
43
44
    /**
45
     * The relationships per model that should be loaded.
46
     *
47
     * @var mixed[]
48
     */
49
    protected $relations = [];
50
51
    /**
52
     * Returns the index name.
53
     *
54
     * @var string
55
     */
56
    protected $indexName;
57
58
    /**
59
     * Boot the aggregator.
60
     *
61
     * @return void
62
     */
63 7
    public static function bootSearchable(): void
64
    {
65 7
        ($self = new static)->registerSearchableMacros();
66
67 7
        $observer = tap(app(AggregatorObserver::class))->setAggregator(static::class, $models = $self->getModels());
68
69 7
        foreach ($models as $model) {
70 7
            $model::observe($observer);
71
        }
72 7
    }
73
74
    /**
75
     * Creates an instance of the aggregator.
76
     *
77
     * @param \Illuminate\Database\Eloquent\Model $model
78
     *
79
     * @return \Algolia\ScoutExtended\Searchable\Aggregator
80
     */
81 8
    public static function create(Model $model): Aggregator
82
    {
83 8
        return (new static)->setModel($model);
84
    }
85
86
    /**
87
     * Get the names of the models that should be aggregated.
88
     *
89
     * @return string[]
90
     */
91 7
    public function getModels(): array
92
    {
93 7
        return $this->models;
94
    }
95
96
    /**
97
     * Get the model instance being queried.
98
     *
99
     * @return \Illuminate\Database\Eloquent\Model
100
     *
101
     * @throws \Algolia\ScoutExtended\Exceptions\ModelNotDefinedInAggregatorException
102
     */
103 8
    public function getModel(): Model
104
    {
105 8
        if ($this->model === null) {
106
            throw new ModelNotDefinedInAggregatorException();
107
        }
108
109 8
        return $this->model;
110
    }
111
112
    /**
113
     * Set a model instance for the model being queried.
114
     *
115
     * @param \Illuminate\Database\Eloquent\Model $model
116
     *
117
     * @return \Algolia\ScoutExtended\Searchable\Aggregator
118
     */
119 8
    public function setModel(Model $model): Aggregator
120
    {
121 8
        $this->model = $model;
122
123 8
        return $this;
124
    }
125
126
    /**
127
     * Get the relations to load.
128
     *
129
     * @param  string  $modelClass
130
     *
131
     * @return  array
132
     */
133 2
    public function getRelations($modelClass): array
134
    {
135 2
        return $this->relations[$modelClass] ?? [];
136
    }
137
138
    /**
139
     * Get the value used to index the model.
140
     *
141
     * @return mixed
142
     */
143 7
    public function getScoutKey()
144
    {
145 7
        if ($this->model === null) {
146
            throw new ModelNotDefinedInAggregatorException();
147
        }
148
149 7
        return method_exists($this->model, 'getScoutKey') ? $this->model->getScoutKey() : $this->model->getKey();
150
    }
151
152
    /**
153
     * Get the index name for the searchable.
154
     *
155
     * @return string
156
     */
157 9
    public function searchableAs(): string
158
    {
159 9
        return config('scout.prefix').str_replace('\\', '', Str::snake(class_basename(static::class)));
160
    }
161
162
    /**
163
     * Get the searchable array of the searchable.
164
     *
165
     * @return array
166
     */
167 7
    public function toSearchableArray(): array
168
    {
169 7
        if ($this->model === null) {
170
            throw new ModelNotDefinedInAggregatorException();
171
        }
172
173 7
        return method_exists($this->model, 'toSearchableArray') ? $this->model->toSearchableArray() :
0 ignored issues
show
Bug Best Practice introduced by
The expression return method_exists($th...$this->model->toArray() could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
174 7
            $this->model->toArray();
175
    }
176
177
    /**
178
     * Make all instances of the model searchable.
179
     *
180
     * @return void
181
     */
182 1
    public static function makeAllSearchable()
183
    {
184 1
        foreach ((new static)->getModels() as $model) {
185 1
            $instance = new $model;
186
187
            $softDeletes =
188 1
                in_array(SoftDeletes::class, class_uses_recursive($model)) && config('scout.soft_delete', false);
189
190
            $instance->newQuery()->when($softDeletes, function ($query) {
191 1
                $query->withTrashed();
192
            })->orderBy($instance->getKeyName())->chunk(config('scout.chunk.searchable', 500), function ($models) {
193
                $models = $models->map(function ($model) {
194 1
                    return static::create($model);
195 1
                })->filter->shouldBeSearchable();
196
197 1
                $models->searchable();
198
199 1
                event(new ModelsImported($models));
200 1
            });
201
        }
202 1
    }
203
204
    /**
205
     * {@inheritdoc}
206
     *
207
     * @internal
208
     */
209 7
    public function searchable(): void
210
    {
211 7
        AggregatorCollection::make([$this])->searchable();
212 7
    }
213
214
    /**
215
     * {@inheritdoc}
216
     *
217
     * @internal
218
     */
219 4
    public function unsearchable(): void
220
    {
221 4
        AggregatorCollection::make([$this])->unsearchable();
222 4
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227
    public function getSearchableCount(): int
228
    {
229
        $count = 0;
230
231
        foreach ($this->getModels() as $model) {
232
            $softDeletes =
233
                in_array(SoftDeletes::class, class_uses_recursive($model), true) && config('scout.soft_delete', false);
234
235
            $count += $model::query()->when($softDeletes, function ($query) {
236
                $query->withTrashed();
237
            })->count();
238
        }
239
240
        return (int) $count;
241
    }
242
243
    /**
244
     * Create a new Eloquent Collection instance.
245
     *
246
     * @param  array  $searchables
247
     *
248
     * @return \Illuminate\Database\Eloquent\Collection
249
     */
250 2
    public function newCollection(array $searchables = []): Collection
251
    {
252 2
        return new Collection($searchables);
253
    }
254
255
    /**
256
     * Handle dynamic method calls into the model.
257
     *
258
     * @param  string $method
259
     * @param  array $parameters
260
     *
261
     * @return mixed
262
     */
263
    public function __call($method, $parameters)
264
    {
265
        $model = $this->model ?? new class extends Model {
266
        };
267
268
        return $model->$method(...$parameters);
269
    }
270
}
271