IDTrait::checkIdExists()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

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