Completed
Push — master ( 76e0e0...e4688d )
by vistart
05:35
created

IDTrait   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 93.94%

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 3
dl 0
loc 187
ccs 62
cts 66
cp 0.9394
rs 8.8
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getID() 0 5 3
A setID() 0 5 3
A attachInitIDEvent() 0 4 1
A checkIdExists() 0 7 2
B onInitIDAttribute() 0 18 7
B generateId() 0 17 5
B compositeIDs() 0 13 5
D getIdRules() 0 35 10
1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link https://vistart.me/
9
 * @copyright Copyright (c) 2016 - 2017 vistart
10
 * @license https://vistart.me/license/
11
 */
12
13
namespace rhosocial\base\models\traits;
14
use rhosocial\base\helpers\Number;
15
use Yii;
16
use yii\base\ModelEvent;
17
18
/**
19
 * Entity features concerning ID.
20
 * @property-read array $idRules
21
 * @property mixed $ID
22
 * @version 1.0
23
 * @author vistart <[email protected]>
24
 */
25
trait IDTrait
26
{
27
    /**
28
     * @var string OPTIONAL. The attribute that will receive the IDentifier No.
29
     * You can set this property to false if you don't use this feature.
30
     */
31
    public $idAttribute = 'id';
32
    public static $idTypeString = 0;
33
    public static $idTypeInteger = 1;
34
    public static $idTypeAutoIncrement = 2;
35
    
36
    /**
37
     * @var integer type of id attribute.
38
     */
39
    public $idAttributeType = 0;
40
    
41
    /**
42
     * @var boolean Determines whether its ID has been pre-assigned. It will not
43
     * generate or assign ID if true.
44
     */
45
    public $idPreassigned = false;
46
    
47
    /**
48
     * @var string The prefix of ID. When ID type is Auto Increment, this feature
49
     * is skipped.
50
     */
51
    public $idAttributePrefix = '';
52
    
53
    /**
54
     * @var integer OPTIONAL. The length of id attribute value, and max length
55
     * of this attribute in rules. If you set $idAttribute to false or ID type
56
     * to Auto Increment, this property will be ignored.
57
     */
58
    public $idAttributeLength = 4;
59
    
60
    /**
61
     * @var boolean Determine whether the ID is safe for validation.
62
     */
63
    protected $idAttributeSafe = false;
64
    
65
    /**
66
     * Get ID.
67
     * @return string|integer
68
     */
69 19
    public function getID()
70
    {
71 19
        $idAttribute = $this->idAttribute;
72 19
        return (is_string($idAttribute) && !empty($idAttribute)) ? $this->$idAttribute : null;
73
    }
74
    
75
    /**
76
     * Set id.
77
     * @param string|integer $identity
78
     * @return string|integer
79
     */
80 249
    public function setID($identity)
81
    {
82 249
        $idAttribute = $this->idAttribute;
83 249
        return (is_string($idAttribute) && !empty($idAttribute)) ? $this->$idAttribute = $identity : null;
84
    }
85
    
86
    /**
87
     * Attach `onInitGuidAttribute` event.
88
     * @param string $eventName
89
     */
90 264
    protected function attachInitIDEvent($eventName)
91
    {
92 264
        $this->on($eventName, [$this, 'onInitIDAttribute']);
0 ignored issues
show
Bug introduced by
It seems like on() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
93 264
    }
94
    
95
    /**
96
     * Initialize the ID attribute with new generated ID.
97
     * If the model's id is pre-assigned, then it will return directly.
98
     * If the model's id is auto-increment, the id attribute will be marked safe.
99
     * This method is ONLY used for being triggered by event. DO NOT call,
100
     * override or modify it directly, unless you know the consequences.
101
     * @param ModelEvent $event
102
     */
103 264
    public function onInitIDAttribute($event)
104
    {
105 264
        $sender = $event->sender;
106
        /* @var $sender static */
107 264
        if ($sender->idPreassigned) {
108 116
            return;
109
        }
110 264
        if ($sender->idAttributeType === static::$idTypeAutoIncrement) {
111 30
            $sender->idAttributeSafe = true;
112 30
            return;
113
        }
114 249
        $idAttribute = $sender->idAttribute;
115 249
        if (is_string($idAttribute) && !empty($idAttribute) &&
116 249
            is_int($sender->idAttributeLength) &&
117 249
            $sender->idAttributeLength > 0) {
118 249
            $sender->setID($sender->generateId());
0 ignored issues
show
Bug introduced by
It seems like $sender->generateId() targeting rhosocial\base\models\traits\IDTrait::generateId() can also be of type false or null; however, rhosocial\base\models\traits\IDTrait::setID() does only seem to accept string|integer, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
119
        }
120 249
    }
121
    
122
    /**
123
     * Generate the ID. You can override this method to implement your own
124
     * generation algorithm.
125
     * @return string the generated ID.
126
     */
127 249
    public function generateId()
128
    {
129 249
        if ($this->idAttributeType == static::$idTypeInteger) {
130
            do {
131 191
                $result = Number::randomNumber($this->idAttributePrefix, $this->idAttributeLength);
132 191
            } while ($this->checkIdExists((int) $result));
133 191
            return $result;
134
        }
135 146
        if ($this->idAttributeType == static::$idTypeString) {
136 146
            return $this->idAttributePrefix .
137 146
                Yii::$app->security->generateRandomString($this->idAttributeLength - strlen($this->idAttributePrefix));
138
        }
139 1
        if ($this->idAttributeType == static::$idTypeAutoIncrement) {
140 1
            return null;
141
        }
142
        return false;
143
    }
144
    
145
    /**
146
     * Check if $identity existed.
147
     * @param mixed $identity
148
     * @return boolean
149
     */
150 192
    public function checkIdExists($identity)
151
    {
152 192
        if ($identity == null) {
153 4
            return false;
154
        }
155 192
        return (static::findOne([$this->idAttribute => $identity]) !== null);
156
    }
157
    
158
    /**
159
     * Get the rules associated with id attribute.
160
     * @return array
161
     */
162 241
    public function getIdRules()
163
    {
164 241
        if ($this->idAttribute == false) {
165 4
            return [];
166
        }
167 241
        if ($this->idAttributeSafe) {
168
            return [
169 29
                [[$this->idAttribute], 'safe'],
170
            ];
171
        }
172 225
        if (is_string($this->idAttribute) && !empty($this->idAttribute) &&
173 225
            is_int($this->idAttributeLength) &&
174 225
            $this->idAttributeLength > 0) {
175
            $rules = [
176 225
                [[$this->idAttribute], 'required'],
177 225
                [[$this->idAttribute], 'unique'],
178
            ];
179 225
            if ($this->idAttributeType === static::$idTypeInteger) {
180 182
                $rules[] = [
181 182
                    [$this->idAttribute], 'number', 'integerOnly' => true
182
                ];
183
            }
184 225
            if ($this->idAttributeType === static::$idTypeString) {
185 124
                $rules[] = [[$this->idAttribute], 'string',
186 124
                    'max' => $this->idAttributeLength,];
187
            }
188 225
            if ($this->idAttributeType === static::$idTypeAutoIncrement) {
189
                $rules[] = [
190
                    [$this->idAttribute], 'safe',
191
                ];
192
            }
193 225
            return $rules;
194
        }
195
        return [];
196
    }
197
    
198 1
    public static function compositeIDs($models)
199
    {
200 1
        if (!is_array($models) && $models instanceof static) {
201 1
            return $models->getID();
202
        }
203 1
        $ids = [];
204 1
        foreach ($models as $model) {
205 1
            if ($model instanceof static) {
206 1
                $ids[] = $model->getID();
207
            }
208
        }
209 1
        return $ids;
210
    }
211
}
212
213