Completed
Push — master ( affc33...0fafe5 )
by vistart
05:30
created

IDTrait::onInitIdAttribute()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 10
Bugs 0 Features 0
Metric Value
c 10
b 0
f 0
dl 0
loc 17
ccs 14
cts 14
cp 1
rs 8.8571
cc 6
eloc 12
nc 4
nop 1
crap 6
1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link http://vistart.name/
9
 * @copyright Copyright (c) 2016 vistart
10
 * @license http://vistart.name/license/
11
 */
12
13
namespace vistart\Models\traits;
14
15
use Yii;
16
use vistart\Helpers\Number;
17
18
/**
19
 * Entity features concerning ID.
20
 * @property-read array $idRules
21
 * @property mixed $id
22
 * @version 2.0
23
 * @author vistart <[email protected]>
24
 */
25
trait IDTrait
26
{
27
28
    /**
29
     * @var string OPTIONAL.The attribute that will receive the IDentifier No.
30
     * You can set this property to false if you don't use this feature.
31
     * @since 1.1
32
     */
33
    public $idAttribute = 'id';
34
    public static $idTypeString = 0;
35
    public static $idTypeInteger = 1;
36
    public static $idTypeAutoIncrement = 2;
37
38
    /**
39
     * @var integer type of id attribute.
40
     * @since 2.0
41
     */
42
    public $idAttributeType = 0;
43
44
    /**
45
     * @var boolean Determines whether its id has been pre-assigned. It will not
46
     * generate or assign ID if true.
47
     */
48
    public $idPreassigned = false;
49
50
    /**
51
     * @var string The prefix of ID. When ID type is Auto Increment, this feature
52
     * is skipped.
53
     * @since 2.0
54
     */
55
    public $idAttributePrefix = '';
56
57
    /**
58
     * @var integer OPTIONAL. The length of id attribute value, and max length
59
     * of this attribute in rules. If you set $idAttribute to false or ID type
60
     * to Auto Increment, this property will be ignored.
61
     * @since 1.1
62
     */
63
    public $idAttributeLength = 4;
64
65
    /**
66
     * @var boolean Determine whether the ID is safe for validation.
67
     * @since 1.1
68
     */
69
    protected $idAttributeSafe = false;
70
71
    /**
72
     * Get id.
73
     * @return string|integer
74
     */
75 1
    public function getId()
76
    {
77 1
        $idAttribute = $this->idAttribute;
78 1
        return is_string($idAttribute) ? $this->$idAttribute : null;
79
    }
80
81
    /**
82
     * Set id.
83
     * @param string|integer $identity
84
     * @return string|integer
85
     */
86
    public function setId($identity)
87
    {
88
        $idAttribute = $this->idAttribute;
89
        return is_string($idAttribute) ? $this->$idAttribute = $identity : null;
90
    }
91
92
    /**
93
     * Attach `onInitGuidAttribute` event.
94
     * @param string $eventName
95
     */
96 38
    protected function attachInitIdEvent($eventName)
97
    {
98 38
        $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...
99 38
    }
100
101
    /**
102
     * Initialize the ID attribute with new generated ID.
103
     * If the model's id is pre-assigned, then it will return directly.
104
     * If the model's id is auto-increment, the id attribute will be marked safe.
105
     * This method is ONLY used for being triggered by event. DO NOT call,
106
     * override or modify it directly, unless you know the consequences.
107
     * @param \yii\base\Event $event
108
     * @since 1.1
109
     */
110 38
    public function onInitIdAttribute($event)
111
    {
112 38
        $sender = $event->sender;
113 38
        if ($sender->idPreassigned) {
114 22
            return;
115
        }
116 38
        if ($sender->idAttributeType === self::$idTypeAutoIncrement) {
117 1
            $sender->idAttributeSafe = true;
118 1
            return;
119
        }
120 37
        if (is_string($sender->idAttribute) &&
121 37
            is_int($sender->idAttributeLength) &&
122 37
            $sender->idAttributeLength > 0) {
123 37
            $idAttribute = $sender->idAttribute;
124 37
            $sender->$idAttribute = $sender->generateId();
125 37
        }
126 37
    }
127
128
    /**
129
     * Generate the ID. You can override this method to implement your own
130
     * generation algorithm.
131
     * @return string the generated ID.
132
     */
133 37
    public function generateId()
134
    {
135 37
        if ($this->idAttributeType == self::$idTypeInteger) {
136
            do {
137 36
                $result = Number::randomNumber($this->idAttributePrefix, $this->idAttributeLength);
138 36
            } while ($this->checkIdExists((int) $result));
139 36
            return $result;
140
        }
141 18
        if ($this->idAttributeType == self::$idTypeString) {
142 18
            return $this->idAttributePrefix .
143 18
                Yii::$app->security->generateRandomString($this->idAttributeLength - strlen($this->idAttributePrefix));
144
        }
145
        if ($this->idAttributeType == self::$idTypeAutoIncrement) {
146
            return null;
147
        }
148
        return false;
149
    }
150
151
    /**
152
     * Check if $identity existed.
153
     * @param mixed $identity
154
     * @return boolean
155
     */
156 36
    public function checkIdExists($identity)
157
    {
158 36
        if ($identity == null) {
159
            return false;
160
        }
161 36
        return (static::findOne([$this->idAttribute => $identity]) !== null);
162
    }
163
164
    /**
165
     * Get the rules associated with id attribute.
166
     * @return array
167
     */
168 8
    public function getIdRules()
169
    {
170 8
        if ($this->idAttribute == false) {
171 3
            return [];
172
        }
173 5
        if ($this->idAttributeSafe) {
174
            return [
175 1
                [[$this->idAttribute], 'safe'],
176 1
            ];
177
        }
178 4
        if (is_string($this->idAttribute) &&
179 4
            is_int($this->idAttributeLength) &&
180 4
            $this->idAttributeLength > 0) {
181
            $rules = [
182 4
                [[$this->idAttribute], 'required'],
183 4
                [[$this->idAttribute], 'unique'],
184 4
            ];
185 4
            if ($this->idAttributeType === self::$idTypeInteger) {
186 1
                $rules[] = [
187 1
                    [$this->idAttribute], 'number', 'integerOnly' => true
188 1
                ];
189 1
            }
190 4
            if ($this->idAttributeType === self::$idTypeString) {
191 4
                $rules[] = [[$this->idAttribute], 'string',
192 4
                    'max' => $this->idAttributeLength,];
193 4
            }
194 4
            if ($this->idAttributeType === self::$idTypeAutoIncrement) {
195
                $rules[] = [
196
                    [$this->idAttribute], 'safe',
197
                ];
198
            }
199 4
            return $rules;
200
        }
201
        return [];
202
    }
203
}
204