Test Failed
Push — develop ( e570c6...984de0 )
by Nuno
03:53
created

Aggregator   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Test Coverage

Coverage 26.53%

Importance

Changes 0
Metric Value
wmc 22
eloc 42
dl 0
loc 192
ccs 13
cts 49
cp 0.2653
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getScoutModelsByIds() 0 3 1
A makeAllSearchable() 0 12 3
A getModel() 0 3 1
A create() 0 3 1
A bootSearchable() 0 8 2
A setModel() 0 5 1
A getScoutKey() 0 9 3
A removeAllFromSearch() 0 8 2
A getModels() 0 3 1
A getSearchableCount() 0 13 3
A toSearchableArray() 0 7 3
A searchableAs() 0 3 1
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 function in_array;
17
use Laravel\Scout\Builder;
18
use Laravel\Scout\Searchable;
19
use Illuminate\Support\Collection;
20
use Illuminate\Database\Eloquent\Model;
21
use Illuminate\Database\Eloquent\SoftDeletes;
22
use Algolia\ScoutExtended\Engines\AlgoliaEngine;
23
use Algolia\ScoutExtended\Contracts\SearchableCountableContract;
24
use Algolia\ScoutExtended\Exceptions\ModelNotDefinedInAggregatorException;
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 current model instance, if any.
39
     *
40
     * @var \Illuminate\Database\Eloquent\Model|null
41
     */
42
    protected $model;
43
44
    /**
45
     * Returns the index name.
46
     *
47
     * @var string
48
     */
49
    protected $indexName;
50
51
    /**
52
     * Boot the aggregator.
53
     *
54
     * @return void
55
     */
56 6
    public static function bootSearchable(): void
57
    {
58 6
        ($self = new static)->registerSearchableMacros();
59
60 6
        $observer = tap(resolve(AggregatorObserver::class))->setAggregator(static::class, $models = $self->getModels());
61
62 6
        foreach ($models as $model) {
63 6
            $model::observe($observer);
64
        }
65 6
    }
66
67
    /**
68
     * Creates an instance of the aggregator.
69
     *
70
     * @param \Illuminate\Database\Eloquent\Model $model
71
     *
72
     * @return \Algolia\ScoutExtended\Searchable
73
     */
74 1
    public static function create(Model $model): Aggregator
75
    {
76 1
        return (new static)->setModel($model);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new static()->setModel($model) returns the type Algolia\ScoutExtended\Searchable\Aggregator which is incompatible with the documented return type Algolia\ScoutExtended\Searchable.
Loading history...
77
    }
78
79
    /**
80
     * Get the names of the models that should be aggregated.
81
     *
82
     * @return string[]
83
     */
84 6
    public function getModels(): array
85
    {
86 6
        return $this->models;
87
    }
88
89
    /**
90
     * Sets the current model.
91
     *
92
     * @param \Illuminate\Database\Eloquent\Model $model
93
     *
94
     * @return \Algolia\ScoutExtended\Searchable\Aggregator
95
     */
96 1
    public function setModel(Model $model): Aggregator
97
    {
98 1
        $this->model = $model;
99
100 1
        return $this;
101
    }
102
103
    /**
104
     * Get the current model.
105
     *
106
     * @return \Illuminate\Database\Eloquent\Model
107
     */
108
    public function getModel(): Model
109
    {
110
        return $this->model;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->model could return the type null which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Model. Consider adding an additional type-check to rule them out.
Loading history...
111
    }
112
113
    /**
114
     * Get the requested models from an array of object IDs.
115
     *
116
     * @param  \Laravel\Scout\Builder $builder
117
     * @param  array $ids
118
     *
119
     * @return \Illuminate\Support\Collection
120
     */
121
    public function getScoutModelsByIds(Builder $builder, array $ids): Collection
122
    {
123
        return resolve(ModelsResolver::class)->from($builder, static::class, $this->models, $ids);
124
    }
125
126
    /**
127
     * Get the value used to index the model.
128
     *
129
     * @return string
130
     */
131
    public function getScoutKey(): string
132
    {
133
        if ($this->model === null) {
134
            throw new ModelNotDefinedInAggregatorException();
135
        }
136
137
        $scoutKey = method_exists($this->model, 'getScoutKey') ? $this->model->getScoutKey() : $this->model->getKey();
138
139
        return UuidGenerator::getUuid($this->model).'_'.$scoutKey;
140
    }
141
142
    /**
143
     * Get the index name for the model.
144
     *
145
     * @return string
146
     */
147
    public function searchableAs(): string
148
    {
149
        return config('scout.prefix').UuidGenerator::getUuid(static::class);
150
    }
151
152
    /**
153
     * Get the searchable array of the model.
154
     *
155
     * @return array
156
     */
157
    public function toSearchableArray(): array
158
    {
159
        if ($this->model === null) {
160
            throw new ModelNotDefinedInAggregatorException();
161
        }
162
163
        return method_exists($this->model, 'toSearchableArray') ? $this->model->toSearchableArray() : $this->model->toArray();
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...
164
    }
165
166
    /**
167
     * Make all instances of the model searchable.
168
     *
169
     * @return void
170
     */
171
    public static function makeAllSearchable()
172
    {
173
        foreach ((new static)->getModels() as $model) {
174
            $instance = new $model;
175
176
            $softDeletes = in_array(SoftDeletes::class, class_uses_recursive($model)) && config('scout.soft_delete', false);
177
178
            $instance->newQuery()->when($softDeletes, function ($query) {
179
                $query->withTrashed();
180
            })->orderBy($instance->getKeyName())->get()->map(function ($model) {
181
                return static::create($model);
182
            })->searchable();
183
        }
184
    }
185
186
    /**
187
     * Remove all instances of the model from the search index.
188
     *
189
     * @return void
190
     */
191
    public static function removeAllFromSearch(): void
192
    {
193
        foreach ((new static)->getModels() as $model) {
194
            $instance = new $model;
195
196
            $instance->newQuery()->orderBy($instance->getKeyName())->get()->map(function ($model) {
197
                return static::create($model);
198
            })->unsearchable();
199
        }
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205
    public function getSearchableCount(): int
206
    {
207
        $count = 0;
208
209
        foreach ($this->getModels() as $model) {
210
            $softDeletes = in_array(SoftDeletes::class, class_uses_recursive($model), true) && config('scout.soft_delete', false);
211
212
            $count += $model::query()->when($softDeletes, function ($query) {
213
                $query->withTrashed();
214
            })->count();
215
        }
216
217
        return (int) $count;
218
    }
219
}
220