Countdown::computeDays()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace jpmurray\LaravelCountdown;
4
5
use Exception;
6
use Carbon\Carbon;
7
use DateTimeInterface;
8
use Illuminate\Foundation\Application;
9
use jpmurray\LaravelCountdown\Exceptions\InvalidArgumentToCountdown;
10
use jpmurray\LaravelCountdown\Exceptions\InvalidDateFormatToCountdown;
11
use jpmurray\LaravelCountdown\Exceptions\InvalidPropertyStringForHumanException;
12
13
class Countdown
14
{
15
    const WEEKS_PER_YEAR     = 52;
16
    const DAYS_PER_WEEK      = 7;
17
    const HOURS_PER_DAY      = 24;
18
    const MINUTES_PER_HOUR   = 60;
19
    const SECONDS_PER_MINUTE = 60;
20
    const SECONDS_PER_HOUR   = 3600;
21
    const SECONDS_PER_DAY    = 86400;
22
    const SECONDS_PER_WEEK   = 604800;
23
    const SECONDS_PER_YEAR   = 31449600;
24
    const STRING_FOR_HUMAN = '{hours} years, {weeks} weeks, {days} days,'
25
    . ' {hours} hours, {minutes} minutes and {seconds} seconds';
26
27
    private $from = null;
28
    private $to = null;
29
    private $delta;
30
    public $years;
31
    public $weeks;
32
    public $days;
33
    public $hours;
34
    public $minutes;
35
    public $seconds;
36
37
    /**
38
     * [__construct description]
39
     * @param Carbon $carbon [description]
40
     */
41
    public function __construct(string $timezone, Carbon $carbon)
42
    {
43
        $this->timezone = $timezone;
0 ignored issues
show
Bug Best Practice introduced by
The property timezone does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
44
        $this->carbon = $carbon->now($this->timezone);
0 ignored issues
show
Bug Best Practice introduced by
The property carbon does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
45
    }
46
47
    /**
48
     * Sets the time to count from
49
     *
50
     * @param string|integer|DateTime|Carbon $time
0 ignored issues
show
Bug introduced by
The type jpmurray\LaravelCountdown\DateTime was not found. Did you mean DateTime? If so, make sure to prefix the type with \.
Loading history...
51
     *
52
     * @return self
53
     */
54
    public function from($time) : self
55
    {
56
        $this->from = $this->asDateTime($time);
57
58
        return $this;
59
    }
60
61
    /**
62
     * Sets the time to count to
63
     *
64
     * @param   string|integer|DateTime|Carbon $time
65
     *
66
     * @return  self
67
     */
68
    public function to($time = null) : self
69
    {
70
        $time ?: $this->carbon;
71
72
        $this->to = $this->asDateTime($time);
73
74
        return $this;
75
    }
76
77
    /**
78
     * Returns the object containing the values for the countdown
79
     *
80
     * @return object
81
     */
82
    public function get()
83
    {
84
        if (is_null($this->from)) {
85
            $this->from = $this->carbon;
86
        }
87
88
        if (is_null($this->to)) {
89
            $this->to = $this->carbon;
90
        }
91
92
        $this->delta = $this->from->diffInSeconds($this->to);
93
        
94
        $this->computeYears()
95
             ->computeWeeks()
96
             ->computeDays()
97
             ->computeHours()
98
             ->computeMinutes()
99
             ->computeSeconds();
100
101
        return $this;
102
    }
103
104
    /**
105
     * Return a timestamp as DateTime object.
106
     *
107
     * @param  mixed  $value
108
     *
109
     * @return \Carbon\Carbon
110
     */
111
    protected function asDateTime($value)
112
    {
113
        try {
114
            // If this value is already a Carbon instance, we shall just return it as is.
115
            // This prevents us having to re-instantiate a Carbon instance when we know
116
            // it already is one, which wouldn't be fulfilled by the DateTime check.
117
            if ($value instanceof Carbon) {
118
                return $value;
119
            }
120
121
            // If the value is already a DateTime instance, we will just skip the rest of
122
            // these checks since they will be a waste of time, and hinder performance
123
            // when checking the field. We will just return the DateTime right away.
124
            if ($value instanceof DateTimeInterface) {
125
                return $this->carbon->instance($value);
126
            }
127
128
            // If this value is an integer, we will assume it is a UNIX timestamp's value
129
            // and format a Carbon object from this timestamp. This allows flexibility
130
            // when defining your date fields as they might be UNIX timestamps here.
131
            if (is_numeric($value)) {
132
                return $this->carbon->createFromTimestamp($value);
133
            }
134
135
            // If the value is in simply year, month, day format
136
            if (is_string($value) && $this->isStandardDateFormat($value)) {
137
                return $this->carbon->createFromFormat('Y-m-d', $value)->startOfDay();
138
            }
139
140
            // Finally
141
            return $this->carbon->parse((string)$value);
142
        } catch (Exception $e) {
143
            throw new InvalidDateFormatToCountdown;
144
        }
145
    }
146
147
    /**
148
     * Determine if the given value is a standard date format.
149
     *
150
     * @param  string  $value
151
     *
152
     * @return bool
153
     */
154
    protected function isStandardDateFormat(string $value) : int
155
    {
156
        return preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value);
157
    }
158
159
    /**
160
     * Compute the number of seconds for the countdown
161
     *
162
     * @return  self
163
     */
164
    private function computeSeconds() : self
165
    {
166
        $this->seconds = intval(bcmod(intval($this->delta), self::SECONDS_PER_MINUTE));
167
168
        return $this;
169
    }
170
171
    /**
172
     * Compute the number of minutes for the countdown
173
     *
174
     * @return  self
175
     */
176
    private function computeMinutes() : self
177
    {
178
        $this->minutes = intval(bcmod((intval($this->delta) / self::SECONDS_PER_MINUTE), self::MINUTES_PER_HOUR));
179
180
        return $this;
181
    }
182
183
    /**
184
     * Compute the number of hours for the countdown
185
     *
186
     * @return  self
187
     */
188
    private function computeHours() : self
189
    {
190
        $this->hours = intval(bcmod((intval($this->delta) / self::SECONDS_PER_HOUR), self::HOURS_PER_DAY));
191
192
        return $this;
193
    }
194
195
    /**
196
     * Compute the number of days for the countdown
197
     *
198
     * @return  self
199
     */
200
    private function computeDays() : self
201
    {
202
        $this->days = intval(bcmod((intval($this->delta) / self::SECONDS_PER_DAY), self::DAYS_PER_WEEK));
203
204
        return $this;
205
    }
206
207
    /**
208
     * Compute the number of weeks for the countdown
209
     *
210
     * @return  self
211
     */
212
    private function computeWeeks() : self
213
    {
214
        $this->weeks = intval(bcmod((intval($this->delta) / self::SECONDS_PER_WEEK), self::WEEKS_PER_YEAR));
215
216
        return $this;
217
    }
218
219
    /**
220
     * Compute the number of years for the countdown
221
     *
222
     * @return  self
223
     */
224
    private function computeYears() : self
225
    {
226
        $this->years = intval(intval($this->delta) / self::SECONDS_PER_YEAR);
227
228
        return $this;
229
    }
230
231
    /**
232
     * Fill string with countdown numbers
233
     *
234
     * @param  string $string string for fill
235
     * @throws \jpmurray\LaravelCountdown\Exceptions\InvalidPropertyStringForHumanException
236
     * @return string
237
     */
238
    private function getStringForHumanRead(string $string) : string
239
    {
240
        // search regex
241
        preg_match_all(
242
            '/{(.*?)}/',
243
            $string,
244
            $matches
245
        );
246
247
        $peaces = $matches[1];
248
        $filled = [];
249
250
        foreach ($peaces as $key => $peace) {
251
            // Check first class has property
252
            if (!property_exists($this, $peace)) {
253
                throw new InvalidPropertyStringForHumanException;
254
            }
255
256
            $filled[$matches[0][$key]] = $this->{$peace};
257
        }
258
259
        $string = str_replace(array_keys($filled), array_values($filled), $string);
260
261
        return $string;
262
    }
263
264
    /**
265
     * Return string with countdown to human read
266
     *
267
     * @param string $custom Custom string to parse
268
     * @return string
269
     */
270
    public function toHuman(string $custom = null) : string
271
    {
272
        $sentence = ($custom ?: static::STRING_FOR_HUMAN);
273
274
        return $this->getStringForHumanRead($sentence);
275
    }
276
}
277