|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* @package Pods\Fields |
|
5
|
|
|
*/ |
|
6
|
|
|
class PodsField_DateTime extends PodsField { |
|
7
|
|
|
|
|
8
|
|
|
/** |
|
9
|
|
|
* {@inheritdoc} |
|
10
|
|
|
*/ |
|
11
|
|
|
public static $group = 'Date / Time'; |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* {@inheritdoc} |
|
15
|
|
|
*/ |
|
16
|
|
|
public static $type = 'datetime'; |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* {@inheritdoc} |
|
20
|
|
|
*/ |
|
21
|
|
|
public static $label = 'Date / Time'; |
|
22
|
|
|
|
|
23
|
|
|
/** |
|
24
|
|
|
* {@inheritdoc} |
|
25
|
|
|
*/ |
|
26
|
|
|
public static $prepare = '%s'; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* Storage format. |
|
30
|
|
|
* |
|
31
|
|
|
* @var string |
|
32
|
|
|
* @since 2.7 |
|
33
|
|
|
*/ |
|
34
|
|
|
public static $storage_format = 'Y-m-d H:i:s'; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* The default empty value (database) |
|
38
|
|
|
* |
|
39
|
|
|
* @var string |
|
40
|
|
|
* @since 2.7 |
|
41
|
|
|
*/ |
|
42
|
|
|
public static $empty_value = '0000-00-00 00:00:00'; |
|
43
|
|
|
|
|
44
|
|
|
/** |
|
45
|
|
|
* {@inheritdoc} |
|
46
|
|
|
*/ |
|
47
|
|
|
public function __construct() { |
|
48
|
|
|
|
|
49
|
|
|
static::$label = __( 'Date / Time', 'pods' ); |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* {@inheritdoc} |
|
54
|
|
|
*/ |
|
55
|
|
|
public function options() { |
|
56
|
|
|
|
|
57
|
|
|
$options = array( |
|
58
|
|
|
static::$type . '_repeatable' => array( |
|
59
|
|
|
'label' => __( 'Repeatable Field', 'pods' ), |
|
60
|
|
|
'default' => 0, |
|
61
|
|
|
'type' => 'boolean', |
|
62
|
|
|
'help' => __( 'Making a field repeatable will add controls next to the field which allows users to Add/Remove/Reorder additional values. These values are saved in the database as an array, so searching and filtering by them may require further adjustments".', 'pods' ), |
|
63
|
|
|
'boolean_yes_label' => '', |
|
64
|
|
|
'dependency' => true, |
|
65
|
|
|
'developer_mode' => true, |
|
66
|
|
|
), |
|
67
|
|
|
static::$type . '_type' => array( |
|
68
|
|
|
'label' => __( 'Date Format Type', 'pods' ), |
|
69
|
|
|
'default' => 'format', |
|
70
|
|
|
// Backwards compatibility |
|
71
|
|
|
'type' => 'pick', |
|
72
|
|
|
'help' => __( 'WordPress Default is the format used in Settings, General under "Date Format".', 'pods' ) . '<br>' . __( 'Predefined Format will allow you to select from a list of commonly used date formats.', 'pods' ) . '<br>' . __( 'Custom will allow you to enter your own using PHP Date/Time Strings.', 'pods' ), |
|
73
|
|
|
'data' => array( |
|
74
|
|
|
'wp' => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'date_format' ) ), |
|
75
|
|
|
'format' => __( 'Predefined format', 'pods' ), |
|
76
|
|
|
'custom' => __( 'Custom format', 'pods' ), |
|
77
|
|
|
), |
|
78
|
|
|
'dependency' => true, |
|
79
|
|
|
), |
|
80
|
|
|
static::$type . '_format_custom' => array( |
|
81
|
|
|
'label' => __( 'Date format for display', 'pods' ), |
|
82
|
|
|
'depends-on' => array( static::$type . '_type' => 'custom' ), |
|
83
|
|
|
'default' => '', |
|
84
|
|
|
'type' => 'text', |
|
85
|
|
|
'help' => '<a href="http://php.net/manual/function.date.php" target="_blank">' . __( 'PHP date documentation', 'pods' ) . '</a>', |
|
86
|
|
|
), |
|
87
|
|
|
static::$type . '_format_custom_js' => array( |
|
88
|
|
|
'label' => __( 'Date format for input', 'pods' ), |
|
89
|
|
|
'depends-on' => array( static::$type . '_type' => 'custom' ), |
|
90
|
|
|
'default' => '', |
|
91
|
|
|
'type' => 'text', |
|
92
|
|
|
'help' => '<a href="https://api.jqueryui.com/datepicker/" target="_blank">' . __( 'jQuery UI datepicker documentation', 'pods' ) . '</a>' . '<br>' . __( 'Leave empty to auto-generate from PHP format.', 'pods' ), |
|
93
|
|
|
), |
|
94
|
|
|
static::$type . '_format' => array( |
|
95
|
|
|
'label' => __( 'Date Format', 'pods' ), |
|
96
|
|
|
'depends-on' => array( static::$type . '_type' => 'format' ), |
|
97
|
|
|
'default' => 'mdy', |
|
98
|
|
|
'type' => 'pick', |
|
99
|
|
|
'data' => array( |
|
100
|
|
|
'mdy' => date_i18n( 'm/d/Y' ), |
|
101
|
|
|
'mdy_dash' => date_i18n( 'm-d-Y' ), |
|
102
|
|
|
'mdy_dot' => date_i18n( 'm.d.Y' ), |
|
103
|
|
|
'ymd_slash' => date_i18n( 'Y/m/d' ), |
|
104
|
|
|
'ymd_dash' => date_i18n( 'Y-m-d' ), |
|
105
|
|
|
'ymd_dot' => date_i18n( 'Y.m.d' ), |
|
106
|
|
|
'fjy' => date_i18n( 'F j, Y' ), |
|
107
|
|
|
'fjsy' => date_i18n( 'F jS, Y' ), |
|
108
|
|
|
'c' => date_i18n( 'c' ), |
|
109
|
|
|
), |
|
110
|
|
|
'dependency' => true, |
|
111
|
|
|
), |
|
112
|
|
|
static::$type . '_time_type' => array( |
|
113
|
|
|
'label' => __( 'Time Format Type', 'pods' ), |
|
114
|
|
|
'excludes-on' => array( static::$type . '_format' => 'c' ), |
|
115
|
|
|
'default' => '12', |
|
116
|
|
|
// Backwards compatibility |
|
117
|
|
|
'type' => 'pick', |
|
118
|
|
|
'help' => __( 'WordPress Default is the format used in Settings, General under "Time Format".', 'pods' ) . '<br>' . __( '12/24 hour will allow you to select from a list of commonly used time formats.', 'pods' ) . '<br>' . __( 'Custom will allow you to enter your own using PHP Date/Time Strings.', 'pods' ), |
|
119
|
|
|
'data' => array( |
|
120
|
|
|
'wp' => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'time_format' ) ), |
|
121
|
|
|
'12' => __( '12 hour', 'pods' ), |
|
122
|
|
|
'24' => __( '24 hour', 'pods' ), |
|
123
|
|
|
'custom' => __( 'Custom', 'pods' ), |
|
124
|
|
|
), |
|
125
|
|
|
'dependency' => true, |
|
126
|
|
|
), |
|
127
|
|
|
static::$type . '_time_format_custom' => array( |
|
128
|
|
|
'label' => __( 'Time format', 'pods' ), |
|
129
|
|
|
'depends-on' => array( static::$type . '_time_type' => 'custom' ), |
|
130
|
|
|
'excludes-on' => array( static::$type . '_format' => 'c' ), |
|
131
|
|
|
'default' => '', |
|
132
|
|
|
'type' => 'text', |
|
133
|
|
|
'help' => '<a href="http://php.net/manual/function.date.php" target="_blank">' . __( 'PHP date documentation', 'pods' ) . '</a>', |
|
134
|
|
|
), |
|
135
|
|
|
static::$type . '_time_format_custom_js' => array( |
|
136
|
|
|
'label' => __( 'Time format field input', 'pods' ), |
|
137
|
|
|
'depends-on' => array( static::$type . '_time_type' => 'custom' ), |
|
138
|
|
|
'excludes-on' => array( static::$type . '_format' => 'c' ), |
|
139
|
|
|
'default' => '', |
|
140
|
|
|
'type' => 'text', |
|
141
|
|
|
'help' => '<a href="http://trentrichardson.com/examples/timepicker/#tp-formatting" target="_blank">' . __( 'jQuery UI timepicker documentation', 'pods' ) . '</a>' . '<br>' . __( 'Leave empty to auto-generate from PHP format.', 'pods' ), |
|
142
|
|
|
), |
|
143
|
|
|
static::$type . '_time_format' => array( |
|
144
|
|
|
'label' => __( 'Time Format', 'pods' ), |
|
145
|
|
|
'depends-on' => array( static::$type . '_time_type' => '12' ), |
|
146
|
|
|
'excludes-on' => array( static::$type . '_format' => 'c' ), |
|
147
|
|
|
'default' => 'h_mma', |
|
148
|
|
|
'type' => 'pick', |
|
149
|
|
|
'data' => array( |
|
150
|
|
|
'h_mm_A' => date_i18n( 'g:i A' ), |
|
151
|
|
|
'h_mm_ss_A' => date_i18n( 'g:i:s A' ), |
|
152
|
|
|
'hh_mm_A' => date_i18n( 'h:i A' ), |
|
153
|
|
|
'hh_mm_ss_A' => date_i18n( 'h:i:s A' ), |
|
154
|
|
|
'h_mma' => date_i18n( 'g:ia' ), |
|
155
|
|
|
'hh_mma' => date_i18n( 'h:ia' ), |
|
156
|
|
|
'h_mm' => date_i18n( 'g:i' ), |
|
157
|
|
|
'h_mm_ss' => date_i18n( 'g:i:s' ), |
|
158
|
|
|
'hh_mm' => date_i18n( 'h:i' ), |
|
159
|
|
|
'hh_mm_ss' => date_i18n( 'h:i:s' ), |
|
160
|
|
|
), |
|
161
|
|
|
), |
|
162
|
|
|
static::$type . '_time_format_24' => array( |
|
163
|
|
|
'label' => __( 'Time Format', 'pods' ), |
|
164
|
|
|
'depends-on' => array( static::$type . '_time_type' => '24' ), |
|
165
|
|
|
'excludes-on' => array( static::$type . '_format' => 'c' ), |
|
166
|
|
|
'default' => 'hh_mm', |
|
167
|
|
|
'type' => 'pick', |
|
168
|
|
|
'data' => array( |
|
169
|
|
|
'hh_mm' => date_i18n( 'H:i' ), |
|
170
|
|
|
'hh_mm_ss' => date_i18n( 'H:i:s' ), |
|
171
|
|
|
), |
|
172
|
|
|
), |
|
173
|
|
|
static::$type . '_allow_empty' => array( |
|
174
|
|
|
'label' => __( 'Allow empty value?', 'pods' ), |
|
175
|
|
|
'default' => 1, |
|
176
|
|
|
'type' => 'boolean', |
|
177
|
|
|
), |
|
178
|
|
|
static::$type . '_html5' => array( |
|
179
|
|
|
'label' => __( 'Enable HTML5 Input Field?', 'pods' ), |
|
180
|
|
|
'default' => apply_filters( 'pods_form_ui_field_html5', 0, static::$type ), |
|
181
|
|
|
'type' => 'boolean', |
|
182
|
|
|
), |
|
183
|
|
|
); |
|
184
|
|
|
|
|
185
|
|
|
// Check if PHP DateTime::createFromFormat exists for additional supported formats |
|
186
|
|
View Code Duplication |
if ( method_exists( 'DateTime', 'createFromFormat' ) || apply_filters( 'pods_form_ui_field_datetime_custom_formatter', false ) ) { |
|
187
|
|
|
$options[ static::$type . '_format' ]['data'] = array_merge( |
|
188
|
|
|
$options[ static::$type . '_format' ]['data'], array( |
|
189
|
|
|
'dmy' => date_i18n( 'd/m/Y' ), |
|
190
|
|
|
'dmy_dash' => date_i18n( 'd-m-Y' ), |
|
191
|
|
|
'dmy_dot' => date_i18n( 'd.m.Y' ), |
|
192
|
|
|
'dMy' => date_i18n( 'd/M/Y' ), |
|
193
|
|
|
'dMy_dash' => date_i18n( 'd-M-Y' ), |
|
194
|
|
|
) |
|
195
|
|
|
); |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
$options[ static::$type . '_format' ]['data'] = apply_filters( 'pods_form_ui_field_date_format_options', $options[ static::$type . '_format' ]['data'] ); |
|
199
|
|
|
$options[ static::$type . '_format' ]['default'] = apply_filters( 'pods_form_ui_field_date_format_default', $options[ static::$type . '_format' ]['default'] ); |
|
200
|
|
|
|
|
201
|
|
|
$options[ static::$type . '_time_type' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_type_default', $options[ static::$type . '_time_type' ]['default'] ); |
|
202
|
|
|
$options[ static::$type . '_time_format' ]['data'] = apply_filters( 'pods_form_ui_field_time_format_options', $options[ static::$type . '_time_format' ]['data'] ); |
|
203
|
|
|
$options[ static::$type . '_time_format' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_default', $options[ static::$type . '_time_format' ]['default'] ); |
|
204
|
|
|
$options[ static::$type . '_time_format_24' ]['data'] = apply_filters( 'pods_form_ui_field_time_format_24_options', $options[ static::$type . '_time_format_24' ]['data'] ); |
|
205
|
|
|
$options[ static::$type . '_time_format_24' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_24_default', $options[ static::$type . '_time_format_24' ]['default'] ); |
|
206
|
|
|
|
|
207
|
|
|
return $options; |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* {@inheritdoc} |
|
212
|
|
|
*/ |
|
213
|
|
|
public function schema( $options = null ) { |
|
214
|
|
|
|
|
215
|
|
|
$schema = 'DATETIME NOT NULL default "0000-00-00 00:00:00"'; |
|
216
|
|
|
|
|
217
|
|
|
return $schema; |
|
218
|
|
|
} |
|
219
|
|
|
|
|
220
|
|
|
/** |
|
221
|
|
|
* {@inheritdoc} |
|
222
|
|
|
*/ |
|
223
|
|
|
public function is_empty( $value = null ) { |
|
224
|
|
|
|
|
225
|
|
|
$is_empty = false; |
|
226
|
|
|
|
|
227
|
|
|
$value = trim( $value ); |
|
228
|
|
|
|
|
229
|
|
|
if ( empty( $value ) || in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) { |
|
230
|
|
|
$is_empty = true; |
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
return $is_empty; |
|
234
|
|
|
|
|
235
|
|
|
} |
|
236
|
|
|
|
|
237
|
|
|
/** |
|
238
|
|
|
* {@inheritdoc} |
|
239
|
|
|
*/ |
|
240
|
|
|
public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) { |
|
241
|
|
|
|
|
242
|
|
|
$value = $this->format_value_display( $value, $options, false ); |
|
243
|
|
|
|
|
244
|
|
|
return $value; |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
/** |
|
248
|
|
|
* {@inheritdoc} |
|
249
|
|
|
*/ |
|
250
|
|
|
public function input( $name, $value = null, $options = null, $pod = null, $id = null ) { |
|
251
|
|
|
|
|
252
|
|
|
$options = (array) $options; |
|
253
|
|
|
$form_field_type = PodsForm::$field_type; |
|
254
|
|
|
|
|
255
|
|
|
if ( is_array( $value ) ) { |
|
256
|
|
|
$value = implode( ' ', $value ); |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
// Format Value |
|
260
|
|
|
$value = $this->format_value_display( $value, $options, true ); |
|
261
|
|
|
|
|
262
|
|
|
$field_type = static::$type; |
|
263
|
|
|
|
|
264
|
|
|
if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) { |
|
265
|
|
|
if ( pods_v( 'read_only', $options, false ) ) { |
|
266
|
|
|
$options['readonly'] = true; |
|
267
|
|
|
|
|
268
|
|
|
$field_type = 'text'; |
|
269
|
|
|
} else { |
|
270
|
|
|
return; |
|
271
|
|
|
} |
|
272
|
|
|
} elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) { |
|
273
|
|
|
$options['readonly'] = true; |
|
274
|
|
|
|
|
275
|
|
|
$field_type = 'text'; |
|
276
|
|
|
} |
|
277
|
|
|
|
|
278
|
|
|
pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) ); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
/** |
|
282
|
|
|
* {@inheritdoc} |
|
283
|
|
|
*/ |
|
284
|
|
|
public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) { |
|
285
|
|
|
|
|
286
|
|
|
if ( ! empty( $value ) && ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array( |
|
287
|
|
|
$value, array( |
|
288
|
|
|
'0000-00-00', |
|
289
|
|
|
'0000-00-00 00:00:00', |
|
290
|
|
|
'00:00:00', |
|
291
|
|
|
), true |
|
292
|
|
|
) ) ) { |
|
293
|
|
|
$js = true; |
|
294
|
|
|
|
|
295
|
|
|
if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) { |
|
296
|
|
|
$js = false; |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
$format = $this->format( $options, $js ); |
|
300
|
|
|
|
|
301
|
|
|
if ( $js ) { |
|
302
|
|
|
$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) ); |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
$check = $this->convert_date( $value, static::$storage_format, $format, true ); |
|
306
|
|
|
|
|
307
|
|
|
if ( false === $check ) { |
|
308
|
|
|
$label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) ); |
|
309
|
|
|
|
|
310
|
|
|
return sprintf( esc_html__( '%1$s was not provided in a recognizable format: "%2$s"', 'pods' ), $label, $value ); |
|
311
|
|
|
} |
|
312
|
|
|
}//end if |
|
313
|
|
|
|
|
314
|
|
|
return true; |
|
315
|
|
|
|
|
316
|
|
|
} |
|
317
|
|
|
|
|
318
|
|
|
/** |
|
319
|
|
|
* {@inheritdoc} |
|
320
|
|
|
*/ |
|
321
|
|
|
public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) { |
|
322
|
|
|
|
|
323
|
|
|
$js = true; |
|
324
|
|
|
if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) { |
|
325
|
|
|
$js = false; |
|
326
|
|
|
} |
|
327
|
|
|
$format = $this->format( $options, $js ); |
|
328
|
|
|
if ( $js ) { |
|
329
|
|
|
$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) ); |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
if ( ! empty( $value ) && ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array( |
|
333
|
|
|
$value, array( |
|
334
|
|
|
'0000-00-00', |
|
335
|
|
|
'0000-00-00 00:00:00', |
|
336
|
|
|
'00:00:00', |
|
337
|
|
|
), true |
|
338
|
|
|
) ) ) { |
|
339
|
|
|
$value = $this->convert_date( $value, static::$storage_format, $format ); |
|
340
|
|
View Code Duplication |
} elseif ( 1 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) ) { |
|
341
|
|
|
$value = static::$empty_value; |
|
342
|
|
|
} else { |
|
343
|
|
|
$value = date_i18n( static::$storage_format ); |
|
344
|
|
|
} |
|
345
|
|
|
|
|
346
|
|
|
return $value; |
|
347
|
|
|
} |
|
348
|
|
|
|
|
349
|
|
|
/** |
|
350
|
|
|
* {@inheritdoc} |
|
351
|
|
|
*/ |
|
352
|
|
|
public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) { |
|
353
|
|
|
|
|
354
|
|
|
$value = $this->display( $value, $name, $options, $pod, $id ); |
|
355
|
|
|
|
|
356
|
|
|
if ( 1 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) && ( empty( $value ) || in_array( |
|
357
|
|
|
$value, array( |
|
358
|
|
|
'0000-00-00', |
|
359
|
|
|
'0000-00-00 00:00:00', |
|
360
|
|
|
'00:00:00', |
|
361
|
|
|
), true |
|
362
|
|
|
) ) ) { |
|
363
|
|
|
$value = false; |
|
364
|
|
|
} |
|
365
|
|
|
|
|
366
|
|
|
return $value; |
|
367
|
|
|
} |
|
368
|
|
|
|
|
369
|
|
|
/** |
|
370
|
|
|
* Convert value to the correct format for display. |
|
371
|
|
|
* |
|
372
|
|
|
* @param string $value |
|
373
|
|
|
* @param array $options |
|
374
|
|
|
* @param bool $js Return formatted from jQuery UI format? (only for custom formats). |
|
375
|
|
|
* |
|
376
|
|
|
* @return string |
|
377
|
|
|
* @since 2.7 |
|
378
|
|
|
*/ |
|
379
|
|
|
public function format_value_display( $value, $options, $js = false ) { |
|
380
|
|
|
|
|
381
|
|
|
if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) { |
|
382
|
|
|
$js = false; |
|
383
|
|
|
} |
|
384
|
|
|
$format = $this->format( $options, $js ); |
|
385
|
|
|
if ( $js ) { |
|
386
|
|
|
$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) ); |
|
387
|
|
|
} |
|
388
|
|
|
|
|
389
|
|
|
if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) { |
|
390
|
|
|
// Try default storage format. |
|
391
|
|
|
$date = $this->createFromFormat( static::$storage_format, (string) $value ); |
|
392
|
|
|
// Try field format. |
|
393
|
|
|
$date_local = $this->createFromFormat( $format, (string) $value ); |
|
394
|
|
|
|
|
395
|
|
View Code Duplication |
if ( $date instanceof DateTime ) { |
|
396
|
|
|
$value = $date->format( $format ); |
|
397
|
|
|
} elseif ( $date_local instanceof DateTime ) { |
|
398
|
|
|
$value = $date_local->format( $format ); |
|
399
|
|
|
} else { |
|
400
|
|
|
$value = date_i18n( $format, strtotime( (string) $value ) ); |
|
401
|
|
|
} |
|
402
|
|
View Code Duplication |
} elseif ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) ) { |
|
403
|
|
|
$value = date_i18n( $format ); |
|
404
|
|
|
} else { |
|
405
|
|
|
$value = ''; |
|
406
|
|
|
} |
|
407
|
|
|
|
|
408
|
|
|
return $value; |
|
409
|
|
|
} |
|
410
|
|
|
|
|
411
|
|
|
/** |
|
412
|
|
|
* {@inheritdoc} |
|
413
|
|
|
*/ |
|
414
|
|
|
public function format( $options, $js = false ) { |
|
415
|
|
|
|
|
416
|
|
|
$format = $this->format_date( $options, $js ); |
|
417
|
|
|
|
|
418
|
|
|
$type = pods_v( static::$type . '_type', $options, 'format' ); |
|
419
|
|
|
|
|
420
|
|
|
if ( 'format' !== $type || 'c' !== pods_v( static::$type . '_format', $options, '' ) ) { |
|
421
|
|
|
$format .= ' ' . $this->format_time( $options, $js ); |
|
422
|
|
|
} |
|
423
|
|
|
|
|
424
|
|
|
return $format; |
|
425
|
|
|
} |
|
426
|
|
|
|
|
427
|
|
|
/** |
|
428
|
|
|
* Build date format string based on options |
|
429
|
|
|
* |
|
430
|
|
|
* @since 2.7 |
|
431
|
|
|
* |
|
432
|
|
|
* @param array $options |
|
433
|
|
|
* @param bool $js Return format for jQuery UI? |
|
434
|
|
|
* |
|
435
|
|
|
* @return string |
|
436
|
|
|
*/ |
|
437
|
|
|
public function format_date( $options, $js = false ) { |
|
438
|
|
|
|
|
439
|
|
|
switch ( (string) pods_v( static::$type . '_type', $options, 'format', true ) ) { |
|
440
|
|
|
case 'wp': |
|
441
|
|
|
$format = get_option( 'date_format' ); |
|
442
|
|
|
if ( $js ) { |
|
443
|
|
|
$format = $this->convert_format( $format, array( 'source' => 'php' ) ); |
|
444
|
|
|
} |
|
445
|
|
|
break; |
|
446
|
|
|
case 'custom': |
|
447
|
|
|
if ( ! $js ) { |
|
448
|
|
|
$format = pods_v( static::$type . '_format_custom', $options, '' ); |
|
449
|
|
|
} else { |
|
450
|
|
|
$format = pods_v( static::$type . '_format_custom_js', $options, '' ); |
|
451
|
|
|
if ( empty( $format ) ) { |
|
452
|
|
|
$format = pods_v( static::$type . '_format_custom', $options, '' ); |
|
453
|
|
|
$format = $this->convert_format( $format, array( 'source' => 'php' ) ); |
|
454
|
|
|
} |
|
455
|
|
|
} |
|
456
|
|
|
break; |
|
457
|
|
|
default: |
|
458
|
|
|
$date_format = $this->get_date_formats( $js ); |
|
459
|
|
|
$format = $date_format[ pods_v( static::$type . '_format', $options, 'ymd_dash', true ) ]; |
|
460
|
|
|
break; |
|
461
|
|
|
}//end switch |
|
462
|
|
|
|
|
463
|
|
|
return $format; |
|
464
|
|
|
} |
|
465
|
|
|
|
|
466
|
|
|
/** |
|
467
|
|
|
* Build time format string based on options |
|
468
|
|
|
* |
|
469
|
|
|
* @since 2.7 |
|
470
|
|
|
* |
|
471
|
|
|
* @param array $options |
|
472
|
|
|
* @param bool $js Return format for jQuery UI? |
|
473
|
|
|
* |
|
474
|
|
|
* @return string |
|
475
|
|
|
*/ |
|
476
|
|
View Code Duplication |
public function format_time( $options, $js = false ) { |
|
|
|
|
|
|
477
|
|
|
|
|
478
|
|
|
switch ( (string) pods_v( static::$type . '_time_type', $options, '12', true ) ) { |
|
479
|
|
|
case '12': |
|
480
|
|
|
$time_format = $this->get_time_formats( $js ); |
|
481
|
|
|
$format = $time_format[ pods_v( static::$type . '_time_format', $options, 'hh_mm', true ) ]; |
|
482
|
|
|
break; |
|
483
|
|
|
case '24': |
|
484
|
|
|
$time_format_24 = $this->get_time_formats_24( $js ); |
|
485
|
|
|
$format = $time_format_24[ pods_v( static::$type . '_time_format_24', $options, 'hh_mm', true ) ]; |
|
486
|
|
|
break; |
|
487
|
|
|
case 'custom': |
|
488
|
|
|
if ( ! $js ) { |
|
489
|
|
|
$format = pods_v( static::$type . '_time_format_custom', $options, '' ); |
|
490
|
|
|
} else { |
|
491
|
|
|
$format = pods_v( static::$type . '_time_format_custom_js', $options, '' ); |
|
492
|
|
|
if ( empty( $format ) ) { |
|
493
|
|
|
$format = pods_v( static::$type . '_time_format_custom', $options, '' ); |
|
494
|
|
|
$format = $this->convert_format( $format, array( 'source' => 'php' ) ); |
|
495
|
|
|
} |
|
496
|
|
|
} |
|
497
|
|
|
break; |
|
498
|
|
|
default: |
|
499
|
|
|
$format = get_option( 'time_format' ); |
|
500
|
|
|
if ( $js ) { |
|
501
|
|
|
$format = $this->convert_format( $format, array( 'source' => 'php' ) ); |
|
502
|
|
|
} |
|
503
|
|
|
break; |
|
504
|
|
|
}//end switch |
|
505
|
|
|
|
|
506
|
|
|
return $format; |
|
507
|
|
|
} |
|
508
|
|
|
|
|
509
|
|
|
/** |
|
510
|
|
|
* Get the date formats. |
|
511
|
|
|
* |
|
512
|
|
|
* @since 2.7 |
|
513
|
|
|
* |
|
514
|
|
|
* @param bool $js Return formats for jQuery UI? |
|
515
|
|
|
* |
|
516
|
|
|
* @return array |
|
517
|
|
|
*/ |
|
518
|
|
|
public function get_date_formats( $js = false ) { |
|
519
|
|
|
|
|
520
|
|
|
$date_format = array( |
|
521
|
|
|
'mdy' => 'm/d/Y', |
|
522
|
|
|
'mdy_dash' => 'm-d-Y', |
|
523
|
|
|
'mdy_dot' => 'm.d.Y', |
|
524
|
|
|
'dmy' => 'd/m/Y', |
|
525
|
|
|
'dmy_dash' => 'd-m-Y', |
|
526
|
|
|
'dmy_dot' => 'd.m.Y', |
|
527
|
|
|
'ymd_slash' => 'Y/m/d', |
|
528
|
|
|
'ymd_dash' => 'Y-m-d', |
|
529
|
|
|
'ymd_dot' => 'Y.m.d', |
|
530
|
|
|
'dMy' => 'd/M/Y', |
|
531
|
|
|
'dMy_dash' => 'd-M-Y', |
|
532
|
|
|
'fjy' => 'F j, Y', |
|
533
|
|
|
'fjsy' => 'F jS, Y', |
|
534
|
|
|
'y' => 'Y', |
|
535
|
|
|
); |
|
536
|
|
|
$filter = 'pods_form_ui_field_date_formats'; |
|
537
|
|
|
if ( $js ) { |
|
538
|
|
|
// @todo Method parameters? (Not supported by array_map) |
|
539
|
|
|
$date_format = array_map( array( $this, 'convert_format' ), $date_format ); |
|
540
|
|
|
$filter = 'pods_form_ui_field_date_js_formats'; |
|
541
|
|
|
} |
|
542
|
|
|
|
|
543
|
|
|
return apply_filters( $filter, $date_format ); |
|
544
|
|
|
} |
|
545
|
|
|
|
|
546
|
|
|
/** |
|
547
|
|
|
* Get the time formats. |
|
548
|
|
|
* |
|
549
|
|
|
* @since 2.7 |
|
550
|
|
|
* |
|
551
|
|
|
* @param bool $js Return formats for jQuery UI? |
|
552
|
|
|
* |
|
553
|
|
|
* @return array |
|
554
|
|
|
*/ |
|
555
|
|
|
public function get_time_formats( $js = false ) { |
|
556
|
|
|
|
|
557
|
|
|
$time_format = array( |
|
558
|
|
|
'h_mm_A' => 'g:i A', |
|
559
|
|
|
'h_mm_ss_A' => 'g:i:s A', |
|
560
|
|
|
'hh_mm_A' => 'h:i A', |
|
561
|
|
|
'hh_mm_ss_A' => 'h:i:s A', |
|
562
|
|
|
'h_mma' => 'g:ia', |
|
563
|
|
|
'hh_mma' => 'h:ia', |
|
564
|
|
|
'h_mm' => 'g:i', |
|
565
|
|
|
'h_mm_ss' => 'g:i:s', |
|
566
|
|
|
'hh_mm' => 'h:i', |
|
567
|
|
|
'hh_mm_ss' => 'h:i:s', |
|
568
|
|
|
); |
|
569
|
|
|
$filter = 'pods_form_ui_field_time_formats'; |
|
570
|
|
|
if ( $js ) { |
|
571
|
|
|
// @todo Method parameters? (Not supported by array_map) |
|
572
|
|
|
$time_format = array_map( array( $this, 'convert_format' ), $time_format ); |
|
573
|
|
|
$filter = 'pods_form_ui_field_time_js_formats'; |
|
574
|
|
|
} |
|
575
|
|
|
|
|
576
|
|
|
return apply_filters( $filter, $time_format ); |
|
577
|
|
|
} |
|
578
|
|
|
|
|
579
|
|
|
/** |
|
580
|
|
|
* Get the time formats. |
|
581
|
|
|
* |
|
582
|
|
|
* @since 2.7 |
|
583
|
|
|
* |
|
584
|
|
|
* @param bool $js Return formats for jQuery UI? |
|
585
|
|
|
* |
|
586
|
|
|
* @return array |
|
587
|
|
|
*/ |
|
588
|
|
|
public function get_time_formats_24( $js = false ) { |
|
589
|
|
|
|
|
590
|
|
|
$time_format_24 = array( |
|
591
|
|
|
'hh_mm' => 'H:i', |
|
592
|
|
|
'hh_mm_ss' => 'H:i:s', |
|
593
|
|
|
); |
|
594
|
|
|
$filter = 'pods_form_ui_field_time_formats_24'; |
|
595
|
|
|
if ( $js ) { |
|
596
|
|
|
// @todo Method parameters? (Not supported by array_map) |
|
597
|
|
|
$time_format_24 = array_map( array( $this, 'convert_format' ), $time_format_24 ); |
|
598
|
|
|
$filter = 'pods_form_ui_field_time_js_formats_24'; |
|
599
|
|
|
} |
|
600
|
|
|
|
|
601
|
|
|
return apply_filters( $filter, $time_format_24 ); |
|
602
|
|
|
} |
|
603
|
|
|
|
|
604
|
|
|
/** |
|
605
|
|
|
* @param string $format |
|
606
|
|
|
* @param string $date Defaults to time() if empty. |
|
607
|
|
|
* @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not |
|
608
|
|
|
* |
|
609
|
|
|
* @return DateTime|null|int|false |
|
610
|
|
|
*/ |
|
611
|
|
|
public function createFromFormat( $format, $date, $return_timestamp = false ) { |
|
612
|
|
|
|
|
613
|
|
|
$datetime = null; |
|
614
|
|
|
|
|
615
|
|
|
if ( method_exists( 'DateTime', 'createFromFormat' ) ) { |
|
616
|
|
|
$timezone = get_option( 'timezone_string' ); |
|
617
|
|
|
|
|
618
|
|
|
if ( empty( $timezone ) ) { |
|
619
|
|
|
$timezone = timezone_name_from_abbr( '', get_option( 'gmt_offset' ) * HOUR_IN_SECONDS, 0 ); |
|
620
|
|
|
} |
|
621
|
|
|
|
|
622
|
|
|
if ( ! empty( $timezone ) ) { |
|
623
|
|
|
$datetimezone = new DateTimeZone( $timezone ); |
|
624
|
|
|
|
|
625
|
|
|
$datetime = DateTime::createFromFormat( $format, (string) $date, $datetimezone ); |
|
|
|
|
|
|
626
|
|
|
|
|
627
|
|
|
if ( false === $datetime ) { |
|
628
|
|
|
$datetime = DateTime::createFromFormat( static::$storage_format, (string) $date, $datetimezone ); |
|
|
|
|
|
|
629
|
|
|
} |
|
630
|
|
|
|
|
631
|
|
|
if ( false !== $datetime && $return_timestamp ) { |
|
632
|
|
|
return $datetime; |
|
633
|
|
|
} |
|
634
|
|
|
} |
|
635
|
|
|
}//end if |
|
636
|
|
|
|
|
637
|
|
|
if ( in_array( $datetime, array( null, false ), true ) ) { |
|
638
|
|
|
if ( empty( $date ) ) { |
|
639
|
|
|
$timestamp = time(); |
|
640
|
|
|
} else { |
|
641
|
|
|
$timestamp = strtotime( (string) $date ); |
|
642
|
|
|
|
|
643
|
|
|
if ( $return_timestamp ) { |
|
644
|
|
|
return $timestamp; |
|
645
|
|
|
} |
|
646
|
|
|
} |
|
647
|
|
|
if ( $timestamp ) { |
|
648
|
|
|
$datetime = new DateTime( date_i18n( static::$storage_format, $timestamp ) ); |
|
649
|
|
|
} |
|
650
|
|
|
} |
|
651
|
|
|
|
|
652
|
|
|
return apply_filters( 'pods_form_ui_field_datetime_formatter', $datetime, $format, $date ); |
|
653
|
|
|
} |
|
654
|
|
|
|
|
655
|
|
|
/** |
|
656
|
|
|
* Convert a date from one format to another |
|
657
|
|
|
* |
|
658
|
|
|
* @param $value |
|
659
|
|
|
* @param $new_format |
|
660
|
|
|
* @param string $original_format |
|
661
|
|
|
* @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not |
|
662
|
|
|
* |
|
663
|
|
|
* @return string|int|boolean|DateTime |
|
664
|
|
|
*/ |
|
665
|
|
|
public function convert_date( $value, $new_format, $original_format = '', $return_timestamp = false ) { |
|
666
|
|
|
|
|
667
|
|
|
if ( empty( $original_format ) ) { |
|
668
|
|
|
$original_format = static::$storage_format; |
|
669
|
|
|
} |
|
670
|
|
|
|
|
671
|
|
|
$date = ''; |
|
672
|
|
|
|
|
673
|
|
|
if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) { |
|
674
|
|
|
$date = $this->createFromFormat( $original_format, (string) $value, $return_timestamp ); |
|
675
|
|
|
|
|
676
|
|
View Code Duplication |
if ( $date instanceof DateTime ) { |
|
677
|
|
|
$value = $date->format( $new_format ); |
|
678
|
|
|
} elseif ( false !== $date ) { |
|
679
|
|
|
$date = strtotime( (string) $value ); |
|
680
|
|
|
|
|
681
|
|
|
$value = date_i18n( $new_format, $date ); |
|
682
|
|
|
} |
|
683
|
|
|
} else { |
|
684
|
|
|
$value = date_i18n( $new_format ); |
|
685
|
|
|
} |
|
686
|
|
|
|
|
687
|
|
|
// Return timestamp conversion result instead |
|
688
|
|
|
if ( $return_timestamp ) { |
|
689
|
|
|
return $date; |
|
690
|
|
|
} |
|
691
|
|
|
|
|
692
|
|
|
return $value; |
|
693
|
|
|
} |
|
694
|
|
|
|
|
695
|
|
|
/** |
|
696
|
|
|
* Matches each symbol of PHP date format standard with jQuery equivalent codeword. |
|
697
|
|
|
* |
|
698
|
|
|
* @link http://stackoverflow.com/questions/16702398/convert-a-php-date-format-to-a-jqueryui-datepicker-date-format |
|
699
|
|
|
* @link https://api.jqueryui.com/datepicker/ |
|
700
|
|
|
* @link http://trentrichardson.com/examples/timepicker/ |
|
701
|
|
|
* |
|
702
|
|
|
* @since 2.7 |
|
703
|
|
|
* |
|
704
|
|
|
* @param string $source_format |
|
705
|
|
|
* @param array $args |
|
706
|
|
|
* |
|
707
|
|
|
* @return string |
|
708
|
|
|
*/ |
|
709
|
|
|
public function convert_format( $source_format, $args = array() ) { |
|
710
|
|
|
|
|
711
|
|
|
// @todo Improve source/target logic. |
|
712
|
|
|
$args = array_merge( |
|
713
|
|
|
array( |
|
714
|
|
|
'source' => 'php', |
|
715
|
|
|
// 'jquery_ui' for reverse. |
|
716
|
|
|
), $args |
|
717
|
|
|
); |
|
718
|
|
|
|
|
719
|
|
|
// Keep keys and values sorted by string length. |
|
720
|
|
|
$symbols = array( |
|
721
|
|
|
// Day |
|
722
|
|
|
'd' => 'dd', |
|
723
|
|
|
'l' => 'DD', |
|
724
|
|
|
'D' => 'D', |
|
725
|
|
|
'j' => 'd', |
|
726
|
|
|
'N' => '', |
|
727
|
|
|
'S' => '', |
|
728
|
|
|
'w' => '', |
|
729
|
|
|
'z' => 'o', |
|
730
|
|
|
// Week |
|
731
|
|
|
'W' => '', |
|
732
|
|
|
// Month |
|
733
|
|
|
'F' => 'MM', |
|
734
|
|
|
'm' => 'mm', |
|
735
|
|
|
'M' => 'M', |
|
736
|
|
|
'n' => 'm', |
|
737
|
|
|
't' => '', |
|
738
|
|
|
// Year |
|
739
|
|
|
'L' => '', |
|
740
|
|
|
'o' => '', |
|
741
|
|
|
'Y' => 'yy', |
|
742
|
|
|
'y' => 'y', |
|
743
|
|
|
// AM/PM |
|
744
|
|
|
'a' => 'tt', |
|
745
|
|
|
'A' => 'TT', |
|
746
|
|
|
// Swatch internet time (not supported) |
|
747
|
|
|
'B' => '', |
|
748
|
|
|
// Hour |
|
749
|
|
|
'h' => 'hh', |
|
750
|
|
|
'H' => 'HH', |
|
751
|
|
|
'g' => 'h', |
|
752
|
|
|
'G' => 'H', |
|
753
|
|
|
// Minute |
|
754
|
|
|
'i' => 'mm', |
|
755
|
|
|
// Second |
|
756
|
|
|
's' => 'ss', |
|
757
|
|
|
// Microsecond |
|
758
|
|
|
'u' => 'c', |
|
759
|
|
|
); |
|
760
|
|
|
if ( version_compare( PHP_VERSION, '7.0.0' ) >= 0 ) { |
|
761
|
|
|
// Millisecond |
|
762
|
|
|
$symbols['v'] = 'l'; |
|
763
|
|
|
} |
|
764
|
|
|
if ( 'jquery_ui' === $args['source'] ) { |
|
765
|
|
|
// Remove empty values. |
|
766
|
|
|
$symbols = array_filter( $symbols ); |
|
767
|
|
|
$symbols = array_flip( $symbols ); |
|
768
|
|
|
} |
|
769
|
|
|
$new_format = ''; |
|
770
|
|
|
$escaping = false; |
|
771
|
|
|
for ( $i = 0; $i < strlen( $source_format ); $i ++ ) { |
|
772
|
|
|
$char = $source_format[ $i ]; |
|
773
|
|
|
// PHP date format escaping character |
|
774
|
|
|
// @todo Do we want to support non-format characters? |
|
775
|
|
|
if ( $char === '\\' ) { |
|
776
|
|
|
$i ++; |
|
777
|
|
|
if ( $escaping ) { |
|
778
|
|
|
$new_format .= $source_format[ $i ]; |
|
779
|
|
|
} else { |
|
780
|
|
|
$new_format .= '\'' . $source_format[ $i ]; |
|
781
|
|
|
} |
|
782
|
|
|
$escaping = true; |
|
783
|
|
|
} else { |
|
784
|
|
|
if ( $escaping ) { |
|
785
|
|
|
$new_format .= "'"; |
|
786
|
|
|
$escaping = false; |
|
787
|
|
|
} |
|
788
|
|
|
// Support 2 characters. |
|
789
|
|
|
if ( isset( $source_format[ $i + 1 ] ) && isset( $symbols[ $char . $source_format[ $i + 1 ] ] ) ) { |
|
790
|
|
|
$new_format .= $symbols[ $char . $source_format[ $i + 1 ] ]; |
|
791
|
|
|
$i ++; |
|
792
|
|
|
} elseif ( isset( $symbols[ $char ] ) ) { |
|
793
|
|
|
$new_format .= $symbols[ $char ]; |
|
794
|
|
|
} else { |
|
795
|
|
|
$new_format .= $char; |
|
796
|
|
|
} |
|
797
|
|
|
}//end if |
|
798
|
|
|
}//end for |
|
799
|
|
|
|
|
800
|
|
|
return $new_format; |
|
801
|
|
|
} |
|
802
|
|
|
|
|
803
|
|
|
/** |
|
804
|
|
|
* Enqueue the i18n files for jquery date/timepicker |
|
805
|
|
|
* |
|
806
|
|
|
* @since 2.7 |
|
807
|
|
|
*/ |
|
808
|
|
|
public function enqueue_jquery_ui_i18n() { |
|
809
|
|
|
|
|
810
|
|
|
static $done = array(); |
|
811
|
|
|
|
|
812
|
|
|
$types = array(); |
|
813
|
|
|
switch ( static::$type ) { |
|
814
|
|
|
case 'time': |
|
815
|
|
|
$types[] = 'time'; |
|
816
|
|
|
break; |
|
817
|
|
|
case 'date': |
|
818
|
|
|
$types[] = 'date'; |
|
819
|
|
|
break; |
|
820
|
|
|
case 'datetime': |
|
821
|
|
|
$types[] = 'time'; |
|
822
|
|
|
$types[] = 'date'; |
|
823
|
|
|
break; |
|
824
|
|
|
} |
|
825
|
|
|
|
|
826
|
|
|
if ( in_array( 'date', $types, true ) && ! in_array( 'date', $done, true ) ) { |
|
827
|
|
|
|
|
828
|
|
|
if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) { |
|
829
|
|
|
wp_localize_jquery_ui_datepicker(); |
|
830
|
|
|
} |
|
831
|
|
|
|
|
832
|
|
|
$done[] = 'date'; |
|
833
|
|
|
} |
|
834
|
|
|
|
|
835
|
|
|
if ( in_array( 'time', $types, true ) && ! in_array( 'time', $done, true ) ) { |
|
836
|
|
|
|
|
837
|
|
|
$locale = str_replace( '_', '-', get_locale() ); |
|
838
|
|
|
|
|
839
|
|
|
// Local files. |
|
840
|
|
|
if ( ! file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) { |
|
841
|
|
|
// Fallback to the base language (non-region specific). |
|
842
|
|
|
$locale = substr( $locale, 0, strpos( $locale, '-' ) ); |
|
843
|
|
|
} |
|
844
|
|
|
|
|
845
|
|
|
if ( ! wp_script_is( 'jquery-ui-timepicker-i18n-' . $locale, 'registered' ) && file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) { |
|
846
|
|
|
wp_enqueue_script( 'jquery-ui-timepicker-i18n-' . $locale, PODS_URL . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js', array( 'jquery-ui-timepicker' ), '1.6.3' ); |
|
847
|
|
|
} |
|
848
|
|
|
|
|
849
|
|
|
$done[] = 'time'; |
|
850
|
|
|
} |
|
851
|
|
|
} |
|
852
|
|
|
} |
|
853
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.