Completed
Push — master ( 15c8d0...bf148f )
by vistart
04:55
created

IDTrait   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 91.38%

Importance

Changes 0
Metric Value
wmc 31
lcom 1
cbo 3
dl 0
loc 173
ccs 53
cts 58
cp 0.9138
rs 9.8
c 0
b 0
f 0

7 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
D getIdRules() 0 35 10
B generateId() 0 17 5
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 18
    public function getID()
70
    {
71 18
        $idAttribute = $this->idAttribute;
72 18
        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 200
    public function setID($identity)
81
    {
82 200
        $idAttribute = $this->idAttribute;
83 200
        return (is_string($idAttribute) && !empty($idAttribute)) ? $this->$idAttribute = $identity : null;
84
    }
85
    
86
    /**
87
     * Attach `onInitGuidAttribute` event.
88
     * @param string $eventName
89
     */
90 215
    protected function attachInitIDEvent($eventName)
91
    {
92 215
        $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 215
    }
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 215
    public function onInitIDAttribute($event)
104
    {
105 215
        $sender = $event->sender;
106
        /* @var $sender static */
107 215
        if ($sender->idPreassigned) {
108 95
            return;
109
        }
110 215
        if ($sender->idAttributeType === static::$idTypeAutoIncrement) {
111 30
            $sender->idAttributeSafe = true;
112 30
            return;
113
        }
114 200
        $idAttribute = $sender->idAttribute;
115 200
        if (is_string($idAttribute) && !empty($idAttribute) &&
116 200
            is_int($sender->idAttributeLength) &&
117 200
            $sender->idAttributeLength > 0) {
118 200
            $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 200
    }
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 200
    public function generateId()
128
    {
129 200
        if ($this->idAttributeType == static::$idTypeInteger) {
130
            do {
131 143
                $result = Number::randomNumber($this->idAttributePrefix, $this->idAttributeLength);
132 143
            } while ($this->checkIdExists((int) $result));
133 143
            return $result;
134
        }
135 97
        if ($this->idAttributeType == static::$idTypeString) {
136 97
            return $this->idAttributePrefix .
137 97
                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 144
    public function checkIdExists($identity)
151
    {
152 144
        if ($identity == null) {
153 4
            return false;
154
        }
155 144
        return (static::findOne([$this->idAttribute => $identity]) !== null);
156
    }
157
    
158
    /**
159
     * Get the rules associated with id attribute.
160
     * @return array
161
     */
162 195
    public function getIdRules()
163
    {
164 195
        if ($this->idAttribute == false) {
165
            return [];
166
        }
167 195
        if ($this->idAttributeSafe) {
168
            return [
169 29
                [[$this->idAttribute], 'safe'],
170
            ];
171
        }
172 179
        if (is_string($this->idAttribute) && !empty($this->idAttribute) &&
173 179
            is_int($this->idAttributeLength) &&
174 179
            $this->idAttributeLength > 0) {
175
            $rules = [
176 179
                [[$this->idAttribute], 'required'],
177 179
                [[$this->idAttribute], 'unique'],
178
            ];
179 179
            if ($this->idAttributeType === static::$idTypeInteger) {
180 137
                $rules[] = [
181 137
                    [$this->idAttribute], 'number', 'integerOnly' => true
182
                ];
183
            }
184 179
            if ($this->idAttributeType === static::$idTypeString) {
185 81
                $rules[] = [[$this->idAttribute], 'string',
186 81
                    'max' => $this->idAttributeLength,];
187
            }
188 179
            if ($this->idAttributeType === static::$idTypeAutoIncrement) {
189
                $rules[] = [
190
                    [$this->idAttribute], 'safe',
191
                ];
192
            }
193 179
            return $rules;
194
        }
195
        return [];
196
    }
197
}
198
199