Completed
Branch develop (9e5d0f)
by Nate
01:59
created

ActiveRecord   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 361
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 6
dl 0
loc 361
ccs 0
cts 169
cp 0
rs 8.2857
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
recordClass() 0 1 ?
A recordClassInstance() 0 4 1
A cacheDuration() 0 4 1
A cacheDependency() 0 4 1
A getQuery() 0 16 2
A getDb() 0 7 1
A getTableSchema() 0 7 1
A create() 0 20 3
A findAll() 0 4 1
A find() 0 11 3
A get() 0 8 2
A findByCondition() 0 7 1
A getByCondition() 0 8 2
A findByCriteria() 0 12 3
A getByCriteria() 0 8 2
A findAllByCondition() 0 7 1
A getAllByCondition() 0 8 2
A findAllByCriteria() 0 14 3
A getAllByCriteria() 0 8 2
A queryOne() 0 18 3
A queryAll() 0 18 3
A notFoundException() 0 8 1
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipboxfactory/craft-ember/blob/master/LICENSE
6
 * @link       https://github.com/flipboxfactory/craft-ember
7
 */
8
9
namespace flipbox\ember\services\traits;
10
11
use flipbox\ember\exceptions\RecordNotFoundException;
12
use flipbox\ember\helpers\QueryHelper;
13
use flipbox\ember\helpers\RecordHelper;
14
use yii\caching\Dependency;
15
use yii\db\ActiveQuery;
16
use yii\db\ActiveRecord as Record;
17
use yii\db\Connection;
18
use yii\db\TableSchema;
19
20
/**
21
 * @author Flipbox Factory <[email protected]>
22
 * @since 1.0.0
23
 */
24
trait ActiveRecord
25
{
26
    /**
27
     * @return string
28
     */
29
    public abstract static function recordClass(): string;
30
31
    /**
32
     * @return string
33
     */
34
    public static function recordClassInstance(): string
35
    {
36
        return Record::class;
37
    }
38
39
    /**
40
     * @return int|null
41
     */
42
    protected static function cacheDuration()
43
    {
44
        return false;
45
    }
46
47
    /**
48
     * @return null|Dependency
49
     */
50
    protected static function cacheDependency()
51
    {
52
        return null;
53
    }
54
55
    /**
56
     * @param array $config
57
     * @return \yii\db\ActiveQuery
58
     */
59
    public static function getQuery($config = []): ActiveQuery
60
    {
61
        /** @var Record $recordClass */
62
        $recordClass = static::recordClass();
63
64
        $query = $recordClass::find();
65
66
        if ($config) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $config of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
67
            QueryHelper::configure(
68
                $query,
69
                $config
70
            );
71
        }
72
73
        return $query;
74
    }
75
76
    /**
77
     * @return Connection
78
     */
79
    public static function getDb(): Connection
80
    {
81
        /** @var Record $recordClass */
82
        $recordClass = static::recordClass();
83
84
        return $recordClass::getDb();
85
    }
86
87
    /**
88
     * @return TableSchema
89
     * @throws \yii\base\InvalidConfigException
90
     */
91
    public static function getTableSchema(): TableSchema
92
    {
93
        /** @var Record $recordClass */
94
        $recordClass = static::recordClass();
95
96
        return $recordClass::getTableSchema();
97
    }
98
99
    /*******************************************
100
     * CREATE
101
     *******************************************/
102
103
    /**
104
     * @param array $attributes
105
     * @param string $toScenario
106
     * @return Record
107
     */
108
    public function create(array $attributes = [], string $toScenario = null): Record
109
    {
110
        /** @var string $recordClass */
111
        $recordClass = static::recordClass();
112
113
        /** @var Record $record */
114
        $record = new $recordClass();
115
116
        // Set scenario
117
        if ($toScenario) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $toScenario of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
118
            $record->setScenario($toScenario);
119
        }
120
121
        // Do we need to set properties too
122
        if (!empty($attributes)) {
123
            $record->setAttributes($attributes);
124
        }
125
126
        return $record;
127
    }
128
129
130
    /*******************************************
131
     * FIND / GET
132
     *******************************************/
133
134
    /**
135
     * @param string $toScenario
136
     * @return Record[]
137
     */
138
    public function findAll(string $toScenario = null)
139
    {
140
        return $this->findAllByCondition(null, $toScenario);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
141
    }
142
143
    /**
144
     * @param $identifier
145
     * @param string|null $toScenario
146
     * @return Record|null
147
     */
148
    public function find($identifier, string $toScenario = null)
149
    {
150
        if ($identifier instanceof Record) {
151
            if (null !== $toScenario) {
152
                $identifier->setScenario($toScenario);
153
            }
154
            return $identifier;
155
        }
156
157
        return $this->findByCondition($identifier, $toScenario);
158
    }
159
160
    /**
161
     * @param $identifier
162
     * @param string $toScenario
163
     * @return Record
164
     * @throws RecordNotFoundException
165
     */
166
    public function get($identifier, string $toScenario = null): Record
167
    {
168
        if (!$object = $this->find($identifier, $toScenario)) {
169
            $this->notFoundException();
170
        }
171
172
        return $object;
173
    }
174
175
176
    /*******************************************
177
     * ONE CONDITION
178
     *******************************************/
179
180
    /**
181
     * @param $condition
182
     * @param string $toScenario
183
     * @return Record|null
184
     */
185
    public function findByCondition($condition, string $toScenario = null)
186
    {
187
        return $this->findByCriteria(
188
            RecordHelper::conditionToCriteria($condition),
189
            $toScenario
190
        );
191
    }
192
193
    /**
194
     * @param $condition
195
     * @param string $toScenario
196
     * @return Record
197
     * @throws RecordNotFoundException
198
     */
199
    public function getByCondition($condition, string $toScenario = null)
200
    {
201
        if (!$record = $this->findByCondition($condition, $toScenario)) {
202
            $this->notFoundException();
203
        }
204
205
        return $record;
206
    }
207
208
209
    /*******************************************
210
     * ONE CRITERIA
211
     *******************************************/
212
213
    /**
214
     * @param $criteria
215
     * @param string|null $toScenario
216
     * @return mixed
217
     */
218
    public function findByCriteria($criteria, string $toScenario = null)
219
    {
220
        $record = $this->queryOne(
221
            $this->getQuery($criteria)
222
        );
223
224
        if ($record && $toScenario) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $toScenario of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
225
            $record->setScenario($toScenario);
226
        }
227
228
        return $record;
229
    }
230
231
    /**
232
     * @param $criteria
233
     * @param string $toScenario
234
     * @return Record
235
     * @throws RecordNotFoundException
236
     */
237
    public function getByCriteria($criteria, string $toScenario = null)
238
    {
239
        if (!$record = $this->findByCriteria($criteria, $toScenario)) {
240
            $this->notFoundException();
241
        }
242
243
        return $record;
244
    }
245
246
247
    /*******************************************
248
     * ALL CONDITION
249
     *******************************************/
250
251
    /**
252
     * @param array $condition
253
     * @param string $toScenario
254
     * @return Record[]
255
     */
256
    public function findAllByCondition($condition = [], string $toScenario = null)
257
    {
258
        return $this->findAllByCriteria(
259
            RecordHelper::conditionToCriteria($condition),
260
            $toScenario
261
        );
262
    }
263
264
    /**
265
     * @param array $condition
266
     * @param string $toScenario
267
     * @return Record[]
268
     * @throws RecordNotFoundException
269
     */
270
    public function getAllByCondition($condition = [], string $toScenario = null)
271
    {
272
        if (!$records = $this->findAllByCondition($condition, $toScenario)) {
273
            $this->notFoundException();
274
        }
275
276
        return $records;
277
    }
278
279
    /*******************************************
280
     * ALL CRITERIA
281
     *******************************************/
282
283
    /**
284
     * @param array $criteria
285
     * @param string $toScenario
286
     * @return Record[]
287
     */
288
    public function findAllByCriteria($criteria = [], string $toScenario = null)
289
    {
290
        $records = $this->queryAll(
291
            $this->getQuery($criteria)
292
        );
293
294
        if ($toScenario) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $toScenario of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
295
            foreach ($records as $record) {
296
                $record->setScenario($toScenario);
297
            }
298
        }
299
300
        return $records;
301
    }
302
303
    /**
304
     * @param array $criteria
305
     * @param string $toScenario
306
     * @return Record[]
307
     * @throws RecordNotFoundException
308
     */
309
    public function getAllByCriteria($criteria = [], string $toScenario = null)
310
    {
311
        if (!$records = $this->findAllByCriteria($criteria, $toScenario)) {
312
            $this->notFoundException();
313
        }
314
315
        return $records;
316
    }
317
318
319
    /*******************************************
320
     * CACHE
321
     *******************************************/
322
323
    /**
324
     * @param ActiveQuery $query
325
     * @return Record|null
326
     */
327
    protected function queryOne(ActiveQuery $query)
328
    {
329
        $db = static::getDb();
330
331
        try {
332
            if (false === ($cacheDuration = static::cacheDuration())) {
333
                return $query->one($db);
334
            }
335
336
            $record = $db->cache(function ($db) use ($query) {
337
                return $query->one($db);
338
            }, $cacheDuration, static::cacheDependency());
0 ignored issues
show
Documentation introduced by
$cacheDuration is of type boolean, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
339
        } catch (\Exception $e) {
340
            return null;
341
        }
342
343
        return $record;
344
    }
345
346
    /**
347
     * @param ActiveQuery $query
348
     * @return Record[]
349
     */
350
    protected function queryAll(ActiveQuery $query)
351
    {
352
        $db = static::getDb();
353
354
        try {
355
            if (false === ($cacheDuration = static::cacheDuration())) {
356
                return $query->all($db);
357
            }
358
359
            $record = $db->cache(function ($db) use ($query) {
360
                return $query->all($db);
361
            }, $cacheDuration, static::cacheDependency());
0 ignored issues
show
Documentation introduced by
$cacheDuration is of type boolean, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
362
        } catch (\Exception $e) {
363
            return [];
364
        }
365
366
        return $record;
367
    }
368
369
    /*******************************************
370
     * EXCEPTIONS
371
     *******************************************/
372
373
    /**
374
     * @throws RecordNotFoundException
375
     */
376
    protected function notFoundException()
377
    {
378
        throw new RecordNotFoundException(
379
            sprintf(
380
                "Record does not exist."
381
            )
382
        );
383
    }
384
}
385