Test Failed
Push — develop ( 013d90...7b3751 )
by Nuno
03:38
created

UpdateJob::handle()   B

Complexity

Conditions 9
Paths 21

Size

Total Lines 42
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
eloc 25
dl 0
loc 42
ccs 0
cts 25
cp 0
rs 8.0555
c 0
b 0
f 0
cc 9
nc 21
nop 1
crap 90
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\Jobs;
15
16
use Illuminate\Support\Str;
17
use Illuminate\Support\Collection;
18
use Illuminate\Database\Eloquent\SoftDeletes;
19
use Algolia\AlgoliaSearch\Interfaces\ClientInterface;
0 ignored issues
show
Bug introduced by
The type Algolia\AlgoliaSearch\Interfaces\ClientInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use Algolia\ScoutExtended\Searchable\ObjectIdEncrypter;
21
22
/**
23
 * @internal
24
 */
25
final class UpdateJob
26
{
27
    /**
28
     * Contains a list of splittables searchables.
29
     *
30
     * Example: [
31
     *      '\App\Thread' => true,
32
     *      '\App\User' => false,
33
     * ];
34
     *
35
     * @var array
36
     */
37
    private $splittables = [];
38
39
    /**
40
     * @var \Illuminate\Support\Collection
41
     */
42
    private $searchables;
43
44
    /**
45
     * UpdateJob constructor.
46
     *
47
     * @param \Illuminate\Support\Collection $searchables
48
     *
49
     * @return void
50
     */
51
    public function __construct(Collection $searchables)
52
    {
53
        $this->searchables = $searchables;
54
    }
55
56
    /**
57
     * @param \Algolia\AlgoliaSearch\Interfaces\ClientInterface $client
58
     *
59
     * @return void
60
     */
61
    public function handle(ClientInterface $client): void
62
    {
63
        if ($this->searchables->isEmpty()) {
64
            return;
65
        }
66
67
        if ($this->usesSoftDelete($this->searchables->first()) && config('scout.soft_delete', false)) {
68
            $this->searchables->each->pushSoftDeleteMetadata();
69
        }
70
71
        $index = $client->initIndex($this->searchables->first()->searchableAs());
72
73
        $objectsToSave = [];
74
        $searchablesToDelete = [];
75
76
        foreach ($this->searchables as $key => $searchable) {
77
            if (empty($array = array_merge($searchable->toSearchableArray(), $searchable->scoutMetadata()))) {
78
                continue;
79
            }
80
81
            $array['_tags'] = ObjectIdEncrypter::encrypt($searchable);
82
83
            if ($this->shouldBeSplitted($searchable)) {
84
                [$pieces, $splittedBy] = $this->splitSearchable($searchable, $array);
85
86
                foreach ($pieces as $number => $piece) {
87
                    $array['objectID'] = ObjectIdEncrypter::encrypt($searchable, $number);
88
                    $array[$splittedBy] = $piece;
89
                    $objectsToSave[] = $array;
90
                }
91
                $searchablesToDelete[] = $searchable;
92
            } else {
93
                $array['objectID'] = ObjectIdEncrypter::encrypt($searchable);
94
                $objectsToSave[] = $array;
95
            }
96
        }
97
98
        dispatch_now(new DeleteJob(collect($searchablesToDelete)));
99
100
        $result = $index->saveObjects($objectsToSave);
101
        if (config('scout.synchronous', false)) {
102
            $result->wait();
103
        }
104
    }
105
106
    /**
107
     * @param  object $searchable
108
     *
109
     * @return bool
110
     */
111
    private function shouldBeSplitted($searchable): bool
112
    {
113
        $class = get_class($searchable->getModel());
114
115
        if (array_key_exists($class, $this->splittables)) {
116
            return $this->splittables[$class];
117
        }
118
119
        $this->splittables[$class] = false;
120
121
        foreach ($searchable->toSearchableArray() as $key => $value) {
122
            $method = 'split'.Str::camel($key);
123
            $model = $searchable->getModel();
124
            if (method_exists($model, $method)) {
125
                $this->splittables[$class] = true;
126
                break;
127
            }
128
        }
129
130
        return $this->splittables[$class];
131
    }
132
133
    /**
134
     * @param  object $searchable
135
     * @param  array $array
136
     *
137
     * @return array
138
     */
139
    private function splitSearchable($searchable, array $array): array
140
    {
141
        $splittedBy = null;
142
        $pieces = [];
143
        foreach ($array as $key => $value) {
144
            $method = 'split'.Str::camel((string) $key);
145
            $model = $searchable->getModel();
146
            if (method_exists($model, $method)) {
147
                $result = $model->{$method}($value);
148
149
                if (is_array($result)) {
150
                    $pieces = $result;
151
                } else {
152
                    if (is_string($result)) {
153
                        $pieces = (new $result)($value);
154
                    } else {
155
                        if (is_object($result)) {
156
                            $pieces = $result->__invoke($value);
157
                        }
158
                    }
159
                }
160
                $splittedBy = $key;
161
                break;
162
            }
163
        }
164
165
        return [$pieces, $splittedBy];
166
    }
167
168
    /**
169
     * Determine if the given searchable uses soft deletes.
170
     *
171
     * @param  object $searchable
172
     * @return bool
173
     */
174
    private function usesSoftDelete($searchable)
175
    {
176
        return $searchable instanceof Model && in_array(SoftDeletes::class, class_uses_recursive($searchable));
0 ignored issues
show
Bug introduced by
The type Algolia\ScoutExtended\Jobs\Model was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
177
    }
178
}
179