Failed Conditions
Pull Request — master (#20)
by Arnold
01:53
created

DateExtension::duration()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 4
Bugs 1 Features 1
Metric Value
cc 5
eloc 8
c 4
b 1
f 1
nc 4
nop 3
dl 0
loc 17
ccs 9
cts 9
cp 1
crap 5
rs 9.6111
1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
3
namespace Jasny\Twig;
4
5
use Twig\Extension\AbstractExtension;
6
use Twig\TwigFilter;
7
8
/**
9
 * Format a date based on the current locale in Twig
10
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
11
class DateExtension extends AbstractExtension
12
{
13
    /**
14
     * Class constructor
15
     */
16 40
    public function __construct()
17
    {
18 40
        if (!extension_loaded('intl')) {
19
            throw new \Exception("The Date Twig extension requires the 'intl' PHP extension."); // @codeCoverageIgnore
20
        }
21 40
    }
22
23
24
    /**
25
     * Return extension name
26
     *
27
     * @return string
28
     */
29
    public function getName()
30
    {
31
        return 'jasny/date';
32
    }
33
34
    /**
35
     * Callback for Twig to get all the filters.
36
     *
37
     * @return \Twig\TwigFilter[]
38
     */
39 30
    public function getFilters()
40
    {
41
        return [
42 30
            new TwigFilter('localdate', [$this, 'localDate']),
43 30
            new TwigFilter('localtime', [$this, 'localTime']),
44 30
            new TwigFilter('localdatetime', [$this, 'localDateTime']),
45 30
            new TwigFilter('duration', [$this, 'duration']),
46 30
            new TwigFilter('age', [$this, 'age']),
47
        ];
48
    }
49
50
    /**
51
     * Turn a value into a DateTime object
52
     *
53
     * @param string|int|\DateTime $date
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
54
     * @return \DateTime
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
55
     */
56 22
    protected function valueToDateTime($date)
57
    {
58 22
        if (!$date instanceof \DateTime) {
59 22
            $date = is_int($date) ? \DateTime::createFromFormat('U', $date) : new \DateTime((string)$date);
60
        }
61
62 22
        return $date;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $date could also return false which is incompatible with the documented return type DateTime. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
63
    }
64
65
    /**
66
     * Get configured intl date formatter.
67
     *
68
     * @param string|null $dateFormat
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
69
     * @param string|null $timeFormat
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
70
     * @param string      $calendar
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
71
     * @return \IntlDateFormatter
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
72
     */
73 20
    protected function getDateFormatter($dateFormat, $timeFormat, $calendar)
74
    {
75 20
        $datetype = isset($dateFormat) ? $this->getFormat($dateFormat) : null;
76 20
        $timetype = isset($timeFormat) ? $this->getFormat($timeFormat) : null;
77
78 20
        $calendarConst = $calendar === 'traditional' ? \IntlDateFormatter::TRADITIONAL : \IntlDateFormatter::GREGORIAN;
79
80 20
        $pattern = $this->getDateTimePattern(
81 20
            isset($datetype) ? $datetype : $dateFormat,
82 20
            isset($timetype) ? $timetype : $timeFormat,
83 20
            $calendarConst
84
        );
85
86 20
        return new \IntlDateFormatter(\Locale::getDefault(), $datetype, $timetype, null, $calendarConst, $pattern);
87
    }
88
89
    /**
90
     * Format the date/time value as a string based on the current locale
91
     *
92
     * @param string|false $format  'short', 'medium', 'long', 'full', 'none' or false
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
93
     * @return int|null
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
94
     */
95 20
    protected function getFormat($format)
96
    {
97 20
        if ($format === false) {
98 18
            $format = 'none';
99
        }
100
101
        $types = [
102 20
            'none' => \IntlDateFormatter::NONE,
103
            'short' => \IntlDateFormatter::SHORT,
104
            'medium' => \IntlDateFormatter::MEDIUM,
105
            'long' => \IntlDateFormatter::LONG,
106
            'full' => \IntlDateFormatter::FULL
107
        ];
108
109 20
        return isset($types[$format]) ? $types[$format] : null;
110
    }
111
112
    /**
113
     * Get the date/time pattern.
114
     *
115
     * @param int|string $datetype
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
116
     * @param int|string $timetype
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
117
     * @param int        $calendar
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
118
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
119
     */
120 20
    protected function getDateTimePattern($datetype, $timetype, $calendar = \IntlDateFormatter::GREGORIAN)
121
    {
122 20
        if (is_int($datetype) && is_int($timetype)) {
123 10
            return null;
124
        }
125
126 10
        return $this->getDatePattern(
127 10
            isset($datetype) ? $datetype : \IntlDateFormatter::SHORT,
128 10
            isset($timetype) ? $timetype : \IntlDateFormatter::SHORT,
129 10
            $calendar
130
        );
131
    }
132
133
    /**
134
     * Get the formatter to create a date and/or time pattern
135
     *
136
     * @param int|string $datetype
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
137
     * @param int|string $timetype
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
138
     * @param int        $calendar
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
139
     * @return \IntlDateFormatter
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
140
     */
141 4
    protected function getDatePatternFormatter($datetype, $timetype, $calendar = \IntlDateFormatter::GREGORIAN)
142
    {
143 4
        return \IntlDateFormatter::create(
144 4
            \Locale::getDefault(),
145 4
            is_int($datetype) ? $datetype : \IntlDateFormatter::NONE,
146 4
            is_int($timetype) ? $timetype : \IntlDateFormatter::NONE,
147 4
            \IntlTimeZone::getGMT(),
0 ignored issues
show
Bug introduced by
IntlTimeZone::getGMT() of type IntlTimeZone is incompatible with the type string expected by parameter $timezone of IntlDateFormatter::create(). ( Ignorable by Annotation )

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

147
            /** @scrutinizer ignore-type */ \IntlTimeZone::getGMT(),
Loading history...
148 4
            $calendar
149
        );
150
    }
151
152
    /**
153
     * Get the date and/or time pattern
154
     * Default date pattern is short date pattern with 4 digit year.
155
     *
156
     * @param int|string $datetype
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
157
     * @param int|string $timetype
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
158
     * @param int        $calendar
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
159
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
160
     */
161 10
    protected function getDatePattern($datetype, $timetype, $calendar = \IntlDateFormatter::GREGORIAN)
162
    {
163
        $createPattern =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
introduced by
Consider adding parentheses for clarity. Current Interpretation: $createPattern = (is_int...ntlDateFormatter::NONE), Probably Intended Meaning: $createPattern = is_int(...ntlDateFormatter::NONE)
Loading history...
164 10
            (is_int($datetype) && $datetype !== \IntlDateFormatter::NONE) ||
165 10
            (is_int($timetype) && $timetype !== \IntlDateFormatter::NONE);
166
167 10
        $pattern = $createPattern ? $this->getDatePatternFormatter($datetype, $timetype, $calendar)->getPattern() : '';
168
169 10
        return trim(
170 10
            (is_string($datetype) ? $datetype . ' ' : '') .
171 10
            preg_replace('/\byy?\b/', 'yyyy', $pattern) .
172 10
            (is_string($timetype) ? ' ' . $timetype : '')
173
        );
174
    }
175
176
    /**
177
     * Format the date and/or time value as a string based on the current locale
178
     *
179
     * @param \DateTime|int|string $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
180
     * @param string               $dateFormat  null, 'short', 'medium', 'long', 'full' or pattern
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
181
     * @param string               $timeFormat  null, 'short', 'medium', 'long', 'full' or pattern
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
182
     * @param string               $calendar    'gregorian' or 'traditional'
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
183
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
184
     */
185 23
    protected function formatLocal($value, $dateFormat, $timeFormat, $calendar = 'gregorian')
186
    {
187 23
        if (!isset($value)) {
188 3
            return null;
189
        }
190
191 20
        $date = $this->valueToDateTime($value);
192 20
        $formatter = $this->getDateFormatter($dateFormat, $timeFormat, $calendar);
193
194 20
        return $formatter->format($date->getTimestamp());
195
    }
196
197
    /**
198
     * Format the date value as a string based on the current locale
199
     *
200
     * @param DateTime|int|string $date
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
Bug introduced by
The type Jasny\Twig\DateTime was not found. Did you mean DateTime? If so, make sure to prefix the type with \.
Loading history...
201
     * @param string              $format    null, 'short', 'medium', 'long', 'full' or pattern
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
202
     * @param string              $calendar  'gregorian' or 'traditional'
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
203
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
204
     */
205 11
    public function localDate($date, $format = null, $calendar = 'gregorian')
206
    {
207 11
        return $this->formatLocal($date, $format, false, $calendar);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $timeFormat of Jasny\Twig\DateExtension::formatLocal(). ( Ignorable by Annotation )

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

207
        return $this->formatLocal($date, $format, /** @scrutinizer ignore-type */ false, $calendar);
Loading history...
208
    }
209
210
    /**
211
     * Format the time value as a string based on the current locale
212
     *
213
     * @param DateTime|int|string $date
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
214
     * @param string              $format    'short', 'medium', 'long', 'full' or pattern
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
215
     * @param string              $calendar  'gregorian' or 'traditional'
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
216
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
217
     */
218 7
    public function localTime($date, $format = 'short', $calendar = 'gregorian')
219
    {
220 7
        return $this->formatLocal($date, false, $format, $calendar);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $dateFormat of Jasny\Twig\DateExtension::formatLocal(). ( Ignorable by Annotation )

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

220
        return $this->formatLocal($date, /** @scrutinizer ignore-type */ false, $format, $calendar);
Loading history...
221
    }
222
223
    /**
224
     * Format the date/time value as a string based on the current locale
225
     *
226
     * @param DateTime|int|string $date
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
227
     * @param string              $format    date format, pattern or ['date'=>format, 'time'=>format)
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
228
     * @param string              $calendar  'gregorian' or 'traditional'
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
229
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
230
     */
231 5
    public function localDateTime($date, $format = null, $calendar = 'gregorian')
232
    {
233 5
        if (is_array($format) || $format instanceof \stdClass || !isset($format)) {
234 2
            $formatDate = isset($format['date']) ? $format['date'] : null;
235 2
            $formatTime = isset($format['time']) ? $format['time'] : 'short';
236
        } else {
237 3
            $formatDate = $format;
238 3
            $formatTime = false;
239
        }
240
241 5
        return $this->formatLocal($date, $formatDate, $formatTime, $calendar);
242
    }
243
244
245
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $max should have a doc-comment as per coding-style.
Loading history...
246
     * Split duration into seconds, minutes, hours, days, weeks and years.
247
     *
248
     * @param int $seconds
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
249
     * @return array
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
250
     */
251 13
    protected function splitDuration($seconds, $max)
252
    {
253 13
        if ($max < 1 || $seconds < 60) {
254 1
            return [$seconds];
255
        }
256
257 12
        $minutes = floor($seconds / 60);
258 12
        $seconds = $seconds % 60;
259 12
        if ($max < 2 || $minutes < 60) {
260 2
            return [$seconds, $minutes];
261
        }
262
263 10
        $hours = floor($minutes / 60);
264 10
        $minutes = $minutes % 60;
265 10
        if ($max < 3 || $hours < 24) {
266 4
            return [$seconds, $minutes, $hours];
267
        }
268
269 6
        $days = floor($hours / 24);
270 6
        $hours = $hours % 24;
271 6
        if ($max < 4 || $days < 7) {
272 2
            return [$seconds, $minutes, $hours, $days];
273
        }
274
275 4
        $weeks = floor($days / 7);
276 4
        $days = $days % 7;
277 4
        if ($max < 5 || $weeks < 52) {
278 2
            return [$seconds, $minutes, $hours, $days, $weeks];
279
        }
280
281 2
        $years = floor($weeks / 52);
282 2
        $weeks = $weeks % 52;
283 2
        return [$seconds, $minutes, $hours, $days, $weeks, $years];
284
    }
285
286
    /**
287
     * Calculate duration from seconds.
288
     * One year is seen as exactly 52 weeks.
289
     *
290
     * Use null to skip a unit.
291
     *
292
     * @param int    $value     Time in seconds
0 ignored issues
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
293
     * @param array  $units     Time units (seconds, minutes, hours, days, weeks, years)
0 ignored issues
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
294
     * @param string $separator
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
295
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
296
     */
297 14
    public function duration($value, $units = ['s', 'm', 'h', 'd', 'w', 'y'], $separator = ' ')
298
    {
299 14
        if (!isset($value)) {
300 1
            return null;
301
        }
302
303 13
        $parts = $this->splitDuration($value, count($units) - 1) + array_fill(0, 6, null);
304
305 13
        $duration = '';
306
307 13
        for ($i = 5; $i >= 0; $i--) {
308 13
            if (isset($parts[$i]) && isset($units[$i])) {
309 13
                $duration .= $separator . $parts[$i] . $units[$i];
310
            }
311
        }
312
313 13
        return trim($duration, $separator);
314
    }
315
316
    /**
317
     * Get the age (in years) based on a date.
318
     *
319
     * @param DateTime|string $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
320
     * @return int
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
321
     */
322 3
    public function age($value)
323
    {
324 3
        if (!isset($value)) {
325 1
            return null;
326
        }
327
328 2
        $date = $this->valueToDateTime($value);
329
330 2
        return $date->diff(new \DateTime())->format('%y');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $date->diff(new DateTime())->format('%y') returns the type string which is incompatible with the documented return type integer.
Loading history...
331
    }
332
}
333