Completed
Push — master ( 113cf9...315017 )
by vistart
05:37
created

IDTrait::compositeIDs()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 8
cp 0
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 8
nc 4
nop 1
crap 30
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 222
    public function setID($identity)
81
    {
82 222
        $idAttribute = $this->idAttribute;
83 222
        return (is_string($idAttribute) && !empty($idAttribute)) ? $this->$idAttribute = $identity : null;
84
    }
85
    
86
    /**
87
     * Attach `onInitGuidAttribute` event.
88
     * @param string $eventName
89
     */
90 237
    protected function attachInitIDEvent($eventName)
91
    {
92 237
        $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 237
    }
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 237
    public function onInitIDAttribute($event)
104
    {
105 237
        $sender = $event->sender;
106
        /* @var $sender static */
107 237
        if ($sender->idPreassigned) {
108 108
            return;
109
        }
110 237
        if ($sender->idAttributeType === static::$idTypeAutoIncrement) {
111 30
            $sender->idAttributeSafe = true;
112 30
            return;
113
        }
114 222
        $idAttribute = $sender->idAttribute;
115 222
        if (is_string($idAttribute) && !empty($idAttribute) &&
116 222
            is_int($sender->idAttributeLength) &&
117 222
            $sender->idAttributeLength > 0) {
118 222
            $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 222
    }
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 222
    public function generateId()
128
    {
129 222
        if ($this->idAttributeType == static::$idTypeInteger) {
130
            do {
131 165
                $result = Number::randomNumber($this->idAttributePrefix, $this->idAttributeLength);
132 165
            } while ($this->checkIdExists((int) $result));
133 165
            return $result;
134
        }
135 119
        if ($this->idAttributeType == static::$idTypeString) {
136 119
            return $this->idAttributePrefix .
137 119
                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 166
    public function checkIdExists($identity)
151
    {
152 166
        if ($identity == null) {
153 4
            return false;
154
        }
155 166
        return (static::findOne([$this->idAttribute => $identity]) !== null);
156
    }
157
    
158
    /**
159
     * Get the rules associated with id attribute.
160
     * @return array
161
     */
162 217
    public function getIdRules()
163
    {
164 217
        if ($this->idAttribute == false) {
165
            return [];
166
        }
167 217
        if ($this->idAttributeSafe) {
168
            return [
169 29
                [[$this->idAttribute], 'safe'],
170
            ];
171
        }
172 201
        if (is_string($this->idAttribute) && !empty($this->idAttribute) &&
173 201
            is_int($this->idAttributeLength) &&
174 201
            $this->idAttributeLength > 0) {
175
            $rules = [
176 201
                [[$this->idAttribute], 'required'],
177 201
                [[$this->idAttribute], 'unique'],
178
            ];
179 201
            if ($this->idAttributeType === static::$idTypeInteger) {
180 159
                $rules[] = [
181 159
                    [$this->idAttribute], 'number', 'integerOnly' => true
182
                ];
183
            }
184 201
            if ($this->idAttributeType === static::$idTypeString) {
185 102
                $rules[] = [[$this->idAttribute], 'string',
186 102
                    'max' => $this->idAttributeLength,];
187
            }
188 201
            if ($this->idAttributeType === static::$idTypeAutoIncrement) {
189
                $rules[] = [
190
                    [$this->idAttribute], 'safe',
191
                ];
192
            }
193 201
            return $rules;
194
        }
195
        return [];
196
    }
197
    
198
    public static function compositeIDs($models)
199
    {
200
        if (!is_array($models) && $models instanceof static) {
201
            return $models->getID();
202
        }
203
        $ids = [];
204
        foreach ($models as $model) {
205
            if ($models instanceof static) {
206
                $ids[] = $model->getID();
207
            }
208
        }
209
        return $ids;
210
    }
211
}
212
213