BaseModel::getDataService()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * BaseModel.php
4
 *
5
 * PHP version 5.6+
6
 *
7
 * @author Philippe Gaultier <[email protected]>
8
 * @copyright 2010-2017 Philippe Gaultier
9
 * @license http://www.sweelix.net/license license
10
 * @version 1.2.0
11
 * @link http://www.sweelix.net
12
 * @package sweelix\oauth2\server\models
13
 */
14
15
namespace sweelix\oauth2\server\models;
16
17
use sweelix\oauth2\server\interfaces\BaseModelInterface;
18
use yii\base\InvalidArgumentException;
19
use yii\base\Model;
20
use yii\base\ModelEvent;
21
use Yii;
22
use Exception;
23
use yii\base\NotSupportedException;
24
use yii\helpers\Inflector;
25
26
/**
27
 * This is the base model
28
 *
29
 * @author Philippe Gaultier <[email protected]>
30
 * @copyright 2010-2017 Philippe Gaultier
31
 * @license http://www.sweelix.net/license license
32
 * @version 1.2.0
33
 * @link http://www.sweelix.net
34
 * @package sweelix\oauth2\server\models
35
 * @since 1.0.0
36
 */
37
abstract class BaseModel extends Model implements BaseModelInterface
38
{
39
    /**
40
     * @var array|null old attribute values indexed by attribute names.
41
     * This is `null` if the record [[isNewRecord|is new]].
42
     */
43
    private $_oldAttributes;
44
45
    /**
46
     * @var array attribute values indexed by attribute names
47
     */
48
    private $_attributes = [];
49
50
    /**
51
     * @codeCoverageIgnore
52
     */
53
    protected static function getDataService()
54
    {
55
        throw new NotSupportedException('You must implement BaseModel::getDataService()');
56
    }
57
58
    /**
59
     * @return string attribute key of the object
60
     * @since 1.0.0
61
     */
62
    abstract public function key();
63
64
    /**
65
     * Definition of model attributes ['attributeName' => 'type', ...] where type can be :
66
     *   * bool
67
     *   * string
68
     *   * float
69
     *   * int
70
     * As database are not always able to retain datatype, this will be used by the service layer to
71
     * cast data
72
     * @return array definition of model attributes
73
     * @since 1.0.0
74
     */
75
    abstract public function attributesDefinition();
76
77
    /**
78
     * Returns the list of all attribute names of the model.
79
     * The default implementation will return all column names defined in scenario.
80
     * @return array list of attribute names.
81
     * @codeCoverageIgnore
82
     */
83
    public function attributes()
84
    {
85
        return array_keys($this->attributesDefinition());
86
    }
87
88
    /**
89
     * Initializes the object.
90
     * This method is called at the end of the constructor.
91
     * The default implementation will trigger an [[EVENT_INIT]] event.
92
     * If you override this method, make sure you call the parent implementation at the end
93
     * to ensure triggering of the event.
94
     */
95 53
    public function init()
96
    {
97 53
        parent::init();
98 53
        $this->trigger(self::EVENT_INIT);
99 53
    }
100
101
    /**
102
     * Repopulates this record with the latest data.
103
     * @return boolean whether the row still exists in the database. If true, the latest data
104
     * will be populated to this active record. Otherwise, this record will remain unchanged.
105
     */
106
    public function refresh()
107
    {
108
        $record = static::findOne($this->getKey());
109
        if ($record === null) {
110
            return false;
111
        }
112
        foreach ($this->attributes() as $name) {
113
            $this->_attributes[$name] = isset($record->_attributes[$name]) ? $record->_attributes[$name] : null;
114
        }
115
        $this->_oldAttributes = $this->_attributes;
116
        return true;
117
    }
118
119
    /**
120
     * Returns the key value of the object
121
     * @return mixed|null
122
     * @since 1.0.0
123
     */
124 49
    public function getKey()
125
    {
126 49
        $key = $this->key();
127 49
        return isset($this->_attributes[$key]) ? $this->_attributes[$key] : null;
128
    }
129
130
    /**
131
     * Returns the old key value of the object
132
     * @return mixed|null
133
     * @since 1.0.0
134
     */
135 20
    public function getOldKey()
136
    {
137 20
        $key = $this->key();
138 20
        return isset($this->_oldAttributes[$key]) ? $this->_oldAttributes[$key] : null;
139
    }
140
141
    /**
142
     * Returns a value indicating whether the model has an attribute with the specified name.
143
     * @param string $name the name of the attribute
144
     * @return boolean whether the model has an attribute with the specified name.
145
     */
146 49
    public function hasAttribute($name)
147
    {
148 49
        return isset($this->_attributes[$name]) || in_array($name, $this->attributes());
149
    }
150
    /**
151
     * Returns the named attribute value.
152
     * If this record is the result of a query and the attribute is not loaded,
153
     * null will be returned.
154
     * @param string $name the attribute name
155
     * @return mixed the attribute value. Null if the attribute is not set or does not exist.
156
     * @see hasAttribute()
157
     */
158
    public function getAttribute($name)
159
    {
160
        return isset($this->_attributes[$name]) ? $this->_attributes[$name] : null;
161
    }
162
    /**
163
     * Sets the named attribute value.
164
     * @param string $name the attribute name
165
     * @param mixed $value the attribute value.
166
     * @throws InvalidArgumentException if the named attribute does not exist.
167
     * @see hasAttribute()
168
     */
169 42
    public function setAttribute($name, $value)
170
    {
171 42
        if ($this->hasAttribute($name)) {
172 42
            $this->_attributes[$name] = $value;
173 42
        } else {
174
            throw new InvalidArgumentException(get_class($this) . ' has no attribute named "' . $name . '".');
175
        }
176 42
    }
177
178
    /**
179
     * Sets the old attribute values.
180
     * All existing old attribute values will be discarded.
181
     * @param array|null $values old attribute values to be set.
182
     * If set to `null` this record is considered to be [[isNewRecord|new]].
183
     */
184 49
    public function setOldAttributes($values)
185
    {
186 49
        $this->_oldAttributes = $values;
187 49
    }
188
189
    /**
190
     * Returns the old attribute values.
191
     * @return array the old attribute values (name-value pairs)
192
     */
193 9
    public function getOldAttributes()
194
    {
195 9
        return $this->_oldAttributes === null ? [] : $this->_oldAttributes;
196
    }
197
198
199
    /**
200
     * Sets the old value of the named attribute.
201
     * @param string $name the attribute name
202
     * @param mixed $value the old attribute value.
203
     * @throws InvalidArgumentException if the named attribute does not exist.
204
     * @see hasAttribute()
205
     */
206 9
    public function setOldAttribute($name, $value)
207
    {
208 9
        if (isset($this->_oldAttributes[$name]) || $this->hasAttribute($name)) {
209 9
            $this->_oldAttributes[$name] = $value;
210 9
        } else {
211
            throw new InvalidArgumentException(get_class($this) . ' has no attribute named "' . $name . '".');
212
        }
213 9
    }
214
215
    /**
216
     * Returns the old value of the named attribute.
217
     * If this record is the result of a query and the attribute is not loaded,
218
     * null will be returned.
219
     * @param string $name the attribute name
220
     * @return mixed the old attribute value. Null if the attribute is not loaded before
221
     * or does not exist.
222
     * @see hasAttribute()
223
     */
224
    public function getOldAttribute($name)
225
    {
226
        return isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
227
    }
228
229
    /**
230
     * Returns a value indicating whether the current record is new.
231
     * @return boolean whether the record is new and should be inserted when calling [[save()]].
232
     */
233 49
    public function getIsNewRecord()
234
    {
235 49
        return $this->_oldAttributes === null;
236
    }
237
    /**
238
     * Sets the value indicating whether the record is new.
239
     * @param boolean $value whether the record is new and should be inserted when calling [[save()]].
240
     * @see getIsNewRecord()
241
     */
242 12
    public function setIsNewRecord($value)
243
    {
244 12
        $this->_oldAttributes = $value ? null : $this->_attributes;
245 12
    }
246
247
    /**
248
     * Marks an attribute dirty.
249
     * This method may be called to force updating a record when calling [[update()]],
250
     * even if there is no change being made to the record.
251
     * @param string $name the attribute name
252
     */
253
    public function markAttributeDirty($name)
254
    {
255
        unset($this->_oldAttributes[$name]);
256
    }
257
258
    /**
259
     * Returns a value indicating whether the named attribute has been changed.
260
     * @param string $name the name of the attribute.
261
     * @param boolean $identical whether the comparison of new and old value is made for
262
     * identical values using `===`, defaults to `true`. Otherwise `==` is used for comparison.
263
     * This parameter is available since version 2.0.4.
264
     * @return boolean whether the attribute has been changed
265
     */
266
    public function isAttributeChanged($name, $identical = true)
267
    {
268
        if (isset($this->_attributes[$name], $this->_oldAttributes[$name])) {
269
            if ($identical) {
270
                return $this->_attributes[$name] !== $this->_oldAttributes[$name];
271
            } else {
272
                return $this->_attributes[$name] != $this->_oldAttributes[$name];
273
            }
274
        } else {
275
            return isset($this->_attributes[$name]) || isset($this->_oldAttributes[$name]);
276
        }
277
    }
278
279
280
    /**
281
     * Returns the attribute values that have been modified since they are loaded or saved most recently.
282
     *
283
     * The comparison of new and old values is made for identical values using `===`.
284
     *
285
     * @param string[]|null $names the names of the attributes whose values may be returned if they are
286
     * changed recently. If null, [[attributes()]] will be used.
287
     * @return array the changed attribute values (name-value pairs)
288
     */
289 49
    public function getDirtyAttributes($names = null)
290
    {
291 49
        if ($names === null) {
292 49
            $names = $this->attributes();
293 49
        }
294 49
        $names = array_flip($names);
295 49
        $attributes = [];
296 49
        if ($this->_oldAttributes === null) {
297 49
            foreach ($this->_attributes as $name => $value) {
298 49
                if (isset($names[$name])) {
299 49
                    $attributes[$name] = $value;
300 49
                }
301 49
            }
302 49
        } else {
303 9
            foreach ($this->_attributes as $name => $value) {
304 9
                if (isset($names[$name]) && (!array_key_exists($name, $this->_oldAttributes) || $value !== $this->_oldAttributes[$name])) {
305 9
                    $attributes[$name] = $value;
306 9
                }
307 9
            }
308
        }
309 49
        return $attributes;
310
    }
311
312
    /**
313
     * PHP getter magic method.
314
     * This method is overridden so that attributes and related objects can be accessed like properties.
315
     *
316
     * @param string $name property name
317
     * @throws \yii\base\InvalidArgumentException if relation name is wrong
318
     * @return mixed property value
319
     * @see getAttribute()
320
     */
321 49
    public function __get($name)
322
    {
323 49
        if (isset($this->_attributes[$name]) || array_key_exists($name, $this->_attributes)) {
324 49
            return $this->_attributes[$name];
325 38
        } elseif ($this->hasAttribute($name)) {
326 38
            return null;
327
        } else {
328
            return parent::__get($name);
329
        }
330
    }
331
    /**
332
     * PHP setter magic method.
333
     * This method is overridden so that AR attributes can be accessed like properties.
334
     * @param string $name property name
335
     * @param mixed $value property value
336
     */
337 49
    public function __set($name, $value)
338
    {
339 49
        if ($this->hasAttribute($name)) {
340 49
            $this->_attributes[$name] = $value;
341 49
        } else {
342
            parent::__set($name, $value);
343
        }
344 49
    }
345
    /**
346
     * Checks if a property value is null.
347
     * This method overrides the parent implementation by checking if the named attribute is null or not.
348
     * @param string $name the property name or the event name
349
     * @return boolean whether the property value is null
350
     */
351 30
    public function __isset($name)
352
    {
353
        try {
354 30
            return $this->__get($name) !== null;
355
        } catch (Exception $e) {
356
            return false;
357
        }
358
    }
359
    /**
360
     * Sets a component property to be null.
361
     * This method overrides the parent implementation by clearing
362
     * the specified attribute value.
363
     * @param string $name the property name or the event name
364
     */
365
    public function __unset($name)
366
    {
367
        if ($this->hasAttribute($name)) {
368
            unset($this->_attributes[$name]);
369
        } else {
370
            parent::__unset($name);
371
        }
372
    }
373
374
    /**
375
     * Populates the model with the data from end user.
376
     * The data to be loaded is `$data[formName]`, where `formName` refers to the value of [[formName()]].
377
     * If [[formName()]] is empty, the whole `$data` array will be used to populate the model.
378
     * The data being populated is subject to the safety check by [[setAttributes()]].
379
     * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array
380
     * supplied by end user.
381
     * @param string $formName the form name to be used for loading the data into the model.
382
     * If not set, [[formName()]] will be used.
383
     * @return boolean whether the model is successfully populated with some data.
384
     */
385
    public function loadIds($data, $formName=null)
386
    {
387
        $camelData = [];
388
        foreach($data as $key => $value) {
389
            $key = lcfirst(Inflector::id2camel($key));
390
            $camelData[$key] = $value;
391
        }
392
        return parent::load($camelData, $formName);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (load() instead of loadIds()). Are you sure this is correct? If so, you might want to change this to $this->load().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
393
    }
394
395
    /**
396
     * This method is called when the AR object is created and populated with the query result.
397
     * The default implementation will trigger an [[EVENT_AFTER_FIND]] event.
398
     * When overriding this method, make sure you call the parent implementation to ensure the
399
     * event is triggered.
400
     */
401 42
    public function afterFind()
402
    {
403 42
        $this->trigger(self::EVENT_AFTER_FIND);
404 42
    }
405
406
    /**
407
     * This method is called at the beginning of inserting or updating a record.
408
     * The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is true,
409
     * or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is false.
410
     * When overriding this method, make sure you call the parent implementation like the following:
411
     *
412
     * ```php
413
     * public function beforeSave($insert)
414
     * {
415
     *     if (parent::beforeSave($insert)) {
416
     *         // ...custom code here...
417
     *         return true;
418
     *     } else {
419
     *         return false;
420
     *     }
421
     * }
422
     * ```
423
     *
424
     * @param boolean $insert whether this method called while inserting a record.
425
     * If false, it means the method is called while updating a record.
426
     * @return boolean whether the insertion or updating should continue.
427
     * If false, the insertion or updating will be cancelled.
428
     */
429 49
    public function beforeSave($insert)
430
    {
431 49
        $event = new ModelEvent;
432 49
        $this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event);
433 49
        return $event->isValid;
434
    }
435
436
    /**
437
     * This method is called at the end of inserting or updating a record.
438
     * The default implementation will trigger an [[EVENT_AFTER_INSERT]] event when `$insert` is true,
439
     * or an [[EVENT_AFTER_UPDATE]] event if `$insert` is false. The event class used is [[AfterSaveEvent]].
440
     * When overriding this method, make sure you call the parent implementation so that
441
     * the event is triggered.
442
     * @param boolean $insert whether this method called while inserting a record.
443
     * If false, it means the method is called while updating a record.
444
     * @param array $changedAttributes The old values of attributes that had changed and were saved.
445
     * You can use this parameter to take action based on the changes made for example send an email
446
     * when the password had changed or implement audit trail that tracks all the changes.
447
     * `$changedAttributes` gives you the old attribute values while the active record (`$this`) has
448
     * already the new, updated values.
449
     */
450 49
    public function afterSave($insert, $changedAttributes)
451
    {
452 49
        $this->trigger($insert ? self::EVENT_AFTER_INSERT : self::EVENT_AFTER_UPDATE, new AfterSaveEvent([
453
            'changedAttributes' => $changedAttributes
454 49
        ]));
455 49
    }
456
457
    /**
458
     * This method is invoked before deleting a record.
459
     * The default implementation raises the [[EVENT_BEFORE_DELETE]] event.
460
     * When overriding this method, make sure you call the parent implementation like the following:
461
     *
462
     * ```php
463
     * public function beforeDelete()
464
     * {
465
     *     if (parent::beforeDelete()) {
466
     *         // ...custom code here...
467
     *         return true;
468
     *     } else {
469
     *         return false;
470
     *     }
471
     * }
472
     * ```
473
     *
474
     * @return boolean whether the record should be deleted. Defaults to true.
475
     */
476 12
    public function beforeDelete()
477
    {
478 12
        $event = new ModelEvent;
479 12
        $this->trigger(self::EVENT_BEFORE_DELETE, $event);
480 12
        return $event->isValid;
481
    }
482
    /**
483
     * This method is invoked after deleting a record.
484
     * The default implementation raises the [[EVENT_AFTER_DELETE]] event.
485
     * You may override this method to do postprocessing after the record is deleted.
486
     * Make sure you call the parent implementation so that the event is raised properly.
487
     */
488 12
    public function afterDelete()
489
    {
490 12
        $this->trigger(self::EVENT_AFTER_DELETE);
491 12
    }
492
}
493