Completed
Push — master ( cb1dba...ffcb18 )
by Juuso
03:45
created

AlgoliaManager   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 267
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 97.75%

Importance

Changes 16
Bugs 4 Features 2
Metric Value
wmc 23
c 16
b 4
f 2
lcom 2
cbo 6
dl 0
loc 267
ccs 87
cts 89
cp 0.9775
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getClient() 0 8 2
A getConfig() 0 4 1
A setEnv() 0 4 1
A getEnv() 0 4 1
A pushToIndices() 0 12 2
A updateInIndices() 0 13 2
A removeFromIndices() 0 12 2
B reindex() 0 38 3
A clearIndices() 0 15 2
A __call() 0 4 1
A checkImplementsSearchableInterface() 0 8 2
A initIndices() 0 16 3
1
<?php
2
3
namespace leinonen\Yii2Algolia;
4
5
use AlgoliaSearch\Client;
6
use AlgoliaSearch\Index;
7
use leinonen\Yii2Algolia\ActiveRecord\ActiveRecordFactory;
8
9
/**
10
 * @method setConnectTimeout(int $connectTimeout, int $timeout = 30, int $searchTimeout = 5)
11
 * @method enableRateLimitForward(string $adminAPIKey, string $endUserIP, string $rateLimitAPIKey)
12
 * @method setForwarderFor(string $ip)
13
 * @method setAlgoliaUserToken(string $token)
14
 * @method disableRateLimitForward()
15
 * @method isAlive()
16
 * @method setExtraHeader(string $key, string $value)
17
 * @method mixed multipleQueries(array $queries, string $indexNameKey = "indexName", string $strategy = "none")
18
 * @method mixed listIndexes()
19
 * @method deleteIndex(string $indexName)
20
 * @method mixed moveIndex(string $srcIndexName, string $dstIndexName)
21
 * @method mixed copyIndex(string $srcIndexName, string $dstIndexName)
22
 * @method mixed getLogs(int $offset = 0, int $length = 10, string $type = "all")
23
 * @method Index initIndex(string $indexName)
24
 * @method mixed listUserKeys()
25
 * @method mixed getUserKeyACL(string $key)
26
 * @method mixed deleteUserKey(string $key)
27
 * @method mixed addUserKey(array $obj, int $validity = 0, int $maxQueriesPerIPPerHour = 0, int $maxHitsPerQuery = 0, array $indexes = null)
28
 * @method mixed updateUserKey(string $key, array $obj, int $validity = 0, int $maxQueriesPerIPPerHour = 0, int $maxHitsPerQuery = 0, array $indexes = null)
29
 * @method mixed batch(array $requests)
30
 * @method string generateSecuredApiKey(string $privateApiKey, mixed $query, string $userToken = null)
31
 * @method string buildQuery(array $args)
32
 * @method mixed request(\AlgoliaSearch\ClientContext $context, string $method, string $path, array $params, array $data, array $hostsArray, int $connectTimeout, int $readTimeout)
33
 * @method mixed doRequest(\AlgoliaSearch\ClientContext $context, string $method, string $path, array $params, array $data, array $hostsArray, int $connectTimeout, int $readTimeout)
34
 * @method \AlgoliaSearch\PlacesIndex initPlaces(string $appId, string $appKey, array $hostsArray = null, array $options = [])
35
 * @see Client
36
 */
37
class AlgoliaManager
38
{
39
    /**
40
     * @var AlgoliaFactory
41
     */
42
    protected $factory;
43
44
    /**
45
     * @var array
46
     */
47
    protected $config;
48
49
    /**
50
     * @var null|Client
51
     */
52
    protected $client;
53
54
    /**
55
     * @var ActiveRecordFactory
56
     */
57
    protected $activeRecordFactory;
58
59
    /**
60
     * @var null|string
61
     */
62
    protected $env;
63
64
    /**
65
     * Initiates a new AlgoliaManager.
66
     *
67
     * @param AlgoliaFactory $algoliaFactory
68
     * @param ActiveRecordFactory $activeRecordFactory
69
     * @param array $config Configurations for the Algolia Client.
70
     */
71 26
    public function __construct(AlgoliaFactory $algoliaFactory, ActiveRecordFactory $activeRecordFactory, array $config = [])
72
    {
73 26
        $this->factory = $algoliaFactory;
74 26
        $this->config = $config;
75 26
        $this->activeRecordFactory = $activeRecordFactory;
76 26
    }
77
78
    /**
79
     * Returns the Algolia Client.
80
     *
81
     * @return Client
82
     */
83 9
    public function getClient()
84
    {
85 9
        if (is_null($this->client)) {
86 9
            $this->client = $this->factory->make($this->config);
87 9
        }
88
89 9
        return $this->client;
90
    }
91
92
    /**
93
     * Returns the config array.
94
     *
95
     * @return array
96
     */
97 2
    public function getConfig()
98
    {
99 2
        return $this->config;
100
    }
101
102
    /**
103
     * Sets the environment for the manager.
104
     *
105
     * @param string $env
106
     */
107 26
    public function setEnv($env)
108
    {
109 26
        $this->env = $env;
110 26
    }
111
112
    /**
113
     * Returns the environment for the manager.
114
     *
115
     * @return null|string
116
     */
117
    public function getEnv()
118
    {
119
        return $this->env;
120
    }
121
122
    /**
123
     * Indexes a searchable model to all indices.
124
     *
125
     * @param SearchableInterface $searchableModel
126
     *
127
     * @return array
128
     */
129 2
    public function pushToIndices(SearchableInterface $searchableModel)
130
    {
131 2
        $indices = $this->initIndices($searchableModel);
132 2
        $response = [];
133
134 2
        foreach ($indices as $index) {
135 2
            $record = $searchableModel->getAlgoliaRecord();
136 2
            $response[$index->indexName] = $index->addObject($record, $searchableModel->getObjectID());
137 2
        }
138
139 2
        return $response;
140
    }
141
142
    /**
143
     * Updates the models data in all indices.
144
     *
145
     * @param SearchableInterface $searchableModel
146
     *
147
     * @return array
148
     */
149 2
    public function updateInIndices(SearchableInterface $searchableModel)
150
    {
151 2
        $indices = $this->initIndices($searchableModel);
152 2
        $response = [];
153
154 2
        foreach ($indices as $index) {
155 2
            $record = $searchableModel->getAlgoliaRecord();
156 2
            $record['objectID'] = $searchableModel->getObjectID();
157 2
            $response[$index->indexName] = $index->saveObject($record);
158 2
        }
159
160 2
        return $response;
161
    }
162
163
    /**
164
     * Removes a searchable model from indices.
165
     *
166
     * @param SearchableInterface $searchableModel
167
     *
168
     * @return array
169
     * @throws \Exception
170
     */
171 2
    public function removeFromIndices(SearchableInterface $searchableModel)
172
    {
173 2
        $indices = $indices = $this->initIndices($searchableModel);
174 2
        $response = [];
175
176 2
        foreach ($indices as $index) {
177 2
            $objectID = $searchableModel->getObjectID();
178 2
            $response[$index->indexName] = $index->deleteObject($objectID);
179 2
        }
180
181 2
        return $response;
182
    }
183
184
    /**
185
     * Re-indexes the indices safely for the given ActiveRecord Class.
186
     *
187
     * @param string $className The name of the ActiveRecord to be indexed.
188
     *
189
     * @return array
190
     */
191 3
    public function reindex($className)
192
    {
193 3
        $this->checkImplementsSearchableInterface($className);
194 2
        $activeRecord = $this->activeRecordFactory->make($className);
195 2
        $response = [];
196
197
        /** @var SearchableInterface[] $activeRecordEntities */
198 2
        $activeRecordEntities = $activeRecord->find()->all();
199
200
        /* @var SearchableInterface $activeRecord */
201 2
        $indices = $indices = $this->initIndices($activeRecord);
202 2
        $records = [];
203
204 2
        foreach ($activeRecordEntities as $activeRecordEntity) {
205 2
            $record = $activeRecordEntity->getAlgoliaRecord();
206 2
            $record['objectID'] = $activeRecordEntity->getObjectID();
207 2
            $records[] = $record;
208 2
        }
209
210 2
        foreach ($indices as $index) {
211 2
            $temporaryIndexName = 'tmp_' . $index->indexName;
212
213
            /** @var Index $temporaryIndex */
214 2
            $temporaryIndex = $this->initIndex($temporaryIndexName);
215 2
            $temporaryIndex->addObjects($records);
216
217 2
            $settings = $index->getSettings();
218
219
            // Temporary index overrides all the settings on the main one.
220
            // So let's set the original settings on the temporary one before atomically moving the index.
221 2
            $temporaryIndex->setSettings($settings);
222
223 2
            $response[$index->indexName] = $this->moveIndex($temporaryIndexName, $index->indexName);
224
225 2
        }
226
227 2
        return $response;
228
    }
229
230
    /**
231
     * Clears the indices for the given Class that implements SearchableInterface.
232
     *
233
     * @param string $className The name of the Class which indices are to be cleared.
234
     *
235
     * @return array
236
     */
237 2
    public function clearIndices($className)
238
    {
239 2
        $this->checkImplementsSearchableInterface($className);
240 1
        $activeRecord = $this->activeRecordFactory->make($className);
241 1
        $response = [];
242
243
        /* @var SearchableInterface $activeRecord */
244 1
        $indices = $indices = $this->initIndices($activeRecord);
245
246 1
        foreach ($indices as $index) {
247 1
            $response[$index->indexName] = $index->clearIndex();
248 1
        }
249
250 1
        return $response;
251
    }
252
253
    /**
254
     * Dynamically pass methods to the Algolia Client.
255
     *
256
     * @param string $method
257
     * @param array $parameters
258
     *
259
     * @return mixed
260
     */
261 8
    public function __call($method, $parameters)
262
    {
263 8
        return call_user_func_array([$this->getClient(), $method], $parameters);
264
    }
265
266
    /**
267
     * Checks if the given class implements SearchableInterface.
268
     *
269
     * @param string $class Either name or instance of the class to be checked.
270
     */
271 5
    private function checkImplementsSearchableInterface($class)
272
    {
273 5
        $reflectionClass = new \ReflectionClass($class);
274
275 5
        if (! $reflectionClass->implementsInterface(SearchableInterface::class)) {
276 2
            throw new \InvalidArgumentException("The class: {$reflectionClass->name} doesn't implement leinonen\\Yii2Algolia\\SearchableInterface");
277
        }
278 3
    }
279
280
    /**
281
     * Initializes indices for the given SearchableModel.
282
     *
283
     * @param SearchableInterface $searchableModel
284
     *
285
     * @return Index[]
286
     */
287 7
    private function initIndices(SearchableInterface $searchableModel)
288
    {
289 7
        $indexNames = $searchableModel->getIndices();
290
291 7
        $indices = [];
292
293 7
        foreach ($indexNames as $indexName) {
294 7
            if($this->env !== null){
295 2
                $indexName = $this->env . '_' . $indexName;
296 2
            }
297
298 7
            $indices[] = $this->initIndex($indexName);
299 7
        }
300
301 7
        return $indices;
302
    }
303
}
304