Passed
Push — master ( 62683c...bde981 )
by Jean-Philippe
11:44
created

Countdown::getStringForHumanRead()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 24
rs 8.9713
cc 3
eloc 12
nc 2
nop 1
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 timezone does not exist on jpmurray\LaravelCountdown\Countdown. Did you maybe forget to declare it?
Loading history...
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;
0 ignored issues
show
Bug Best Practice introduced by
The property carbon does not exist on jpmurray\LaravelCountdown\Countdown. Did you maybe forget to declare it?
Loading history...
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;
0 ignored issues
show
Bug Best Practice introduced by
The property carbon does not exist on jpmurray\LaravelCountdown\Countdown. Did you maybe forget to declare it?
Loading history...
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);
0 ignored issues
show
Bug Best Practice introduced by
The property carbon does not exist on jpmurray\LaravelCountdown\Countdown. Did you maybe forget to declare it?
Loading history...
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