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.me/ |
||
9 | * @copyright Copyright (c) 2016 - 2017 vistart |
||
10 | * @license https://vistart.me/license/ |
||
11 | */ |
||
12 | |||
13 | namespace rhosocial\base\models\traits; |
||
14 | |||
15 | use Closure; |
||
16 | use yii\base\ModelEvent; |
||
17 | use yii\behaviors\TimestampBehavior; |
||
18 | |||
19 | /** |
||
20 | * Entity features concerning timestamp. |
||
21 | * @property-read array $timestampBehaviors |
||
22 | * @property-read string|int createdAt |
||
23 | * @property-read string|int updatedAt |
||
24 | * @property-read array $createdAtRules |
||
25 | * @property-read array $updatedAtRules |
||
26 | * @property-read boolean isExpired |
||
27 | * @property int|false expiredAfter the expiration duration in seconds, or false if not expired. |
||
28 | * @version 1.0 |
||
29 | * @author vistart <[email protected]> |
||
30 | */ |
||
31 | trait TimestampTrait |
||
32 | { |
||
33 | /** |
||
34 | * @var string|false the attribute that receive datetime value |
||
35 | * Set this property to false if you do not want to record the creation time. |
||
36 | */ |
||
37 | public $createdAtAttribute = 'created_at'; |
||
38 | |||
39 | /** |
||
40 | * @var string|false the attribute that receive datetime value. |
||
41 | * Set this property to false if you do not want to record the update time. |
||
42 | */ |
||
43 | public $updatedAtAttribute = 'updated_at'; |
||
44 | |||
45 | /** |
||
46 | * @var string|false the attribute that determine when this entity expire. |
||
47 | * If this entity does not expire, set to false. |
||
48 | */ |
||
49 | public $expiredAfterAttribute = false; |
||
50 | |||
51 | /** |
||
52 | * @var integer Determine the format of timestamp. |
||
53 | */ |
||
54 | public $timeFormat = 0; |
||
55 | public static $timeFormatDatetime = 0; |
||
56 | public static $timeFormatTimestamp = 1; |
||
57 | public static $initDatetime = '1970-01-01 00:00:00'; |
||
58 | public static $initTimestamp = 0; |
||
59 | public $timeType = 0; |
||
60 | public static $timeTypeUtc = 0; |
||
61 | public static $timeTypeLocal = 1; |
||
62 | public static $timeTypes = [ |
||
63 | 0 => 'GMT', |
||
64 | 1 => 'local', |
||
65 | ]; |
||
66 | |||
67 | /** |
||
68 | * @var Closure |
||
69 | */ |
||
70 | public $expiredRemovingCallback; |
||
71 | public static $eventExpiredRemoved = 'expiredRemoved'; |
||
72 | |||
73 | /** |
||
74 | * Check this entity whether expired. |
||
75 | * This feature require creation time. If creation time didn't record, false |
||
76 | * is returned. |
||
77 | * This feature also need expiration duration. If expiration duration didn't |
||
78 | * record, false is returned. |
||
79 | * @return boolean |
||
80 | */ |
||
81 | 221 | public function getIsExpired() |
|
82 | { |
||
83 | 221 | $createdAt = $this->getCreatedAt(); |
|
84 | 221 | if ($this->getExpiredAfter() === false || $createdAt === null) { |
|
85 | 213 | return false; |
|
86 | } |
||
87 | 11 | if ($this->timeType == static::$timeTypeLocal) { |
|
88 | return $this->getDatetimeOffset($this->offsetDatetime($this->currentDatetime(), -$this->getExpiredAfter()), $createdAt) > 0; |
||
89 | 11 | } elseif ($this->timeType == static::$timeTypeUtc) { |
|
90 | 11 | return $this->getDatetimeOffset($this->offsetDatetime($this->currentUtcDatetime(), -$this->getExpiredAfter()), $createdAt) > 0; |
|
91 | } |
||
92 | return false; |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Remove myself if expired. |
||
97 | * The `expiredRemovingCallback` will be called before removing itself, |
||
98 | * then it would trigger `static::$eventExpiredRemoved` event, and attach |
||
99 | * the removing results. |
||
100 | * @return boolean |
||
101 | */ |
||
102 | 216 | public function removeIfExpired() |
|
103 | { |
||
104 | 216 | if ($this->getIsExpired() && !$this->getIsNewRecord()) { |
|
0 ignored issues
–
show
|
|||
105 | 11 | if (($this->expiredRemovingCallback instanceof Closure || is_array($this->expiredRemovingCallback)) && is_callable($this->expiredRemovingCallback)) { |
|
106 | 3 | call_user_func($this->expiredRemovingCallback, $this); |
|
107 | } |
||
108 | 11 | $result = $this->removeSelf(); |
|
109 | 11 | $this->trigger(static::$eventExpiredRemoved, new ModelEvent(['data' => ['result' => $result]])); |
|
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 ![]() |
|||
110 | 11 | return true; |
|
111 | } |
||
112 | 205 | return false; |
|
113 | } |
||
114 | |||
115 | /** |
||
116 | * Remove self. |
||
117 | * You can override this method for implementing more complex features. |
||
118 | * @see delete() |
||
119 | * @return integer |
||
120 | */ |
||
121 | 7 | public function removeSelf() |
|
122 | { |
||
123 | 7 | return $this->delete(); |
|
0 ignored issues
–
show
It seems like
delete() 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 ![]() |
|||
124 | } |
||
125 | |||
126 | /** |
||
127 | * We recommened you attach this event when after finding this active record. |
||
128 | * @param ModelEvent $event |
||
129 | * @return boolean |
||
130 | */ |
||
131 | 216 | public function onRemoveExpired($event) |
|
132 | { |
||
133 | 216 | return $event->sender->removeIfExpired(); |
|
134 | } |
||
135 | |||
136 | /** |
||
137 | * Get the current date & time in format of "Y-m-d H:i:s" or timestamp. |
||
138 | * You can override this method to customize the return value. |
||
139 | * @param ModelEvent $event |
||
140 | * @return string Date & Time. |
||
141 | */ |
||
142 | 350 | public static function getCurrentDatetime($event) |
|
143 | { |
||
144 | 350 | $sender = $event->sender; |
|
145 | /* @var $sender static */ |
||
146 | 350 | if ($sender->timeType == static::$timeTypeUtc) { |
|
147 | 348 | return $sender->currentUtcDatetime(); |
|
148 | 2 | } elseif ($sender->timeType == static::$timeTypeLocal) { |
|
149 | 2 | return $sender->currentDatetime(); |
|
150 | } |
||
151 | return null; |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * Get current date & time, by current time format. |
||
156 | * @return string|int Date & time string if format is datetime, or timestamp. |
||
157 | */ |
||
158 | 8 | public function currentDatetime() |
|
159 | { |
||
160 | 8 | if ($this->timeFormat === static::$timeFormatDatetime) { |
|
161 | 7 | return date('Y-m-d H:i:s'); |
|
162 | } |
||
163 | 2 | if ($this->timeFormat === static::$timeFormatTimestamp) { |
|
164 | 1 | return time(); |
|
165 | } |
||
166 | 2 | return null; |
|
167 | } |
||
168 | |||
169 | /** |
||
170 | * Get current Greenwich date & time (UTC), by current time format. |
||
171 | * @return string|int Date & time string if format is datetime, or timestamp. |
||
172 | */ |
||
173 | 349 | public function currentUtcDatetime() |
|
174 | { |
||
175 | 349 | if ($this->timeFormat === static::$timeFormatDatetime) { |
|
176 | 341 | return gmdate('Y-m-d H:i:s'); |
|
177 | } |
||
178 | 9 | if ($this->timeFormat === static::$timeFormatTimestamp) { |
|
179 | 9 | return time(); |
|
180 | } |
||
181 | return null; |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Get offset date & time, by current time format. |
||
186 | * @param string|int $time Date &time string or timestamp. |
||
187 | * @param int $offset Offset in seconds. |
||
188 | * @return string|int Date & time string if format is datetime, or timestamp. |
||
189 | */ |
||
190 | 15 | public function offsetDatetime($time = null, $offset = 0) |
|
191 | { |
||
192 | 15 | if ($this->timeFormat === static::$timeFormatDatetime) { |
|
193 | 14 | return date('Y-m-d H:i:s', strtotime(($offset >= 0 ? "+$offset" : $offset) . " seconds", is_string($time) ? strtotime($time) : (is_int($time) ? $time : time()))); |
|
194 | } |
||
195 | 3 | if ($this->timeFormat === static::$timeFormatTimestamp) { |
|
196 | 3 | return (is_int($time) ? $time : time()) + $offset; |
|
197 | } |
||
198 | 2 | return null; |
|
199 | } |
||
200 | |||
201 | /** |
||
202 | * Calculate the time difference(in seconds). |
||
203 | * @param string|integer $datetime1 |
||
204 | * @param string|integer $datetime2 |
||
205 | * @return integer Positive integer if $datetime1 is later than $datetime2, and vise versa. |
||
206 | */ |
||
207 | 11 | public function getDatetimeOffset($datetime1, $datetime2 = null) |
|
208 | { |
||
209 | 11 | if ($datetime2 === null) { |
|
210 | if ($this->timeType == static::$timeTypeLocal) { |
||
211 | $datetime2 = $this->currentDatetime(); |
||
212 | } elseif ($this->timeType == static::$timeTypeUtc) { |
||
213 | $datetime2 = $this->currentUtcDatetime(); |
||
214 | } |
||
215 | } |
||
216 | 11 | if ($this->timeFormat == static::$timeFormatDatetime) { |
|
217 | 10 | $datetime1 = strtotime($datetime1); |
|
218 | 10 | $datetime2 = strtotime($datetime2); |
|
219 | } |
||
220 | 11 | return $datetime1 - $datetime2; |
|
221 | } |
||
222 | |||
223 | /** |
||
224 | * Get init date & time in format of "Y-m-d H:i:s" or timestamp. |
||
225 | * @param ModelEvent $event |
||
226 | * @return string|int |
||
227 | */ |
||
228 | 23 | public static function getInitDatetime($event) |
|
229 | { |
||
230 | 23 | $sender = $event->sender; |
|
231 | 23 | return $sender->initDatetime(); |
|
232 | } |
||
233 | |||
234 | /** |
||
235 | * Get init date & time, by current time format. |
||
236 | * @return string|int Date & time string if format is datetime, or timestamp. |
||
237 | */ |
||
238 | 24 | public function initDatetime() |
|
239 | { |
||
240 | 24 | if ($this->timeFormat === static::$timeFormatDatetime) { |
|
241 | 24 | return static::$initDatetime; |
|
242 | } |
||
243 | 1 | if ($this->timeFormat === static::$timeFormatTimestamp) { |
|
244 | 1 | return static::$initTimestamp; |
|
245 | } |
||
246 | 1 | return null; |
|
247 | } |
||
248 | |||
249 | /** |
||
250 | * Check whether the attribute is init datetime. |
||
251 | * @param mixed $attribute |
||
252 | * @return boolean |
||
253 | */ |
||
254 | 7 | protected function isInitDatetime($attribute) |
|
255 | { |
||
256 | 7 | if ($this->timeFormat === static::$timeFormatDatetime) { |
|
257 | 7 | return $attribute == static::$initDatetime || $attribute == null; |
|
258 | } |
||
259 | if ($this->timeFormat === static::$timeFormatTimestamp) { |
||
260 | return $attribute == static::$initTimestamp || $attribute == null; |
||
261 | } |
||
262 | return false; |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * Get the current date & time in format of "Y-m-d H:i:s". |
||
267 | * This method is ONLY used for being triggered by event. DO NOT call, |
||
268 | * override or modify it directly, unless you know the consequences. |
||
269 | * @param ModelEvent $event |
||
270 | * @return string Date & Time. |
||
271 | */ |
||
272 | 350 | public function onUpdateCurrentDatetime($event) |
|
273 | { |
||
274 | 350 | return static::getCurrentDatetime($event); |
|
275 | } |
||
276 | |||
277 | /** |
||
278 | * Behaviors associated with timestamp. |
||
279 | * @return array behaviors |
||
280 | */ |
||
281 | 392 | public function getTimestampBehaviors() |
|
282 | { |
||
283 | return [ |
||
284 | [ |
||
285 | 392 | 'class' => TimestampBehavior::class, |
|
286 | 392 | 'createdAtAttribute' => $this->createdAtAttribute, |
|
287 | 392 | 'updatedAtAttribute' => $this->updatedAtAttribute, |
|
288 | 392 | 'value' => [$this, 'onUpdateCurrentDatetime'], |
|
289 | ] |
||
290 | ]; |
||
291 | } |
||
292 | |||
293 | /** |
||
294 | * Get creation time. |
||
295 | * @return string timestamp |
||
296 | */ |
||
297 | 244 | public function getCreatedAt() |
|
298 | { |
||
299 | 244 | $createdAtAttribute = $this->createdAtAttribute; |
|
300 | 244 | if (!is_string($createdAtAttribute) || empty($createdAtAttribute)) { |
|
301 | 9 | return null; |
|
302 | } |
||
303 | 235 | return $this->$createdAtAttribute; |
|
304 | } |
||
305 | |||
306 | /** |
||
307 | * Get rules associated with createdAtAttribute. |
||
308 | * The default rule is safe. Because the [[TimestampBehavior]] will attach |
||
309 | * the creation time automatically. |
||
310 | * Under normal circumstances is not recommended to amend. |
||
311 | * If `createdAtAttribute` is not specified, the empty array will be given. |
||
312 | * @return array rules |
||
313 | */ |
||
314 | 361 | public function getCreatedAtRules() |
|
315 | { |
||
316 | 361 | if (!is_string($this->createdAtAttribute) || empty($this->createdAtAttribute)) { |
|
317 | 9 | return []; |
|
318 | } |
||
319 | return [ |
||
320 | 354 | [[$this->createdAtAttribute], 'safe'], |
|
321 | ]; |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * Get update time. |
||
326 | * @return string timestamp |
||
327 | */ |
||
328 | 35 | public function getUpdatedAt() |
|
329 | { |
||
330 | 35 | $updatedAtAttribute = $this->updatedAtAttribute; |
|
331 | 35 | if (!is_string($updatedAtAttribute) || empty($updatedAtAttribute)) { |
|
332 | 7 | return null; |
|
333 | } |
||
334 | 28 | return $this->$updatedAtAttribute; |
|
335 | } |
||
336 | |||
337 | /** |
||
338 | * Get rules associated with `updatedAtAttribute`. |
||
339 | * The default rule is safe. Because the [[TimestampBehavior]] will attach |
||
340 | * the last update time automatically. |
||
341 | * Under normal circumstances is not recommended to amend. |
||
342 | * If `updatedAtAttribute` is not specified, the empty array will be given. |
||
343 | * @return array rules |
||
344 | */ |
||
345 | 361 | public function getUpdatedAtRules() |
|
346 | { |
||
347 | 361 | if (!is_string($this->updatedAtAttribute) || empty ($this->updatedAtAttribute)) { |
|
348 | 22 | return []; |
|
349 | } |
||
350 | return [ |
||
351 | 354 | [[$this->updatedAtAttribute], 'safe'], |
|
352 | ]; |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Get expiration duration. |
||
357 | * If `expiredAfterAttribute` is not specified, false will be given. |
||
358 | * @return boolean |
||
359 | */ |
||
360 | 221 | public function getExpiredAfter() |
|
361 | { |
||
362 | 221 | if (!is_string($this->expiredAfterAttribute) || empty($this->expiredAfterAttribute)) { |
|
363 | 210 | return false; |
|
364 | } |
||
365 | 11 | return (int)($this->{$this->expiredAfterAttribute}); |
|
366 | } |
||
367 | |||
368 | /** |
||
369 | * Set expiration duration (in seconds). |
||
370 | * If `expiredAfterAttribute` is not specified, this feature will be skipped, |
||
371 | * and return false. |
||
372 | * @param integer $expiredAfter the duration after which is expired (in seconds). |
||
373 | * @return boolean|integer |
||
374 | */ |
||
375 | 15 | public function setExpiredAfter($expiredAfter) |
|
376 | { |
||
377 | 15 | if (!is_string($this->expiredAfterAttribute) || empty($this->expiredAfterAttribute)) { |
|
378 | 4 | return false; |
|
379 | } |
||
380 | 11 | return (int)($this->{$this->expiredAfterAttribute} = (int)$expiredAfter); |
|
381 | } |
||
382 | |||
383 | /** |
||
384 | * Get rules associated with `expiredAfterAttribute`. |
||
385 | * The default rule is unsigned integer. |
||
386 | * Under normal circumstances is not recommended to amend. |
||
387 | * If `expiredAfterAttribute` is not specified, the empty array will be given. |
||
388 | * @return array The key of array is not specified. |
||
389 | */ |
||
390 | 361 | public function getExpiredAfterRules() |
|
391 | { |
||
392 | 361 | if (!is_string($this->expiredAfterAttribute) || empty($this->expiredAfterAttribute)) { |
|
393 | 338 | return []; |
|
394 | } |
||
395 | return [ |
||
396 | 23 | [[$this->expiredAfterAttribute], 'integer', 'min' => 0], |
|
397 | ]; |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Get enabled fields associated with timestamp, including `createdAtAttribute`, |
||
402 | * `updatedAtAttribute` and `expiredAfterAttribute`. |
||
403 | * @return array field list. The keys of array are not specified. |
||
404 | */ |
||
405 | 138 | public function enabledTimestampFields() |
|
406 | { |
||
407 | 138 | $fields = []; |
|
408 | 138 | if (is_string($this->createdAtAttribute) && !empty($this->createdAtAttribute)) { |
|
409 | 138 | $fields[] = $this->createdAtAttribute; |
|
410 | } |
||
411 | 138 | if (is_string($this->updatedAtAttribute) && !empty($this->updatedAtAttribute)) { |
|
412 | 125 | $fields[] = $this->updatedAtAttribute; |
|
413 | } |
||
414 | 138 | if (is_string($this->expiredAfterAttribute) && !empty($this->expiredAfterAttribute)) { |
|
415 | 3 | $fields[] = $this->expiredAfterAttribute; |
|
416 | } |
||
417 | 138 | return $fields; |
|
418 | } |
||
419 | |||
420 | /** |
||
421 | * Check it has been ever edited. |
||
422 | * The judgement principle is to compare the creation time and the last update time, |
||
423 | * if one of the two does not exist, then that has not been modified, |
||
424 | * if both exist but not consistent, that modified. |
||
425 | * You can override this method to implement more complex function. |
||
426 | * @return boolean Whether this entity has ever been edited. |
||
427 | */ |
||
428 | 11 | public function hasEverEdited() |
|
429 | { |
||
430 | 11 | if ($this->getCreatedAt() === null || $this->getUpdatedAt() === null) { |
|
431 | return false; |
||
432 | } |
||
433 | 11 | return $this->getCreatedAt() !== $this->getUpdatedAt(); |
|
434 | } |
||
435 | } |
||
436 |
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
The trait
Idable
provides a methodequalsId
that in turn relies on the methodgetId()
. 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.