Element   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 317
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 9
dl 0
loc 317
ccs 0
cts 126
cp 0
rs 10
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
elementClass() 0 1 ?
A elementClassInstance() 0 4 1
A create() 0 12 1
A find() 0 17 4
A findById() 0 17 3
A get() 0 10 2
A getById() 0 10 2
A freshFindById() 0 4 1
A freshGetById() 0 9 2
A getQuery() 0 17 1
A findCache() 0 9 2
A addToCache() 0 7 1
A findCacheById() 0 13 2
A isCachedById() 0 11 2
A cacheById() 0 17 2
A notFoundException() 0 9 1
A notFoundByIdException() 0 10 1
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipbox/spark/blob/master/LICENSE
6
 * @link       https://github.com/flipbox/spark
7
 */
8
9
namespace flipbox\spark\services;
10
11
use Craft;
12
use craft\base\Element as BaseElement;
13
use craft\base\ElementInterface;
14
use craft\elements\db\ElementQueryInterface;
15
use flipbox\spark\exceptions\ElementNotFoundException;
16
use flipbox\spark\helpers\ElementHelper;
17
use flipbox\spark\helpers\QueryHelper;
18
use flipbox\spark\helpers\SiteHelper;
19
use yii\base\Component as BaseComponent;
20
21
/**
22
 * @author Flipbox Factory <[email protected]>
23
 * @since 1.0.0
24
 */
25
abstract class Element extends BaseComponent
26
{
27
28
    /**
29
     * @var [ElementInterface[]]
30
     */
31
    protected $cacheById = [];
32
33
    /*******************************************
34
     * ELEMENT CLASSES
35
     *******************************************/
36
37
    /**
38
     * @return string
39
     */
40
    abstract public static function elementClass(): string;
41
42
    /**
43
     * The element instance that this class interacts with
44
     *
45
     * @return string
46
     */
47
    public static function elementClassInstance(): string
48
    {
49
        return ElementInterface::class;
50
    }
51
52
    /*******************************************
53
     * CREATE
54
     *******************************************/
55
56
    /**
57
     * @param array $config
58
     * @return BaseElement|ElementInterface
59
     */
60
    public function create(array $config = [])
61
    {
62
63
        // Set the class the element should be
64
        $config['class'] = static::elementClass();
65
66
        // Create new model
67
        return ElementHelper::create(
68
            $config,
69
            static::elementClassInstance()
70
        );
71
    }
72
73
74
    /**
75
     * @param $identifier
76
     * @param int|null $siteId
77
     * @return BaseElement|ElementInterface|null
78
     */
79
    public function find($identifier, int $siteId = null)
80
    {
81
82
        if ($identifier instanceof ElementInterface) {
83
            $this->addToCache($identifier);
84
85
            return $identifier;
86
        } elseif (is_numeric($identifier)) {
87
            return $this->findById($identifier, $siteId);
88
        } elseif (is_array($identifier)) {
89
            return $this->getQuery($identifier)
90
                ->siteId($siteId)
91
                ->one();
92
        }
93
94
        return null;
95
    }
96
97
    /**
98
     * @param int $id
99
     * @param int|null $siteId
100
     * @return BaseElement|ElementInterface|null
101
     */
102
    public function findById(int $id, int $siteId = null)
103
    {
104
105
        // Check cache
106
        if (!$element = $this->findCacheById($id, $siteId)) {
107
            // Find new element
108
            if ($element = $this->freshFindById($id, $siteId)) {
109
                // Cache it
110
                $this->addToCache($element);
111
            } else {
112
                // Cache nothing
113
                $this->cacheById[$id] = $element;
114
            }
115
        }
116
117
        return $element;
118
    }
119
120
    /*******************************************
121
     * GET
122
     *******************************************/
123
124
    /**
125
     * @param $identifier
126
     * @param int|null $siteId
127
     * @return BaseElement|ElementInterface
128
     * @throws ElementNotFoundException
129
     */
130
    public function get($identifier, int $siteId = null)
131
    {
132
133
        // Find
134
        if (!$element = $this->find($identifier, $siteId)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression $this->find($identifier, $siteId); of type craft\base\ElementInterface|null|false adds false to the return on line 138 which is incompatible with the return type documented by flipbox\spark\services\Element::get of type craft\base\ElementInterface|null. It seems like you forgot to handle an error condition.
Loading history...
135
            $this->notFoundException();
136
        }
137
138
        return $element;
139
    }
140
141
    /**
142
     * @param int $id
143
     * @param int|null $siteId
144
     * @return BaseElement|ElementInterface
145
     * @throws ElementNotFoundException
146
     */
147
    public function getById(int $id, int $siteId = null)
148
    {
149
150
        // Find by ID
151
        if (!$element = $this->findById($id, $siteId)) {
152
            $this->notFoundByIdException($id);
153
        }
154
155
        return $element;
156
    }
157
158
    /*******************************************
159
     * FRESH FIND
160
     *******************************************/
161
162
    /**
163
     * @param int $id
164
     * @param int|null $siteId
165
     * @return BaseElement|ElementInterface|null
166
     */
167
    public function freshFindById(int $id, int $siteId = null)
168
    {
169
        return Craft::$app->getElements()->getElementById($id, static::elementClass(), $siteId);
170
    }
171
172
    /**
173
     * @param $id
174
     * @param int|null $siteId
175
     * @return BaseElement|ElementInterface
176
     * @throws ElementNotFoundException
177
     */
178
    public function freshGetById($id, int $siteId = null)
179
    {
180
181
        if (!$element = $this->freshFindById($id, $siteId)) {
182
            $this->notFoundByIdException($id);
183
        }
184
185
        return $element;
186
    }
187
188
189
    /*******************************************
190
     * QUERY
191
     *******************************************/
192
193
    /**
194
     * Get query
195
     *
196
     * @param $criteria
197
     * @return ElementQueryInterface
198
     */
199
    public function getQuery($criteria = [])
200
    {
201
202
        /** @var ElementInterface $elementClass */
203
        $elementClass = static::elementClass();
204
205
        /** @var ElementQueryInterface $query */
206
        $query = $elementClass::find();
207
208
        // Configure it
209
        QueryHelper::configure(
210
            $query,
211
            $criteria
212
        );
213
214
        return $query;
215
    }
216
217
    /*******************************************
218
     * CACHE
219
     *******************************************/
220
221
    /**
222
     * @param $identifier
223
     * @param int|null $siteId
224
     * @return BaseElement|ElementInterface|null
225
     */
226
    public function findCache($identifier, int $siteId = null)
227
    {
228
229
        if (is_numeric($identifier)) {
230
            return $this->findCacheById($identifier, $siteId);
231
        }
232
233
        return null;
234
    }
235
236
    /**
237
     * @param ElementInterface $element
238
     * @return $this
239
     */
240
    public function addToCache(ElementInterface $element)
241
    {
242
243
        $this->cacheById($element);
244
245
        return $this;
246
    }
247
248
    /**
249
     * Find an existing cache by ID
250
     *
251
     * @param int $id
252
     * @param int|null $siteId
253
     * @return BaseElement|ElementInterface|null
254
     */
255
    public function findCacheById(int $id, int $siteId = null)
256
    {
257
258
        // Resolve siteId
259
        $siteId = SiteHelper::resolveSiteId($siteId);
260
261
        // Check if already in addToCache
262
        if ($this->isCachedById($id, $siteId)) {
263
            return $this->cacheById[$siteId][$id];
264
        }
265
266
        return null;
267
    }
268
269
    /**
270
     * Identify whether in cached by ID
271
     *
272
     * @param int $id
273
     * @param int|null $siteId
274
     * @return bool
275
     */
276
    protected function isCachedById(int $id, int $siteId = null)
277
    {
278
        // Resolve siteId
279
        $siteId = SiteHelper::resolveSiteId($siteId);
280
281
        if (!isset($this->cacheById[$siteId])) {
282
            $this->cacheById[$siteId] = [];
283
        }
284
285
        return array_key_exists($id, $this->cacheById[$siteId]);
286
    }
287
288
    /**
289
     * @param ElementInterface $element
290
     * @return $this
291
     */
292
    protected function cacheById(ElementInterface $element)
293
    {
294
295
        /** @var BaseElement $element */
296
297
        $id = $element->id;
298
299
        $siteId = $element->siteId;
300
301
        // Check if already in cache
302
        if (!$this->isCachedById($id, $siteId)) {
303
            // Cache it
304
            $this->cacheById[$siteId][$id] = $element;
305
        }
306
307
        return $this;
308
    }
309
310
    /*******************************************
311
     * EXCEPTIONS
312
     *******************************************/
313
314
    /**
315
     * @throws ElementNotFoundException
316
     */
317
    protected function notFoundException()
318
    {
319
320
        throw new ElementNotFoundException(
321
            sprintf(
322
                "Element does not exist."
323
            )
324
        );
325
    }
326
327
    /**
328
     * @param int|null $id
329
     * @throws ElementNotFoundException
330
     */
331
    protected function notFoundByIdException(int $id = null)
332
    {
333
334
        throw new ElementNotFoundException(
335
            sprintf(
336
                'Element does not exist with the id "%s".',
337
                (string)$id
338
            )
339
        );
340
    }
341
}
342