TimestampableTrait::usesTimestampsDefault()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace ByTIC\DataObjects\Behaviors\Timestampable;
4
5
use DateTime;
6
use Nip\Utility\Date;
7
8
/**
9
 * Trait TimestampableTrait
10
 * @package ByTIC\DataObjects\Behaviors\Timestampable
11
 */
12
trait TimestampableTrait
13
{
14
    /**
15
     * Indicates if the model should be timestamped.
16
     *
17
     * @var bool
18
     * public $timestamps = true;
19
     */
20
21
    protected $timestampableTypes = ['create', 'update'];
22
23
    /**
24
     * @param $attributes
25
     * @throws \Exception
26
     */
27
    public function updatedTimestamps($attributes)
28
    {
29
        if ($this->usesTimestamps() === false) {
30
            return;
31
        }
32
33
        if (is_string($attributes)) {
34
            if (in_array($attributes, $this->timestampableTypes)) {
0 ignored issues
show
Bug introduced by
$this->timestampableTypes of type boolean is incompatible with the type array expected by parameter $haystack of in_array(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

34
            if (in_array($attributes, /** @scrutinizer ignore-type */ $this->timestampableTypes)) {
Loading history...
35
                $attributes = $this->getTimestampAttributes($attributes);
36
            } else {
37
                $attributes = [$attributes];
38
            }
39
        }
40
        foreach ($attributes as $attribute) {
41
            /** @noinspection PhpUnhandledExceptionInspection */
42
            $this->setModelTimeAttribute($attribute, $this->{$attribute});
43
        }
44
    }
45
46
    /**
47
     * Determine if the model uses timestamps.
48
     *
49
     * @return bool
50
     */
51
    public function usesTimestamps(): bool
52
    {
53
        static $timestamps = null;
54
        if (is_bool($timestamps)) {
55
            return $timestamps;
56
        }
57
        if (property_exists($this, 'timestamps')) {
58
            $timestamps = $this->timestamps;
59
            return $timestamps;
60
        }
61
        if (property_exists($this, 'createTimestamps')) {
62
            $timestamps = true;
63
            return $timestamps;
64
        }
65
        if (property_exists($this, 'updateTimestamps')) {
66
            $timestamps = true;
67
            return $timestamps;
68
        }
69
70
        $timestamps = $this->usesTimestampsDefault();
71
        return $timestamps;
72
    }
73
74
    /**
75
     * @return false
76
     */
77
    protected function usesTimestampsDefault()
78
    {
79
        return false;
80
    }
81
82
    public function bootTimestampableTrait()
83
    {
84
        if ($this->usesTimestamps() === false) {
85
            return;
86
        }
87
        $this->hookCastableTrait();
88
    }
89
90
    /**
91
     * @param $attribute
92
     * @param $value
93
     * @return false|int|mixed|Date
94
     * @throws \Exception
95
     */
96
    public function setModelTimeAttribute($attribute, $value = null)
97
    {
98
        if (\is_string($value) && !empty($value)) {
99
            $unix = \strtotime($value);
100
            if ($unix === false) {
101
                throw new \Exception(
102
                    sprintf(
103
                        "Error parsing time value [%s] for field [%s] in object [%s]",
104
                        $value,
105
                        $attribute,
106
                        get_class($this)
107
                    )
108
                );
109
            }
110
            $value = $unix;
111
        }
112
113
        if (\is_numeric($value)) {
114
            $value = Date::createFromTimestamp($value);
115
        }
116
117
        if (!\is_object($value)) {
118
            $value = Date::now();
119
        }
120
        return $this->{$attribute} = $value;
121
    }
122
123
    /**
124
     * Get a fresh timestamp for the model.
125
     *
126
     * @return \Nip\Utility\Date
127
     */
128
    public function freshTimestamp(): DateTime
129
    {
130
        return Date::now();
131
    }
132
133
    /**
134
     * @param string $type
135
     * @return array
136
     */
137
    public function getTimestampAttributes(string $type = 'create'): array
138
    {
139
        if (!in_array($type, ['create', 'update'])) {
140
            return [];
141
        }
142
        $updateTimestamps = $this->getUpdateTimestamps();
143
        if ($type == 'update') {
144
            return $updateTimestamps;
145
        }
146
        $createTimestamps = $this->getCreateTimestamps();
147
148
        return array_merge($createTimestamps, $updateTimestamps);
149
    }
150
151
    /**
152
     * Get the name of the "created at" column.
153
     *
154
     * @return array
155
     */
156
    public function getCreateTimestamps(): array
157
    {
158
        if (!isset(static::$createTimestamps)) {
159
            return $this->timestamps === true ? ['created_at'] : [];
0 ignored issues
show
Bug introduced by
The property timestamps does not exist on ByTIC\DataObjects\Behavi...able\TimestampableTrait. Did you mean timestampableTypes?
Loading history...
160
        }
161
        if (is_string(static::$createTimestamps)) {
162
            static::$createTimestamps = [static::$createTimestamps];
0 ignored issues
show
Bug Best Practice introduced by
The property createTimestamps does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
163
        }
164
        return static::$createTimestamps;
165
    }
166
167
    /**
168
     * Get the name of the "updated at" column.
169
     *
170
     * @return array
171
     */
172
    public function getUpdateTimestamps(): array
173
    {
174
        if (!isset(static::$updateTimestamps)) {
175
            return $this->timestamps === true ? ['updated_at'] : [];
0 ignored issues
show
Bug introduced by
The property timestamps does not exist on ByTIC\DataObjects\Behavi...able\TimestampableTrait. Did you mean timestampableTypes?
Loading history...
176
        }
177
        if (is_string(static::$updateTimestamps)) {
178
            static::$updateTimestamps = [static::$updateTimestamps];
0 ignored issues
show
Bug Best Practice introduced by
The property updateTimestamps does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
179
        }
180
        return static::$updateTimestamps;
181
    }
182
183
    /**
184
     * Get carbon object from timestamp attribute.
185
     *
186
     * @param string $attribute Attribute name
187
     *
188
     * @return Date|null|string
189
     */
190
    public function getTimeFromAttribute(string $attribute)
191
    {
192
        $value = $this->{$attribute};
0 ignored issues
show
Unused Code introduced by
The assignment to $value is dead and can be removed.
Loading history...
193
194
        if (!$this->{$attribute}) {
195
            return $this->attributes[$attribute] = Date::now()->timestamp;
0 ignored issues
show
Bug Best Practice introduced by
The property attributes does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
196
        }
197
198
        if (\is_string($this->attributes[$attribute]) && $timestamp = \strtotime($this->attributes[$attribute])) {
199
            return $this->attributes[$attribute] = (new Date())->setTimestamp($timestamp);
200
        }
201
202
        return $this->attributes[$attribute];
203
    }
204
205
    protected function hookCastableTrait()
206
    {
207
        if (method_exists($this, 'addCast') === false) {
208
            return;
209
        }
210
        $fields = $this->getTimestampAttributes();
211
        foreach ($fields as $field) {
212
            if ($this->hasCast($field)) {
0 ignored issues
show
Bug introduced by
It seems like hasCast() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

212
            if ($this->/** @scrutinizer ignore-call */ hasCast($field)) {
Loading history...
213
                continue;
214
            }
215
            $this->addCast($field,'datetime');
216
        }
217
    }
218
}
219