Completed
Push — master ( 638976...707b9c )
by vistart
20:52
created

TimestampTrait::initDatetime()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 4.125

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 10
ccs 3
cts 6
cp 0.5
rs 9.4285
cc 3
eloc 6
nc 3
nop 0
crap 4.125
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 Closure;
16
use yii\behaviors\TimestampBehavior;
17
18
/**
19
 * Entity features concerning timestamp.
20
 * @property-read array $timestampBehaviors
21
 * @property-read string|int createdAt
22
 * @property-read string|int updatedAt
23
 * @property-read array $createdAtRules
24
 * @property-read array $updatedAtRules
25
 * @property-read boolean isExpired
26
 * @version 2.0
27
 * @author vistart <[email protected]>
28
 */
29
trait TimestampTrait
30
{
31
32
    /**
33
     * @var string the attribute that will receive datetime value
34
     * Set this property to false if you do not want to record the creation time.
35
     */
36
    public $createdAtAttribute = 'create_time';
37
38
    /**
39
     * @var string the attribute that will receive datetime value.
40
     * Set this property to false if you do not want to record the update time.
41
     */
42
    public $updatedAtAttribute = 'update_time';
43
44
    /**
45
     * @var integer Determine the format of timestamp.
46
     */
47
    public $timeFormat = 0;
48
    public static $timeFormatDatetime = 0;
49
    public static $timeFormatTimestamp = 1;
50
    public static $initDatetime = '1970-01-01 00:00:00';
51
    public static $initTimestamp = 0;
52
53
    /**
54
     * @var int|false the expiration in seconds, or false if it will not be expired.
55
     */
56
    public $expiredAt = false;
57
58
    /**
59
     * @var Closure
60
     */
61
    public $expiredRemovingCallback;
62
    public static $eventExpiredRemoved = 'expiredRemoved';
63
64
    /**
65
     * Check this entity whether expired.
66
     * @return boolean
67
     */
68 37
    public function getIsExpired()
69
    {
70 37
        $createdAt = $this->createdAt;
71 37
        if ($this->expiredAt === false || $createdAt === null) {
72 31
            return false;
73
        }
74 6
        return $this->offsetDatetime($this->currentDatetime(), -$this->expiredAt) > $createdAt;
75
    }
76
77
    /**
78
     * Remove myself if expired.
79
     * @return boolean
80
     */
81 36
    public function removeIfExpired()
82
    {
83 36
        if ($this->getIsExpired() && !$this->getIsNewRecord()) {
0 ignored issues
show
Bug introduced by
It seems like getIsNewRecord() 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...
84 1
            if (($this->expiredRemovingCallback instanceof Closure || is_array($this->expiredRemovingCallback)) && is_callable($this->expiredRemovingCallback)) {
85 1
                $result = call_user_func($this->expiredRemovingCallback, $this);
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
86 1
            }
87 1
            $result = $this->delete();
0 ignored issues
show
Bug introduced by
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 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...
88 1
            $this->trigger(static::$eventExpiredRemoved, new \yii\base\ModelEvent(['data' => ['result' => $result]]));
0 ignored issues
show
Bug introduced by
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 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...
89 1
        }
90 36
        return false;
91
    }
92
93 36
    public function onRemoveExpired($event)
94
    {
95 36
        $sender = $event->sender;
96 36
        return $sender->removeIfExpired();
97
    }
98
99
    /**
100
     * Get the current date & time in format of "Y-m-d H:i:s" or timestamp.
101
     * You can override this method to customize the return value.
102
     * @param \yii\base\ModelEvent $event
103
     * @return string Date & Time.
104
     * @since 1.1
105
     */
106 46
    public static function getCurrentDatetime($event)
107
    {
108 46
        $sender = $event->sender;
109 46
        return $sender->currentDatetime();
110
    }
111
112 46
    public function currentDatetime()
113
    {
114 46
        if ($this->timeFormat === self::$timeFormatDatetime) {
115 46
            return date('Y-m-d H:i:s');
116
        }
117
        if ($this->timeFormat === self::$timeFormatTimestamp) {
118
            return time();
119
        }
120
    }
121
122 6
    public function offsetDatetime($time = null, $offset = 0)
123
    {
124 6
        if ($this->timeFormat === self::$timeFormatDatetime) {
125 6
            return date('Y-m-d H:i:s', strtotime(($offset >= 0 ? "+$offset" : $offset) . " seconds", is_string($time) ? strtotime($time) : time()));
126
        }
127
        if ($this->timeFormat === self::$timeFormatTimestamp) {
128
            return (is_int($time) ? $time : time()) + $offset;
129
        }
130
        return null;
131
    }
132
133
    /**
134
     * Get init date & time in format of "Y-m-d H:i:s" or timestamp.s
135
     * @param \yii\base\ModelEvent $event
136
     * @return string|int
137
     */
138 8
    public static function getInitDatetime($event)
139
    {
140 8
        $sender = $event->sender;
141 8
        return $sender->initDatetime();
142
    }
143
144 8
    public function initDatetime()
145
    {
146 8
        if ($this->timeFormat === self::$timeFormatDatetime) {
147 8
            return static::$initDatetime;
148
        }
149
        if ($this->timeFormat === self::$timeFormatTimestamp) {
150
            return static::$initTimestamp;
151
        }
152
        return null;
153
    }
154
155
    /**
156
     * Check whether the attribute is init datetime.
157
     * @param mixed $attribute
158
     * @return boolean
159
     */
160 4
    protected function isInitDatetime($attribute)
161
    {
162 4
        if ($this->timeFormat === self::$timeFormatDatetime) {
163 4
            return $attribute == static::$initDatetime || $attribute == null;
164
        }
165
        if ($this->timeFormat === self::$timeFormatTimestamp) {
166
            return $attribute == static::$initTimestamp || $attribute == null;
167
        }
168
        return false;
169
    }
170
171
    /**
172
     * Get the current date & time in format of "Y-m-d H:i:s".
173
     * This method is ONLY used for being triggered by event. DO NOT call,
174
     * override or modify it directly, unless you know the consequences.
175
     * @param \yii\base\Event $event
176
     * @return string Date & Time.
177
     * @since 1.1
178
     */
179 46
    public function onUpdateCurrentDatetime($event)
180
    {
181 46
        return self::getCurrentDatetime($event);
0 ignored issues
show
Compatibility introduced by
$event of type object<yii\base\Event> is not a sub-type of object<yii\base\ModelEvent>. It seems like you assume a child class of the class yii\base\Event to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
182
    }
183
184
    /**
185
     * Behaviors associated with timestamp.
186
     * @return array behaviors
187
     */
188 13
    public function getTimestampBehaviors()
189
    {
190
        return [
191
            [
192 13
                'class' => TimestampBehavior::className(),
193 13
                'createdAtAttribute' => $this->createdAtAttribute,
194 13
                'updatedAtAttribute' => $this->updatedAtAttribute,
195 13
                'value' => [$this, 'onUpdateCurrentDatetime'],
196
            ]
197 13
        ];
198
    }
199
200
    /**
201
     * Get createdAt.
202
     * @return string timestamp
203
     */
204 37
    public function getCreatedAt()
205
    {
206 37
        $createdAtAttribute = $this->createdAtAttribute;
207 37
        if (!is_string($createdAtAttribute)) {
208
            return null;
209
        }
210 37
        return $this->$createdAtAttribute;
211
    }
212
213
    /**
214
     * Get rules associated with createdAtAttribute.
215
     * @return array rules
216
     */
217 13
    public function getCreatedAtRules()
218
    {
219 13
        if (!$this->createdAtAttribute) {
220
            return [];
221
        }
222
        return [
223 13
            [[$this->createdAtAttribute], 'safe'],
224 13
        ];
225
    }
226
227
    /**
228
     * Get updatedAt.
229
     * @return string timestamp
230
     */
231
    public function getUpdatedAt()
232
    {
233
        $updatedAtAttribute = $this->updatedAtAttribute;
234
        if (!is_string($updatedAtAttribute)) {
235
            return null;
236
        }
237
        return $this->$updatedAtAttribute;
238
    }
239
240
    /**
241
     * Get rules associated with updatedAtAttribute.
242
     * @return array rules
243
     */
244 13
    public function getUpdatedAtRules()
245
    {
246 13
        if (!$this->updatedAtAttribute) {
247 1
            return [];
248
        }
249
        return [
250 12
            [[$this->updatedAtAttribute], 'safe'],
251 12
        ];
252
    }
253
}
254