This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * _ __ __ _____ _____ ___ ____ _____ |
||
5 | * | | / // // ___//_ _// || __||_ _| |
||
6 | * | |/ // /(__ ) / / / /| || | | | |
||
7 | * |___//_//____/ /_/ /_/ |_||_| |_| |
||
8 | * @link https://vistart.name/ |
||
9 | * @copyright Copyright (c) 2016 vistart |
||
10 | * @license https://vistart.name/license/ |
||
11 | */ |
||
12 | |||
13 | namespace vistart\Models\traits; |
||
14 | |||
15 | use vistart\helpers\Number; |
||
16 | use vistart\Models\events\MultipleBlameableEvent; |
||
17 | use vistart\Models\models\BaseUserModel; |
||
18 | use yii\base\ModelEvent; |
||
19 | use yii\base\InvalidCallException; |
||
20 | use yii\base\InvalidConfigException; |
||
21 | use yii\base\InvalidParamException; |
||
22 | use yii\web\JsonParser; |
||
23 | |||
24 | /** |
||
25 | * 一个模型的某个属性可能对应多个责任者,该 trait 用于处理此种情况。此种情况违反 |
||
26 | * 了关系型数据库第一范式,因此此 trait 只适用于责任者属性修改不频繁的场景,在开 |
||
27 | * 发时必须严格测试数据一致性,并同时考量性能。 |
||
28 | * Basic Principles: |
||
29 | * <ol> |
||
30 | * <li>when adding blame, it will check whether each of blames including to be |
||
31 | * added is valid. |
||
32 | * </li> |
||
33 | * <li>when removing blame, as well as counting, getting or setting list of them, |
||
34 | * it will also check whether each of blames is valid. |
||
35 | * </li> |
||
36 | * <li>By default, once blame was deleted, the guid of it is not removed from |
||
37 | * list of blames immediately. It will check blame if valid when adding, removing, |
||
38 | * counting, getting and setting it. You can define a blame model and attach it |
||
39 | * events triggered when inserting, updating and deleting a blame, then disable |
||
40 | * checking the validity of blames. |
||
41 | * </li> |
||
42 | * </ol> |
||
43 | * Notice: |
||
44 | * <ol> |
||
45 | * <li>You must specify two properties: $multiBlamesClass and $multiBlamesAttribute. |
||
46 | * <ul> |
||
47 | * <li>$multiBlamesClass specify the class name of blame.</li> |
||
48 | * <li>$multiBlamesAttribute specify the field name of blames.</li> |
||
49 | * </ul> |
||
50 | * </li> |
||
51 | * <li>You should rename the following methods to be needed optionally.</li> |
||
52 | * </ol> |
||
53 | * @property-read array $multiBlamesAttributeRules |
||
54 | * @property string[] $blameGuids |
||
55 | * @property-read array $allBlames |
||
56 | * @property-read array $nonBlameds |
||
57 | * @property-read integer $blamesCount |
||
58 | * @version 2.0 |
||
59 | * @author vistart <[email protected]> |
||
60 | */ |
||
61 | trait MultipleBlameableTrait |
||
62 | { |
||
63 | |||
64 | /** |
||
65 | * @var string class name of multiple blameable class. |
||
66 | */ |
||
67 | public $multiBlamesClass = ''; |
||
68 | |||
69 | /** |
||
70 | * @var string name of multiple blameable attribute. |
||
71 | */ |
||
72 | public $multiBlamesAttribute = 'blames'; |
||
73 | |||
74 | /** |
||
75 | * @var integer the limit of blames. it should be greater than or equal 1, and |
||
76 | * less than or equal 10. |
||
77 | */ |
||
78 | public $blamesLimit = 10; |
||
79 | |||
80 | /** |
||
81 | * @var boolean determines whether blames list has been changed. |
||
82 | */ |
||
83 | public $blamesChanged = false; |
||
84 | |||
85 | /** |
||
86 | * @var string event name. |
||
87 | */ |
||
88 | public static $eventMultipleBlamesChanged = 'multipleBlamesChanged'; |
||
89 | |||
90 | /** |
||
91 | * Get the rules associated with multiple blameable attribute. |
||
92 | * @return array rules. |
||
93 | */ |
||
94 | 10 | public function getMultipleBlameableAttributeRules() |
|
95 | { |
||
96 | 10 | return is_string($this->multiBlamesAttribute) ? [ |
|
97 | 10 | [[$this->multiBlamesAttribute], 'required'], |
|
98 | 10 | [[$this->multiBlamesAttribute], 'string', 'max' => $this->blamesLimit * 39 + 1], |
|
99 | 10 | [[$this->multiBlamesAttribute], 'default', 'value' => '[]'], |
|
100 | 10 | ] : []; |
|
101 | } |
||
102 | |||
103 | /** |
||
104 | * Add specified blame. |
||
105 | * @param {$this->multiBlamesClass}|string $blame |
||
0 ignored issues
–
show
|
|||
106 | * @return false|array |
||
107 | * @throws InvalidParamException |
||
108 | * @throws InvalidCallException |
||
109 | */ |
||
110 | 2 | public function addBlame($blame) |
|
111 | { |
||
112 | 2 | if (!is_string($this->multiBlamesAttribute)) { |
|
113 | return false; |
||
114 | } |
||
115 | 2 | $blameGuid = ''; |
|
116 | 2 | if (is_string($blame)) { |
|
117 | 1 | $blameGuid = $blame; |
|
118 | 1 | } |
|
119 | 2 | if ($blame instanceof $this->multiBlamesClass) { |
|
120 | 1 | $blameGuid = $blame->guid; |
|
121 | 1 | } |
|
122 | 2 | $blameGuids = $this->getBlameGuids(true); |
|
123 | 2 | if (array_search($blameGuid, $blameGuids)) { |
|
124 | throw new InvalidParamException('the blame has existed.'); |
||
125 | } |
||
126 | 2 | if ($this->getBlamesCount() >= $this->blamesLimit) { |
|
127 | throw new InvalidCallException("the limit($this->blamesLimit) of blames has been reached."); |
||
128 | } |
||
129 | 2 | $blameGuids[] = $blameGuid; |
|
130 | 2 | $this->setBlameGuids($blameGuids); |
|
131 | 2 | return $this->getBlameGuids(); |
|
132 | } |
||
133 | |||
134 | /** |
||
135 | * Create blame. |
||
136 | * @param BaseUserModel $user who will own this blame. |
||
137 | * @param array $config blame class configuration array. |
||
138 | * @return {$this->multiBlamesClass} |
||
0 ignored issues
–
show
The doc-type
{$this->multiBlamesClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
139 | */ |
||
140 | 1 | public static function createBlame($user, $config = []) |
|
141 | { |
||
142 | 1 | if (!($user instanceof BaseUserModel)) { |
|
143 | $message = 'the type of user instance must be the extended class of BaseUserModel.'; |
||
144 | throw new InvalidParamException($message); |
||
145 | } |
||
146 | 1 | $mbClass = static::buildNoInitModel(); |
|
147 | 1 | $mbi = $mbClass->multiBlamesClass; |
|
148 | 1 | return $user->create($mbi::className(), $config); |
|
149 | } |
||
150 | |||
151 | /** |
||
152 | * Add specified blame, or create it before adding if doesn't exist. |
||
153 | * But you should save the blame instance before adding, or the operation |
||
154 | * will fail. |
||
155 | * @param {$this->multiBlamesClass}|string|array $blame |
||
0 ignored issues
–
show
The doc-type
{$this->multiBlamesClass}|string|array could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
156 | * It will be regarded as blame's guid if it is a string. And assign the |
||
157 | * reference parameter $blame the instance if it existed, or create one if not |
||
158 | * found. |
||
159 | * If it is {$this->multiBlamesClass} instance and existed, then will add it, or |
||
160 | * false will be given if it is not found in database. So if you want to add |
||
161 | * blame instance, you should save it before adding. |
||
162 | * If it is a array, it will be regarded as configuration array of blame. |
||
163 | * Notice! This parameter passed by reference, so it must be a variable! |
||
164 | * @param BaseUserModel $user whose blame. |
||
165 | * If null, it will take this blameable model's user. |
||
166 | * @return false|array false if blame created failed or not enable this feature. |
||
167 | * blames guid array if created and added successfully. |
||
168 | * @throws InvalidConfigException |
||
169 | * @throws InvalidParamException |
||
170 | * @see addBlame() |
||
171 | */ |
||
172 | 1 | public function addOrCreateBlame(&$blame = null, $user = null) |
|
173 | { |
||
174 | 1 | if (!is_string($this->multiBlamesClass)) { |
|
175 | throw new InvalidConfigException('$multiBlamesClass must be specified if you want to use multiple blameable features.'); |
||
176 | } |
||
177 | 1 | if (is_array($blame)) { |
|
178 | 1 | if ($user == null) { |
|
179 | 1 | $user = $this->user; |
|
0 ignored issues
–
show
The property
user does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
180 | 1 | } |
|
181 | 1 | $blame = static::getOrCreateBlame($blame, $user); |
|
182 | 1 | if (!$blame->save()) { |
|
183 | return false; |
||
184 | } |
||
185 | 1 | return $this->addBlame($blame->guid); |
|
186 | } |
||
187 | $blameGuid = ''; |
||
188 | if (is_string($blame)) { |
||
189 | $blameGuid = $blame; |
||
190 | } |
||
191 | if ($blame instanceof $this->multiBlamesClass) { |
||
192 | $blameGuid = $blame->guid; |
||
193 | } |
||
194 | if (($mbi = static::getBlame($blameGuid)) !== null) { |
||
195 | return $this->addBlame($mbi); |
||
196 | } |
||
197 | return false; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Remove specified blame. |
||
202 | * @param {$this->multiBlamesClass} $blame |
||
0 ignored issues
–
show
The doc-type
{$this->multiBlamesClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
203 | * @return false|array all guids in json format. |
||
204 | */ |
||
205 | 1 | public function removeBlame($blame) |
|
206 | { |
||
207 | 1 | if (!is_string($this->multiBlamesAttribute)) { |
|
208 | return false; |
||
209 | } |
||
210 | 1 | $blameGuid = ''; |
|
211 | 1 | if (is_string($blame)) { |
|
212 | 1 | $blameGuid = $blame; |
|
213 | 1 | } |
|
214 | 1 | if ($blame instanceof $this->multiBlamesClass) { |
|
215 | 1 | $blameGuid = $blame->guid; |
|
216 | 1 | } |
|
217 | 1 | $blameGuids = $this->getBlameGuids(true); |
|
218 | 1 | if (($key = array_search($blameGuid, $blameGuids)) !== false) { |
|
219 | 1 | unset($blameGuids[$key]); |
|
220 | 1 | $this->setBlameGuids($blameGuids); |
|
221 | 1 | } |
|
222 | 1 | return $this->getBlameGuids(); |
|
223 | } |
||
224 | |||
225 | /** |
||
226 | * Remove all blames. |
||
227 | */ |
||
228 | 10 | public function removeAllBlames() |
|
229 | { |
||
230 | 10 | $this->setBlameGuids(); |
|
231 | 10 | } |
|
232 | |||
233 | /** |
||
234 | * Count the blames. |
||
235 | * @return integer |
||
236 | */ |
||
237 | 2 | public function getBlamesCount() |
|
238 | { |
||
239 | 2 | return count($this->getBlameGuids(true)); |
|
240 | } |
||
241 | |||
242 | /** |
||
243 | * Get the guid array of blames. it may check all guids if valid before return. |
||
244 | * @param boolean $checkValid determines whether checking the blame is valid. |
||
245 | * @return array all guids in json format. |
||
246 | */ |
||
247 | 2 | public function getBlameGuids($checkValid = false) |
|
248 | { |
||
249 | 2 | $multiBlamesAttribute = $this->multiBlamesAttribute; |
|
250 | 2 | if ($multiBlamesAttribute === false) { |
|
251 | return []; |
||
252 | } |
||
253 | 2 | $jsonParser = new JsonParser(); |
|
254 | 2 | $guids = $jsonParser->parse($this->$multiBlamesAttribute, true); |
|
0 ignored issues
–
show
true is of type boolean , but the function expects a string .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
255 | 2 | if ($checkValid) { |
|
256 | 2 | $guids = $this->unsetInvalidBlames($guids); |
|
257 | 2 | } |
|
258 | 2 | return $guids; |
|
259 | } |
||
260 | |||
261 | /** |
||
262 | * Event triggered when blames list changed. |
||
263 | * @param MultipleBlameableEvent $event |
||
264 | */ |
||
265 | 10 | public function onBlamesChanged($event) |
|
266 | { |
||
267 | 10 | $sender = $event->sender; |
|
268 | 10 | $sender->blamesChanged = $event->blamesChanged; |
|
269 | 10 | } |
|
270 | |||
271 | /** |
||
272 | * Remove invalid blame guid from provided guid array. |
||
273 | * @param array $guids guid array of blames. |
||
274 | * @return array guid array of blames unset invalid. |
||
275 | */ |
||
276 | 10 | protected function unsetInvalidBlames($guids) |
|
277 | { |
||
278 | 10 | $checkedGuids = Number::unsetInvalidUuids($guids); |
|
279 | 10 | $multiBlamesClass = $this->multiBlamesClass; |
|
280 | 10 | foreach ($checkedGuids as $key => $guid) { |
|
281 | 2 | $blame = $multiBlamesClass::findOne($guid); |
|
282 | 2 | if (!$blame) { |
|
283 | 1 | unset($checkedGuids[$key]); |
|
284 | 1 | } |
|
285 | 10 | } |
|
286 | 10 | $diff = array_diff($guids, $checkedGuids); |
|
287 | 10 | $eventName = static::$eventMultipleBlamesChanged; |
|
288 | 10 | $this->trigger($eventName, new MultipleBlameableEvent(['blamesChanged' => !empty($diff)])); |
|
0 ignored issues
–
show
It seems like
trigger() 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 Adding the ![]() |
|||
289 | 10 | return $checkedGuids; |
|
290 | } |
||
291 | |||
292 | /** |
||
293 | * Set the guid array of blames, it may check all guids if valid. |
||
294 | * @param array $guids guid array of blames. |
||
295 | * @param boolean $checkValid determines whether checking the blame is valid. |
||
296 | * @return false|array all guids. |
||
297 | */ |
||
298 | 10 | public function setBlameGuids($guids = [], $checkValid = true) |
|
299 | { |
||
300 | 10 | if (!is_array($guids) || $this->multiBlamesAttribute === false) { |
|
301 | return null; |
||
302 | } |
||
303 | 10 | if ($checkValid) { |
|
304 | 10 | $guids = $this->unsetInvalidBlames($guids); |
|
305 | 10 | } |
|
306 | 10 | $multiBlamesAttribute = $this->multiBlamesAttribute; |
|
307 | 10 | $this->$multiBlamesAttribute = json_encode(array_values($guids)); |
|
308 | 10 | return $guids; |
|
309 | } |
||
310 | |||
311 | /** |
||
312 | * Get blame. |
||
313 | * @param string $blameGuid |
||
314 | * @return {$this->multiBlamesClass} |
||
0 ignored issues
–
show
The doc-type
{$this->multiBlamesClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
315 | */ |
||
316 | 2 | public static function getBlame($blameGuid) |
|
317 | { |
||
318 | 2 | $self = static::buildNoInitModel(); |
|
319 | 2 | if (empty($self->multiBlamesClass) || !is_string($self->multiBlamesClass) || $self->multiBlamesAttribute === false) { |
|
320 | return null; |
||
321 | } |
||
322 | 2 | $mbClass = $self->multiBlamesClass; |
|
323 | 2 | return $mbClass::findOne($blameGuid); |
|
324 | } |
||
325 | |||
326 | /** |
||
327 | * Get or create blame. |
||
328 | * @param string|array $blameGuid |
||
329 | * @param BaseUserModel $user |
||
330 | * @return {$this->multiBlamesClass}|null |
||
0 ignored issues
–
show
The doc-type
{$this->multiBlamesClass}|null could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
331 | */ |
||
332 | 1 | public static function getOrCreateBlame($blameGuid, $user = null) |
|
333 | { |
||
334 | 1 | if (is_string($blameGuid)) { |
|
335 | $blameGuid = static::getBlame($blameGuid); |
||
336 | if ($blameGuid !== null) { |
||
337 | return $blameGuid; |
||
338 | } |
||
339 | } |
||
340 | 1 | if (is_array($blameGuid)) { |
|
341 | 1 | return static::createBlame($user, $blameGuid); |
|
0 ignored issues
–
show
It seems like
$user defined by parameter $user on line 332 can be null ; however, vistart\Models\traits\Mu...bleTrait::createBlame() does not accept null , maybe add an additional type check?
It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null. We recommend to add an additional type check (or disallow null for the parameter): function notNullable(stdClass $x) { }
// Unsafe
function withoutCheck(stdClass $x = null) {
notNullable($x);
}
// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
if ($x instanceof stdClass) {
notNullable($x);
}
}
// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
notNullable($x);
}
![]() |
|||
342 | } |
||
343 | return null; |
||
344 | } |
||
345 | |||
346 | /** |
||
347 | * Get all ones to be blamed by `$blame`. |
||
348 | * @param {$this->multiBlamesClass} $blame |
||
0 ignored issues
–
show
The doc-type
{$this->multiBlamesClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
349 | * @return array |
||
350 | */ |
||
351 | 1 | public function getBlameds($blame) |
|
352 | { |
||
353 | 1 | $blameds = static::getBlame($blame->guid); |
|
354 | 1 | if (empty($blameds)) { |
|
355 | 1 | return null; |
|
356 | } |
||
357 | 1 | $createdByAttribute = $this->createdByAttribute; |
|
0 ignored issues
–
show
The property
createdByAttribute does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
358 | 1 | return static::find()->where([$createdByAttribute => $this->$createdByAttribute]) |
|
359 | 1 | ->andWhere(['like', $this->multiBlamesAttribute, $blame->guid])->all(); |
|
360 | } |
||
361 | |||
362 | /** |
||
363 | * Get all the blames of record. |
||
364 | * @return array all blames. |
||
365 | */ |
||
366 | 1 | public function getAllBlames() |
|
367 | { |
||
368 | 1 | if (empty($this->multiBlamesClass) || |
|
369 | 1 | !is_string($this->multiBlamesClass) || |
|
370 | 1 | $this->multiBlamesAttribute === false) { |
|
371 | return null; |
||
372 | } |
||
373 | 1 | $multiBlamesClass = $this->multiBlamesClass; |
|
374 | 1 | $createdByAttribute = $this->createdByAttribute; |
|
375 | 1 | return $multiBlamesClass::findAll([$createdByAttribute => $this->$createdByAttribute]); |
|
376 | } |
||
377 | |||
378 | /** |
||
379 | * Get all records which without any blames. |
||
380 | * @return array all non-blameds. |
||
381 | */ |
||
382 | 1 | public function getNonBlameds() |
|
383 | { |
||
384 | 1 | $createdByAttribute = $this->createdByAttribute; |
|
385 | $cond = [ |
||
386 | 1 | $createdByAttribute => $this->$createdByAttribute, |
|
387 | 1 | $this->multiBlamesAttribute => static::getEmptyBlamesJson() |
|
388 | 1 | ]; |
|
389 | 1 | return static::find()->where($cond)->all(); |
|
390 | } |
||
391 | |||
392 | /** |
||
393 | * Initialize blames limit. |
||
394 | * @param ModelEvent $event |
||
395 | */ |
||
396 | 10 | public function onInitBlamesLimit($event) |
|
397 | { |
||
398 | 10 | $sender = $event->sender; |
|
399 | 10 | if (!is_int($sender->blamesLimit) || $sender->blamesLimit < 1 || $sender->blamesLimit > 64) { |
|
400 | $sender->blamesLimit = 10; |
||
401 | } |
||
402 | 10 | } |
|
403 | |||
404 | /** |
||
405 | * Get the json of empty blames array. |
||
406 | * @return string |
||
407 | */ |
||
408 | 1 | public static function getEmptyBlamesJson() |
|
409 | { |
||
410 | 1 | return json_encode([]); |
|
411 | } |
||
412 | } |
||
413 |
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.