Completed
Push — 2.0 ( 28ef84...5fe9f3 )
by Christopher
02:48
created

DateToolbox::validateDateFormat()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 9
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Licensed under The GPL-3.0 License
4
 * For full copyright and license information, please see the LICENSE.txt
5
 * Redistributions of files must retain the above copyright notice.
6
 *
7
 * @since    2.0.0
8
 * @author   Christopher Castro <[email protected]>
9
 * @link     http://www.quickappscms.org
10
 * @license  http://opensource.org/licenses/gpl-3.0.html GPL-3.0 License
11
 */
12
namespace Field\Utility;
13
14
use Cake\Datasource\EntityInterface;
15
use Field\Model\Entity\Field;
16
17
/**
18
 * DateToolbox class for handling date related tasks.
19
 *
20
 */
21
class DateToolbox
22
{
23
24
    /**
25
     * Maps jQuery's datepicker format tokens to PHP's
26
     *
27
     * @var array
28
     */
29
    protected static $_map = [
30
        'date' => [
31
            'dd' => 'd',
32
            'd' => 'j',
33
            'oo' => 'z',
34
            'DD' => 'l',
35
            'D' => 'D',
36
            'mm' => 'm',
37
            'm' => 'n',
38
            'MM' => 'F',
39
            'M' => 'M',
40
            'yy' => 'Y',
41
            'y' => 'y',
42
            '@' => 'U',
43
        ],
44
        'time' => [
45
            'HH' => 'G',
46
            'H' => 'H',
47
            'hh' => 'h',
48
            'h' => 'g',
49
            'mm' => 'i',
50
            'ss' => 's',
51
            'tt' => 'a',
52
            'TT' => 'A',
53
        ]
54
    ];
55
56
    /**
57
     * Formats the given DateField accordingly to current view-mode.
58
     *
59
     * @param \Field\Model\Entity\Field $field The field to be formatted
60
     * @return string Formated date. e.g. `2036-01-01`
61
     */
62
    public static function formatField(Field $field)
63
    {
64
        $timestamp = $field->value ? $field->value->getTimestamp() : 0;
0 ignored issues
show
Bug introduced by
The method getTimestamp cannot be called on $field->value (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
65
        return DateToolbox::formatDate($field->view_mode_settings['format'], $timestamp);
66
    }
67
68
    /**
69
     * Converts the given $date to a valid PHP's DateTime object using a jQuery's
70
     * date/time $format.
71
     *
72
     * @param string $format A jQuery's date/time format. e.g. `'today is:' yy-mm-dd`
73
     * @param string $date A date formatted using $format. e.g. `today is: 2015-01-30`
74
     * @return \DateTime|false Date object on success, false on error
75
     */
76
    public static function createFromFormat($format, $date)
77
    {
78
        if (preg_match_all("/'([^']+)'/", $format, $matches)) {
79
            foreach ($matches[1] as $literal) {
80
                $date = str_replace($literal, '', $date);
81
            }
82
            $date = preg_replace('/\s{2,}/', ' ', $date); // remove double spaces
83
        }
84
85
        $date = trim($date);
86
        $format = DateToolbox::normalizeFormat($format);
87
88
        return date_create_from_format($format, $date);
89
    }
90
91
    /**
92
     * Formats then given UNIX timestamp using the given jQuery format.
93
     *
94
     * @param string $format jQuery format. e.g. `'today is:' yy-mm-dd`
95
     * @param int $timestamp Date as UNIX timestamp
96
     * @return string Formated date. e.g. `today is: 2018-09-09`
97
     */
98
    public static function formatDate($format, $timestamp)
99
    {
100
        static $datesPatterns = null;
101
        static $timesPatterns = null;
102
103 View Code Duplication
        if ($datesPatterns === null || $timesPatterns === null) {
104
            $datesPatterns = "/\b(" . implode('|', array_keys(static::$_map['date'])) . ")\b(?![^']*'(?:(?:[^']*'){2})*[^']*$)/i";
105
            $timesPatterns = "/\b(" . implode('|', array_keys(static::$_map['time'])) . ")\b(?![^']*'(?:(?:[^']*'){2})*[^']*$)/i";
106
        }
107
108
        // normalize formats
109
        $result = preg_replace_callback($datesPatterns, function ($matches) use ($timestamp) {
110
            return date(static::$_map['date'][$matches[1]], $timestamp);
111
        }, trim($format));
112
113
        $result = preg_replace_callback($timesPatterns, function ($matches) use ($timestamp) {
114
            return date(static::$_map['time'][$matches[1]], $timestamp);
115
        }, $result);
116
117
        return str_replace('\'', '', $result);
118
    }
119
120
    /**
121
     * Converts jQuery's date/time format to PHP's.
122
     *
123
     * @param string $format Date format coming from jQuery's datepicker widget.
124
     *  e.g. yy-mm-dd hh:mm
125
     * @return string A valid date/time format to use with PHP
126
     */
127
    public static function normalizeFormat($format)
128
    {
129
        static $datesPatterns = null;
130
        static $timesPatterns = null;
131
132 View Code Duplication
        if ($datesPatterns === null || $timesPatterns === null) {
133
            $datesPatterns = '/(' . implode('|', array_keys(static::$_map['date'])) . ')/';
134
            $timesPatterns = '/(' . implode('|', array_keys(static::$_map['time'])) . ')/';
135
        }
136
137
        $format = trim($format);
138
        $format = preg_replace("/'([^']+)'/", '', $format); // remove quotes
139
        $format = preg_replace('/\s{2,}/', ' ', $format); // remove double spaces
140
        $format = trim($format);
141
        list($dateFormat, $timeFormat) = explode(' ', "{$format} ");
142
143
        // normalize formats
144
        $dateFormat = preg_replace_callback($datesPatterns, function ($matches) {
145
            return static::$_map['date'][$matches[1]];
146
        }, $dateFormat);
147
148
        $timeFormat = preg_replace_callback($timesPatterns, function ($matches) {
149
            return static::$_map['time'][$matches[1]];
150
        }, $timeFormat);
151
152
        $format = trim($dateFormat . ' ' . $timeFormat);
153
154
        return $format;
155
    }
156
157
    /**
158
     * Validates a date format for jQuery's datepicker widget.
159
     *
160
     * @param string $format Format to validate. e.g. yy:mm:ddQ (invalid)
161
     * @return bool
162
     */
163 View Code Duplication
    public static function validateDateFormat($format)
164
    {
165
        $format = str_replace(array_keys(static::$_map['date']), '', $format); // remove placeholders
166
        $format = preg_replace("/'(.*)'/", '', $format); // remove literals
167
        $format = preg_replace('/[^a-z]/i', '', $format);
168
        $format = trim($format);
169
170
        return empty($format);
171
    }
172
173
    /**
174
     * Validates a time format for jQuery's datepicker widget.
175
     *
176
     * @param string $format Format to validate. e.g. hh:mm:ssA (invalid)
177
     * @return bool
178
     */
179 View Code Duplication
    public static function validateTimeFormat($format)
180
    {
181
        $format = str_replace(array_keys(static::$_map['time']), '', $format); // remove placeholders
182
        $format = preg_replace("/'(.*)'/", '', $format); // remove literals
183
        $format = preg_replace('/[^a-z]/i', '', $format);
184
        $format = trim($format);
185
186
        return empty($format);
187
    }
188
189
    /**
190
     * Given a DateField instance, gets its PHP's date-format.
191
     *
192
     * @param \Cake\Datasource\EntityInterface $field DateField instance
193
     * @return string PHP date-format for later use with date() function
194
     */
195
    public static function getPHPFormat(EntityInterface $field)
196
    {
197
        $settings = $field->metadata->settings;
198
        $format = empty($settings['format']) ? 'yy-mm-dd' : $settings['format'];
199
        if ($settings['timepicker']) {
200
            $format .= ' ';
201
            if (empty($settings['time_format'])) {
202
                $format .= 'H:mm';
203
                $format .= empty($settings['time_seconds']) ?: ':ss';
204
            } else {
205
                $format .= $settings['time_format'];
206
            }
207
        }
208
209
        return static::normalizeFormat($format);
210
    }
211
}
212