Completed
Push — master ( 11971b...eeafb3 )
by Nate
01:16
created

ActiveRecord::findByCondition()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 0
cts 25
cp 0
rs 8.0555
c 0
b 0
f 0
cc 9
nc 7
nop 1
crap 90
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\craft\ember\records;
10
11
use craft\helpers\Json;
12
use flipbox\craft\ember\exceptions\RecordNotFoundException;
13
use flipbox\craft\ember\models\DateCreatedRulesTrait;
14
use flipbox\craft\ember\models\DateUpdatedRulesTrait;
15
use flipbox\craft\ember\models\UidRulesTrait;
16
use yii\base\InvalidConfigException;
17
use yii\db\ActiveQueryInterface;
18
use yii\helpers\ArrayHelper;
19
20
/**
21
 * This class provides additional functionality to Craft's ActiveRecord:
22
 *
23
 * Table Alias - By default the table alias is the name of the table, without the opening '{{%' and closing '}}'
24
 * syntax.  Additionally, the table alias (and therefore table name) is set via a constant.
25
 *
26
 * Audit Attributes - Craft defines 'dateCreated', 'dateUpdated' and 'UID' as audit attributes which are automatically
27
 * accounted for.  It is important to note that these attributes are also set as 'safe' for the 'default' scenario;
28
 * therefore making them easily set-able and accessible.
29
 *
30
 * Getter Priority Attributes - When set, the attribute will call the 'getter' method instead of the traditional
31
 * 'getAttribute' method.  Examine the case when using relational Id attributes; we'll use 'userId' as an example.
32
 * Calling the attribute directly `$this->userId` would call `$this->getUserId()` which should look at the relation
33
 * `$this->user->getId()` to ensure the related object and Id are the same.  Commonly, this is useful when continuity
34
 * between the Id an object need to be upheld.
35
 *
36
 * @author Flipbox Factory <[email protected]>
37
 * @since 2.0.0
38
 */
39
abstract class ActiveRecord extends \craft\db\ActiveRecord
40
{
41
    use DateCreatedRulesTrait,
42
        DateUpdatedRulesTrait,
43
        UidRulesTrait;
44
45
    /**
46
     * These attributes will have their 'getter' methods take priority over the normal attribute lookup.  It's
47
     * VERY important to note, that the value returned from the getter should NEVER be different than the raw
48
     * attribute value set.  If, for whatever reason, the getter determines the attribute value is
49
     * incorrect, it should set the new value prior to returning it.
50
     *
51
     * These getters are commonly used to ensure an associated model and their identifier are in sync.  For example,
52
     * a userId attribute and a user object (with an id attribute).  An operation may have saved and set an Id on the
53
     * model, but the userId attribute remains null.  The getter method may check (and set) the value prior to
54
     * returning it.
55
     *
56
     * @var array
57
     */
58
    protected $getterPriorityAttributes = [];
59
60
    /**
61
     * The table alias
62
     */
63
    const TABLE_ALIAS = '';
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public static function tableAlias()
69
    {
70
        return static::TABLE_ALIAS;
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76
    public static function tableName()
77
    {
78
        return '{{%' . static::tableAlias() . '}}';
79
    }
80
81
82
    /*******************************************
83
     * OVERRIDE CONDITION HANDLING
84
     *******************************************/
85
86
    /**
87
     * Finds ActiveRecord instance(s) by the given condition.
88
     * This method is internally called by [[findOne()]] and [[findAll()]].
89
     * @param mixed $condition please refer to [[findOne()]] for the explanation of this parameter
90
     * @return ActiveQueryInterface the newly created [[ActiveQueryInterface|ActiveQuery]] instance.
91
     * @throws InvalidConfigException if there is no primary key defined.
92
     * @internal
93
     */
94
    protected static function findByCondition($condition)
95
    {
96
        $query = static::find();
97
98
        if (!ArrayHelper::isAssociative($condition)) {
99
            // query by primary key
100
            $primaryKey = static::primaryKey();
101
            if (isset($primaryKey[0])) {
102
                $pk = $primaryKey[0];
103
                if (!empty($query->join) || !empty($query->joinWith)) {
104
                    $pk = static::tableName() . '.' . $pk;
105
                }
106
                // if condition is scalar, search for a single primary key, if it is array, search for
107
                // multiple primary key values
108
                $condition = [$pk => is_array($condition) ? array_values($condition) : $condition];
109
            } else {
110
                throw new InvalidConfigException('"' . get_called_class() . '" must have a primary key.');
111
            }
112
        } elseif (is_array($condition)) {
113
            foreach ($condition as $key => $value) {
114
                if ($query->canSetProperty($key)) {
115
                    $query->{$key} = $value;
116
                    unset($condition[$key]);
117
                }
118
            }
119
120
            /** @noinspection PhpInternalEntityUsedInspection */
121
            $condition = static::filterCondition($condition);
122
        }
123
124
        return $query->andWhere($condition);
125
    }
126
127
    /*******************************************
128
     * GET
129
     *******************************************/
130
131
    /**
132
     * @param $condition
133
     * @return static|null
134
     * @throws RecordNotFoundException
135
     */
136
    public static function getOne($condition)
137
    {
138
        if (null === ($record = static::findOne($condition))) {
139
            throw new RecordNotFoundException(
140
                sprintf(
141
                    "Record not found with the following condition: %s",
142
                    Json::encode($condition)
143
                )
144
            );
145
        }
146
147
        return $record;
148
    }
149
150
    /**
151
     * @param $condition
152
     * @return static[]
153
     * @throws RecordNotFoundException
154
     */
155
    public static function getAll($condition)
156
    {
157
        $records = static::findAll($condition);
158
159
        if (empty($records)) {
160
            throw new RecordNotFoundException(
161
                sprintf(
162
                    "Records not found with the following condition: %s",
163
                    Json::encode($condition)
164
                )
165
            );
166
        }
167
168
        return $records;
169
    }
170
171
172
    /*******************************************
173
     * RULES
174
     *******************************************/
175
176
    /**
177
     * @inheritdoc
178
     */
179
    public function rules()
180
    {
181
        return array_merge(
182
            parent::rules(),
183
            $this->dateCreatedRules(),
184
            $this->dateUpdatedRules(),
185
            $this->uidRules()
186
        );
187
    }
188
189
    /*******************************************
190
     * MAGIC
191
     *******************************************/
192
193
    /**
194
     * @param string $name
195
     * @return mixed
196
     */
197
    public function __get($name)
198
    {
199
        $getter = 'get' . $name;
200
        if (in_array($name, $this->getterPriorityAttributes, true) &&
201
            method_exists($this, $getter)
202
        ) {
203
            return $this->$getter();
204
        }
205
206
        return parent::__get($name);
207
    }
208
}
209