Completed
Push — master ( 554b31...9f86af )
by Nuno
31:31 queued 27:37
created

Aggregator::unsearchable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 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 function in_array;
17
use Illuminate\Support\Str;
18
use Laravel\Scout\Searchable;
19
use Illuminate\Database\Eloquent\Model;
20
use Laravel\Scout\Events\ModelsImported;
21
use Illuminate\Database\Eloquent\SoftDeletes;
22
use Algolia\ScoutExtended\Contracts\SearchableCountableContract;
23
use Algolia\ScoutExtended\Exceptions\ModelNotDefinedInAggregatorException;
24
25
abstract class Aggregator implements SearchableCountableContract
26
{
27
    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...
28
29
    /**
30
     * The names of the models that should be aggregated.
31
     *
32
     * @var string[]
33
     */
34
    protected $models = [];
35
36
    /**
37
     * The model being queried, if any.
38
     *
39
     * @var \Illuminate\Database\Eloquent\Model|null
40
     */
41
    protected $model;
42
43
    /**
44
     * Returns the index name.
45
     *
46
     * @var string
47
     */
48
    protected $indexName;
49
50
    /**
51
     * Boot the aggregator.
52
     *
53
     * @return void
54
     */
55 6
    public static function bootSearchable(): void
56
    {
57 6
        ($self = new static)->registerSearchableMacros();
58
59 6
        $observer = tap(resolve(AggregatorObserver::class))->setAggregator(static::class, $models = $self->getModels());
60
61 6
        foreach ($models as $model) {
62 6
            $model::observe($observer);
63
        }
64 6
    }
65
66
    /**
67
     * Creates an instance of the aggregator.
68
     *
69
     * @param \Illuminate\Database\Eloquent\Model $model
70
     *
71
     * @return \Algolia\ScoutExtended\Searchable\Aggregator
72
     */
73 7
    public static function create(Model $model): Aggregator
74
    {
75 7
        return (new static)->setModel($model);
76
    }
77
78
    /**
79
     * Get the names of the models that should be aggregated.
80
     *
81
     * @return string[]
82
     */
83 6
    public function getModels(): array
84
    {
85 6
        return $this->models;
86
    }
87
88
    /**
89
     * Get the model instance being queried.
90
     *
91
     * @return \Illuminate\Database\Eloquent\Model
92
     *
93
     * @throws \Algolia\ScoutExtended\Exceptions\ModelNotDefinedInAggregatorException
94
     */
95 7
    public function getModel(): Model
96
    {
97 7
        if ($this->model === null) {
98
            throw new ModelNotDefinedInAggregatorException();
99
        }
100
101 7
        return $this->model;
102
    }
103
104
    /**
105
     * Set a model instance for the model being queried.
106
     *
107
     * @param \Illuminate\Database\Eloquent\Model $model
108
     *
109
     * @return \Algolia\ScoutExtended\Searchable\Aggregator
110
     */
111 7
    public function setModel(Model $model): Aggregator
112
    {
113 7
        $this->model = $model;
114
115 7
        return $this;
116
    }
117
118
    /**
119
     * Get the value used to index the model.
120
     *
121
     * @return mixed
122
     */
123 6
    public function getScoutKey()
124
    {
125 6
        if ($this->model === null) {
126
            throw new ModelNotDefinedInAggregatorException();
127
        }
128
129 6
        return method_exists($this->model, 'getScoutKey') ? $this->model->getScoutKey() : $this->model->getKey();
130
    }
131
132
    /**
133
     * Get the index name for the searchable.
134
     *
135
     * @return string
136
     */
137 8
    public function searchableAs(): string
138
    {
139 8
        return config('scout.prefix').str_replace('\\', '', Str::snake(class_basename(static::class)));
140
    }
141
142
    /**
143
     * Get the searchable array of the searchable.
144
     *
145
     * @return array
146
     */
147 6
    public function toSearchableArray(): array
148
    {
149 6
        if ($this->model === null) {
150
            throw new ModelNotDefinedInAggregatorException();
151
        }
152
153 6
        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...
154 6
            $this->model->toArray();
155
    }
156
157
    /**
158
     * Make all instances of the model searchable.
159
     *
160
     * @return void
161
     */
162 1
    public static function makeAllSearchable()
163
    {
164 1
        foreach ((new static)->getModels() as $model) {
165 1
            $instance = new $model;
166
167
            $softDeletes =
168 1
                in_array(SoftDeletes::class, class_uses_recursive($model)) && config('scout.soft_delete', false);
169
170
            $instance->newQuery()->when($softDeletes, function ($query) {
171
                $query->withTrashed();
172
            })->orderBy($instance->getKeyName())->chunk(config('scout.chunk.searchable', 500), function ($models) {
173
                $models = $models->map(function ($model) {
174 1
                    return static::create($model);
175 1
                })->filter->shouldBeSearchable();
176
177 1
                $models->searchable();
178
179 1
                event(new ModelsImported($models));
180 1
            });
181
        }
182 1
    }
183
184
    /**
185
     * {@inheritdoc}
186
     */
187 6
    public function searchable(): void
188
    {
189 6
        AggregatorCollection::make([$this])->searchable();
190 6
    }
191
192
    /**
193
     * {@inheritdoc}
194
     */
195 4
    public function unsearchable(): void
196
    {
197 4
        AggregatorCollection::make([$this])->unsearchable();
198 4
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function getSearchableCount(): int
204
    {
205
        $count = 0;
206
207
        foreach ($this->getModels() as $model) {
208
            $softDeletes =
209
                in_array(SoftDeletes::class, class_uses_recursive($model), true) && config('scout.soft_delete', false);
210
211
            $count += $model::query()->when($softDeletes, function ($query) {
212
                $query->withTrashed();
213
            })->count();
214
        }
215
216
        return (int) $count;
217
    }
218
219
    /**
220
     * Handle dynamic method calls into the model.
221
     *
222
     * @param  string $method
223
     * @param  array $parameters
224
     * @return mixed
225
     */
226
    public function __call($method, $parameters)
227
    {
228
        $model = $this->model ?? new class extends Model {
229
        };
230
231
        return $model->$method(...$parameters);
232
    }
233
}
234