Completed
Pull Request — 2.x (#4370)
by
unknown
05:02
created

PodsField_DateTime::convert_date()   C

Complexity

Conditions 7
Paths 16

Size

Total Lines 28
Code Lines 16

Duplication

Lines 7
Ratio 25 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 16
nop 4
dl 7
loc 28
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package Pods\Fields
4
 */
5
class PodsField_DateTime extends PodsField {
6
7
	/**
8
	 * Field Type Group
9
	 *
10
	 * @var string
11
	 * @since 2.0
12
	 */
13
	public static $group = 'Date / Time';
14
15
	/**
16
	 * Field Type Identifier
17
	 *
18
	 * @var string
19
	 * @since 2.0
20
	 */
21
	public static $type = 'datetime';
22
23
	/**
24
	 * Field Type Label
25
	 *
26
	 * @var string
27
	 * @since 2.0
28
	 */
29
	public static $label = 'Date / Time';
30
31
	/**
32
	 * Field Type Preparation
33
	 *
34
	 * @var string
35
	 * @since 2.0
36
	 */
37
	public static $prepare = '%s';
38
39
	/**
40
	 * Storage format.
41
	 *
42
	 * @var string
43
	 * @since 2.7
44
	 */
45
	public static $storage_format = 'Y-m-d H:i:s';
46
47
	/**
48
	 * The default empty value (database)
49
	 *
50
	 * @var string
51
	 * @since 2.7
52
	 */
53
	public static $empty_value = '0000-00-00 00:00:00';
54
55
	/**
56
	 * Do things like register/enqueue scripts and stylesheets
57
	 *
58
	 * @since 2.0
59
	 */
60
	public function __construct () {
61
		static::$label = __( 'Date / Time', 'pods' );
62
	}
63
64
	/**
65
	 * Add options and set defaults to
66
	 *
67
	 * @return array
68
	 *
69
	 * @since 2.0
70
	 */
71
	public function options () {
72
		$options = array(
73
			static::$type . '_repeatable' => array(
74
				'label' => __( 'Repeatable Field', 'pods' ),
75
				'default' => 0,
76
				'type' => 'boolean',
77
				'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' ),
78
				'boolean_yes_label' => '',
79
				'dependency' => true,
80
				'developer_mode' => true
81
			),
82
			static::$type . '_type' => array(
83
				'label' => __( 'Date Format Type', 'pods' ),
84
				'default' => 'format', // Backwards compatibility
85
				'type' => 'pick',
86
				'help' => __( 'WordPress Default is the format used in Settings, General under "Date Format".', 'pods' ) . '<br>'
87
						  . __( 'Predefined Format will allow you to select from a list of commonly used date formats.', 'pods' ) . '<br>'
88
						  . __( 'Custom will allow you to enter your own using PHP Date/Time Strings.', 'pods' ),
89
				'data' => array(
90
					'wp' => __( 'WordPress default', 'pods' ) . ': '. date_i18n( get_option( 'date_format' ) ),
91
					'format' => __( 'Predefined format', 'pods' ),
92
					'custom' => __( 'Custom format', 'pods' ),
93
				),
94
				'dependency' => true
95
			),
96
			static::$type . '_format_custom' => array(
97
				'label' => __( 'Date format for display', 'pods' ),
98
				'depends-on' => array( static::$type . '_type' => 'custom' ),
99
				'default' => '',
100
				'type' => 'text',
101
				'help' => '<a href="http://php.net/manual/function.date.php" target="_blank">' . __( 'PHP date documentation', 'pods' ) . '</a>',
102
			),
103
			static::$type . '_format_custom_js' => array(
104
				'label' => __( 'Date format for input', 'pods' ),
105
				'depends-on' => array( static::$type . '_type' => 'custom' ),
106
				'default' => '',
107
				'type' => 'text',
108
				'help' => '<a href="https://api.jqueryui.com/datepicker/" target="_blank">' . __( 'jQuery UI datepicker documentation', 'pods' ) . '</a>'
109
						  . '<br>' . __( 'Leave empty to auto-generate from PHP format.', 'pods' ),
110
			),
111
			static::$type . '_format' => array(
112
				'label' => __( 'Date Format', 'pods' ),
113
				'depends-on' => array( static::$type . '_type' => 'format' ),
114
				'default' => 'mdy',
115
				'type' => 'pick',
116
				'data' => array(
117
					'mdy' => date_i18n( 'm/d/Y' ),
118
					'mdy_dash' => date_i18n( 'm-d-Y' ),
119
					'mdy_dot' => date_i18n( 'm.d.Y' ),
120
					'ymd_slash' => date_i18n( 'Y/m/d' ),
121
					'ymd_dash' => date_i18n( 'Y-m-d' ),
122
					'ymd_dot' => date_i18n( 'Y.m.d' ),
123
					'fjy' => date_i18n( 'F j, Y' ),
124
					'fjsy' => date_i18n( 'F jS, Y' ),
125
					'c' => date_i18n( 'c' ),
126
				),
127
				'dependency' => true
128
			),
129
			static::$type . '_time_type' => array(
130
				'label' => __( 'Time Format Type', 'pods' ),
131
				'excludes-on' => array( static::$type . '_format' => 'c' ),
132
				'default' => '12', // Backwards compatibility
133
				'type' => 'pick',
134
				'help' => __( 'WordPress Default is the format used in Settings, General under "Time Format".', 'pods' ) . '<br>'
135
						  . __( '12/24 hour will allow you to select from a list of commonly used time formats.', 'pods' ) . '<br>'
136
						  . __( 'Custom will allow you to enter your own using PHP Date/Time Strings.', 'pods' ),
137
				'data' => array(
138
					'wp' => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'time_format' ) ),
139
					'12' => __( '12 hour', 'pods' ),
140
					'24' => __( '24 hour', 'pods' ),
141
					'custom' => __( 'Custom', 'pods' ),
142
				),
143
				'dependency' => true
144
			),
145
			static::$type . '_time_format_custom' => array(
146
				'label' => __( 'Time format', 'pods' ),
147
				'depends-on' => array( static::$type . '_time_type' => 'custom' ),
148
				'excludes-on' => array( static::$type . '_format' => 'c' ),
149
				'default' => '',
150
				'type' => 'text',
151
				'help' => '<a href="http://php.net/manual/function.date.php" target="_blank">' . __( 'PHP date documentation', 'pods' ) . '</a>',
152
			),
153
			static::$type . '_time_format_custom_js' => array(
154
				'label' => __( 'Time format field input', 'pods' ),
155
				'depends-on' => array( static::$type . '_time_type' => 'custom' ),
156
				'excludes-on' => array( static::$type . '_format' => 'c' ),
157
				'default' => '',
158
				'type' => 'text',
159
				'help' => '<a href="http://trentrichardson.com/examples/timepicker/#tp-formatting" target="_blank">' . __( 'jQuery UI timepicker documentation', 'pods' ) . '</a>'
160
						  . '<br>' . __( 'Leave empty to auto-generate from PHP format.', 'pods' ),
161
			),
162
			static::$type . '_time_format' => array(
163
				'label' => __( 'Time Format', 'pods' ),
164
				'depends-on' => array( static::$type . '_time_type' => '12' ),
165
				'excludes-on' => array( static::$type . '_format' => 'c' ),
166
				'default' => 'h_mma',
167
				'type' => 'pick',
168
				'data' => array(
169
					'h_mm_A' => date_i18n( 'g:i A' ),
170
					'h_mm_ss_A' => date_i18n( 'g:i:s A' ),
171
					'hh_mm_A' => date_i18n( 'h:i A' ),
172
					'hh_mm_ss_A' => date_i18n( 'h:i:s A' ),
173
					'h_mma' => date_i18n( 'g:ia' ),
174
					'hh_mma' => date_i18n( 'h:ia' ),
175
					'h_mm' => date_i18n( 'g:i' ),
176
					'h_mm_ss' => date_i18n( 'g:i:s' ),
177
					'hh_mm' => date_i18n( 'h:i' ),
178
					'hh_mm_ss' => date_i18n( 'h:i:s' ),
179
				)
180
			),
181
			static::$type . '_time_format_24' => array(
182
				'label' => __( 'Time Format', 'pods' ),
183
				'depends-on' => array( static::$type . '_time_type' => '24' ),
184
				'excludes-on' => array( static::$type . '_format' => 'c' ),
185
				'default' => 'hh_mm',
186
				'type' => 'pick',
187
				'data' => array(
188
					'hh_mm' => date_i18n( 'H:i' ),
189
					'hh_mm_ss' => date_i18n( 'H:i:s' )
190
				)
191
			),
192
			static::$type . '_allow_empty' => array(
193
				'label' => __( 'Allow empty value?', 'pods' ),
194
				'default' => 1,
195
				'type' => 'boolean'
196
			),
197
			static::$type . '_html5' => array(
198
				'label' => __( 'Enable HTML5 Input Field?', 'pods' ),
199
				'default' => apply_filters( 'pods_form_ui_field_html5', 0, static::$type ),
200
				'type' => 'boolean'
201
			)
202
		);
203
204
		// Check if PHP DateTime::createFromFormat exists for additional supported formats
205 View Code Duplication
		if ( method_exists( 'DateTime', 'createFromFormat' ) || apply_filters( 'pods_form_ui_field_datetime_custom_formatter', false ) ) {
206
			$options[ static::$type . '_format' ][ 'data' ] = array_merge(
207
				$options[ static::$type . '_format' ][ 'data' ],
208
				array(
209
					'dmy' => date_i18n( 'd/m/Y' ),
210
					'dmy_dash' => date_i18n( 'd-m-Y' ),
211
					'dmy_dot' => date_i18n( 'd.m.Y' ),
212
					'dMy' => date_i18n( 'd/M/Y' ),
213
					'dMy_dash' => date_i18n( 'd-M-Y' )
214
				)
215
			);
216
		}
217
218
		$options[ static::$type . '_format' ][ 'data' ] = apply_filters( 'pods_form_ui_field_date_format_options', $options[ static::$type . '_format' ][ 'data' ] );
219
		$options[ static::$type . '_format' ][ 'default' ] = apply_filters( 'pods_form_ui_field_date_format_default', $options[ static::$type . '_format' ][ 'default' ] );
220
221
		$options[ static::$type . '_time_type' ][ 'default' ] = apply_filters( 'pods_form_ui_field_time_format_type_default', $options[ static::$type . '_time_type' ][ 'default' ] );
222
		$options[ static::$type . '_time_format' ][ 'data' ] = apply_filters( 'pods_form_ui_field_time_format_options', $options[ static::$type . '_time_format' ][ 'data' ] );
223
		$options[ static::$type . '_time_format' ][ 'default' ] = apply_filters( 'pods_form_ui_field_time_format_default', $options[ static::$type . '_time_format' ][ 'default' ] );
224
		$options[ static::$type . '_time_format_24' ][ 'data' ] = apply_filters( 'pods_form_ui_field_time_format_24_options', $options[ static::$type . '_time_format_24' ][ 'data' ] );
225
		$options[ static::$type . '_time_format_24' ][ 'default' ] = apply_filters( 'pods_form_ui_field_time_format_24_default', $options[ static::$type . '_time_format_24' ][ 'default' ] );
226
227
		return $options;
228
	}
229
230
	/**
231
	 * Define the current field's schema for DB table storage
232
	 *
233
	 * @param array $options
234
	 *
235
	 * @return string
236
	 * @since 2.0
237
	 */
238
	public function schema ( $options = null ) {
239
		$schema = 'DATETIME NOT NULL default "0000-00-00 00:00:00"';
240
241
		return $schema;
242
	}
243
244
	/**
245
	 * {@inheritdoc}
246
	 */
247
	public function is_empty( $value = null ) {
248
249
		$is_empty = false;
250
251
		$value = trim( $value );
252
253
		if ( empty( $value ) || in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ) ) ) {
254
			$is_empty = true;
255
		}
256
257
		return $is_empty;
258
259
	}
260
261
	/**
262
	 * Change the way the value of the field is displayed with Pods::get
263
	 *
264
	 * @param mixed $value
265
	 * @param string $name
266
	 * @param array $options
267
	 * @param array $pod
268
	 * @param int $id
269
	 *
270
	 * @return mixed|null|string
271
	 * @since 2.0
272
	 */
273
	public function display ( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
274
275
		$value = $this->format_value_display( $value, $options, false );
276
277
		return $value;
278
	}
279
280
	/**
281
	 * Customize output of the form field
282
	 *
283
	 * @param string $name
284
	 * @param mixed $value
285
	 * @param array $options
286
	 * @param array $pod
287
	 * @param int $id
288
	 *
289
	 * @since 2.0
290
	 */
291
	public function input ( $name, $value = null, $options = null, $pod = null, $id = null ) {
292
		$options = (array) $options;
293
		$form_field_type = PodsForm::$field_type;
0 ignored issues
show
Bug introduced by
The property field_type cannot be accessed from this context as it is declared private in class PodsForm.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
294
295
		if ( is_array( $value ) )
296
			$value = implode( ' ', $value );
297
298
		// Format Value
299
		$value = $this->format_value_display( $value, $options, true );
300
301
		$field_type = static::$type;
302
303
		if ( isset( $options[ 'name' ] ) && false === PodsForm::permission( static::$type, $options[ 'name' ], $options, null, $pod, $id ) ) {
304
			if ( pods_v( 'read_only', $options, false ) ) {
305
				$options[ 'readonly' ] = true;
306
307
				$field_type = 'text';
308
			}
309
			else
310
				return;
311
		}
312
		elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
313
			$options[ 'readonly' ] = true;
314
315
			$field_type = 'text';
316
		}
317
318
		pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
319
	}
320
321
	/**
322
	 * {@inheritdoc}
323
	 */
324
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
325
326
		if ( ! empty( $value ) && ( 0 == pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ) ) ) ) {
327
			$js = true;
328
329
			if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
330
				$js = false;
331
			}
332
333
			$format = $this->format( $options, $js );
334
335
			if ( $js ) {
336
				$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
337
			}
338
339
			$check = $this->convert_date( $value, static::$storage_format, $format, true );
340
341
			if ( false === $check ) {
342
				$label = pods_var( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) );
343
344
				return sprintf( esc_html__( '%1$s was not provided in a recognizable format: "%2$s"', 'pods' ), $label, $value );
345
			}
346
		}
347
348
		return true;
349
350
	}
351
352
	/**
353
	 * Change the value or perform actions after validation but before saving to the DB
354
	 *
355
	 * @param mixed $value
356
	 * @param int $id
357
	 * @param string $name
358
	 * @param array $options
359
	 * @param array $fields
360
	 * @param array $pod
361
	 * @param object $params
362
	 *
363
	 * @return mixed|string
364
	 * @since 2.0
365
	 */
366
	public function pre_save ( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
367
		$js = true;
368
		if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
369
			$js = false;
370
		}
371
		$format = $this->format( $options, $js );
372
		if ( $js ) {
373
			$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
374
		}
375
376
		if ( ! empty( $value ) && ( 0 == pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ) ) ) )
377
			$value = $this->convert_date( $value, static::$storage_format, $format );
378
		elseif ( 1 == pods_v( static::$type . '_allow_empty', $options, 1 ) )
379
			$value = static::$empty_value;
380
		else
381
			$value = date_i18n( static::$storage_format );
382
383
		return $value;
384
	}
385
386
	/**
387
	 * Customize the Pods UI manage table column output
388
	 *
389
	 * @param int $id
390
	 * @param mixed $value
391
	 * @param string $name
392
	 * @param array $options
393
	 * @param array $fields
394
	 * @param array $pod
395
	 *
396
	 * @return mixed|null|string
397
	 * @since 2.0
398
	 */
399
	public function ui ( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
400
		$value = $this->display( $value, $name, $options, $pod, $id );
401
402
		if ( 1 == pods_v( static::$type . '_allow_empty', $options, 1 ) && ( empty( $value ) || in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ) ) ) )
403
			$value = false;
404
405
		return $value;
406
	}
407
408
	/**
409
	 * Convert value to the correct format for display.
410
	 *
411
	 * @param string $value
412
	 * @param array  $options
413
	 * @param bool   $js       Return formatted from jQuery UI format? (only for custom formats).
414
	 * @return string
415
	 * @since 2.7
416
	 */
417
	public function format_value_display( $value, $options, $js = false ) {
418
		if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
419
			$js = false;
420
		}
421
		$format = $this->format( $options, $js );
422
		if ( $js ) {
423
			$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
424
		}
425
426
		if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ) ) ) {
427
			// Try default storage format.
428
			$date = $this->createFromFormat( static::$storage_format, (string) $value );
429
			// Try field format.
430
			$date_local = $this->createFromFormat( $format, (string) $value );
431
432 View Code Duplication
			if ( $date instanceof DateTime )
433
				$value = $date->format( $format );
434
			elseif ( $date_local instanceof DateTime )
435
				$value = $date_local->format( $format );
436
			else
437
				$value = date_i18n( $format, strtotime( (string) $value ) );
438
		}
439
		elseif ( 0 == pods_v( static::$type . '_allow_empty', $options, 1 ) )
440
			$value = date_i18n( $format );
441
		else
442
			$value = '';
443
444
		return $value;
445
	}
446
447
	/**
448
	 * Build date/time format string based on options
449
	 *
450
	 * @param array $options
451
	 * @param bool  $js       Return format for jQuery UI?
452
	 *
453
	 * @return string
454
	 * @since 2.0
455
	 */
456
	public function format ( $options, $js = false ) {
457
458
		$format = $this->format_date( $options, $js );
459
460
		$type = pods_v( static::$type . '_type', $options, 'format' );
461
462
		if ( 'format' !== $type || 'c' !== pods_v( static::$type . '_format', $options, '' ) ) {
463
			$format .= ' ' . $this->format_time( $options, $js );
464
		}
465
466
		return $format;
467
	}
468
469
	/**
470
	 * Build date format string based on options
471
	 *
472
	 * @since  2.7
473
	 *
474
	 * @param  array $options
475
	 * @param  bool  $js       Return format for jQuery UI?
476
	 * @return string
477
	 */
478
	public function format_date( $options, $js = false ) {
479
480
		switch ( (string) pods_v( static::$type . '_type', $options, 'format', true ) ) {
481
			case 'wp':
482
				$format = get_option( 'date_format' );
483
				if ( $js ) {
484
					$format = $this->convert_format( $format, array( 'source' => 'php' ) );
485
				}
486
			break;
487
			case 'custom':
488
				if ( ! $js ) {
489
					$format = pods_v( static::$type . '_format_custom', $options, '' );
490
				} else {
491
					$format = pods_v( static::$type . '_format_custom_js', $options, '' );
492
					if ( empty( $format ) ) {
493
						$format = pods_v( static::$type . '_format_custom', $options, '' );
494
						$format = $this->convert_format( $format, array( 'source' => 'php' ) );
495
					}
496
				}
497
			break;
498
			default:
499
				$date_format = $this->get_date_formats( $js );
500
				$format = $date_format[ pods_v( static::$type . '_format', $options, 'ymd_dash', true ) ];
501
			break;
502
		}
503
504
		return $format;
505
	}
506
507
	/**
508
	 * Build time format string based on options
509
	 *
510
	 * @since  2.7
511
	 *
512
	 * @param  array $options
513
	 * @param  bool  $js       Return format for jQuery UI?
514
	 * @return string
515
	 */
516 View Code Duplication
	public function format_time( $options, $js = false ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
517
518
		switch ( (string) pods_v( static::$type . '_time_type', $options, '12', true ) ) {
519
			case '12':
520
				$time_format = $this->get_time_formats( $js );
521
				$format = $time_format[ pods_v( static::$type . '_time_format', $options, 'hh_mm', true ) ];
522
			break;
523
			case '24':
524
				$time_format_24 = $this->get_time_formats_24( $js );
525
				$format = $time_format_24[ pods_v( static::$type . '_time_format_24', $options, 'hh_mm', true ) ];
526
			break;
527
			case 'custom':
528
				if ( ! $js ) {
529
					$format = pods_v( static::$type . '_time_format_custom', $options, '' );
530
				} else {
531
					$format = pods_v( static::$type . '_time_format_custom_js', $options, '' );
532
					if ( empty( $format ) ) {
533
						$format = pods_v( static::$type . '_time_format_custom', $options, '' );
534
						$format = $this->convert_format( $format, array( 'source' => 'php' ) );
535
					}
536
				}
537
			break;
538
			default:
539
				$format = get_option( 'time_format' );
540
				if ( $js ) {
541
					$format = $this->convert_format( $format, array( 'source' => 'php' ) );
542
				}
543
			break;
544
		}
545
546
		return $format;
547
	}
548
549
	/**
550
	 * Get the date formats.
551
	 *
552
	 * @since  2.7
553
	 *
554
	 * @param  bool  $js       Return formats for jQuery UI?
555
	 * @return array
556
	 */
557
	public function get_date_formats( $js = false ) {
558
		$date_format = array(
559
			'mdy'       => 'm/d/Y',
560
			'mdy_dash'  => 'm-d-Y',
561
			'mdy_dot'   => 'm.d.Y',
562
			'dmy'       => 'd/m/Y',
563
			'dmy_dash'  => 'd-m-Y',
564
			'dmy_dot'   => 'd.m.Y',
565
			'ymd_slash' => 'Y/m/d',
566
			'ymd_dash'  => 'Y-m-d',
567
			'ymd_dot'   => 'Y.m.d',
568
			'dMy'       => 'd/M/Y',
569
			'dMy_dash'  => 'd-M-Y',
570
			'fjy'       => 'F j, Y',
571
			'fjsy'      => 'F jS, Y',
572
			'y'         => 'Y',
573
		);
574
		$filter = 'pods_form_ui_field_date_formats';
575
		if ( $js ) {
576
			// @todo Method parameters? (Not supported by array_map)
577
			$date_format = array_map( array( $this, 'convert_format' ), $date_format );
578
			$filter = 'pods_form_ui_field_date_js_formats';
579
		}
580
		return apply_filters( $filter, $date_format );
581
	}
582
583
	/**
584
	 * Get the time formats.
585
	 *
586
	 * @since  2.7
587
	 *
588
	 * @param  bool  $js       Return formats for jQuery UI?
589
	 * @return array
590
	 */
591
	public function get_time_formats( $js = false ) {
592
		$time_format = array(
593
			'h_mm_A'     => 'g:i A',
594
			'h_mm_ss_A'  => 'g:i:s A',
595
			'hh_mm_A'    => 'h:i A',
596
			'hh_mm_ss_A' => 'h:i:s A',
597
			'h_mma'      => 'g:ia',
598
			'hh_mma'     => 'h:ia',
599
			'h_mm'       => 'g:i',
600
			'h_mm_ss'    => 'g:i:s',
601
			'hh_mm'      => 'h:i',
602
			'hh_mm_ss'   => 'h:i:s',
603
		);
604
		$filter = 'pods_form_ui_field_time_formats';
605
		if ( $js ) {
606
			// @todo Method parameters? (Not supported by array_map)
607
			$time_format = array_map( array( $this, 'convert_format' ), $time_format );
608
			$filter = 'pods_form_ui_field_time_js_formats';
609
		}
610
		return apply_filters( $filter, $time_format );
611
	}
612
613
	/**
614
	 * Get the time formats.
615
	 *
616
	 * @since  2.7
617
	 *
618
	 * @param  bool  $js       Return formats for jQuery UI?
619
	 * @return array
620
	 */
621
	public function get_time_formats_24( $js = false ) {
622
		$time_format_24 = array(
623
			'hh_mm'    => 'H:i',
624
			'hh_mm_ss' => 'H:i:s'
625
		);
626
		$filter = 'pods_form_ui_field_time_formats_24';
627
		if ( $js ) {
628
			// @todo Method parameters? (Not supported by array_map)
629
			$time_format_24 = array_map( array( $this, 'convert_format' ), $time_format_24 );
630
			$filter = 'pods_form_ui_field_time_js_formats_24';
631
		}
632
		return apply_filters( $filter, $time_format_24 );
633
	}
634
635
	/**
636
	 * @param string $format
637
	 * @param string $date Defaults to time() if empty.
638
	 * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not
639
	 *
640
	 * @return DateTime|null|int|false
641
	 */
642
	public function createFromFormat ( $format, $date, $return_timestamp = false ) {
643
		$datetime = null;
644
645
		if ( method_exists( 'DateTime', 'createFromFormat' ) ) {
646
			$timezone = get_option( 'timezone_string' );
647
648
			if ( empty( $timezone ) )
649
				$timezone = timezone_name_from_abbr( '', get_option( 'gmt_offset' ) * HOUR_IN_SECONDS, 0 );
650
651
			if ( !empty( $timezone ) ) {
652
				$datetimezone = new DateTimeZone( $timezone );
653
654
				$datetime = DateTime::createFromFormat( $format, (string) $date, $datetimezone );
0 ignored issues
show
Bug introduced by
The method createFromFormat() does not exist on DateTime. Did you maybe mean format()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
655
656
				if ( false === $datetime ) {
657
					$datetime = DateTime::createFromFormat( static::$storage_format, (string) $date, $datetimezone );
0 ignored issues
show
Bug introduced by
The method createFromFormat() does not exist on DateTime. Did you maybe mean format()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
658
				}
659
660
				if ( false !== $datetime && $return_timestamp ) {
661
					return $datetime;
662
				}
663
			}
664
		}
665
666
		if ( in_array( $datetime, array( null, false ), true ) ) {
667
			if ( empty( $date ) ) {
668
				$timestamp = time();
669
			} else {
670
				$timestamp = strtotime( (string) $date );
671
672
				if ( $return_timestamp ) {
673
					return $timestamp;
674
				}
675
			}
676
			if ( $timestamp ) {
677
				$datetime = new DateTime( date_i18n( static::$storage_format, $timestamp ) );
678
			}
679
		}
680
681
		return apply_filters( 'pods_form_ui_field_datetime_formatter', $datetime, $format, $date );
682
	}
683
684
	/**
685
	 * Convert a date from one format to another
686
	 *
687
	 * @param $value
688
	 * @param $new_format
689
	 * @param string $original_format
690
	 * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not
691
	 *
692
	 * @return string|int|boolean|DateTime
693
	 */
694
	public function convert_date ( $value, $new_format, $original_format = '', $return_timestamp = false ) {
695
		if ( empty( $original_format ) ) {
696
			$original_format = static::$storage_format;
697
		}
698
699
		$date = '';
700
701
		if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ) ) ) {
702
			$date = $this->createFromFormat( $original_format, (string) $value, $return_timestamp );
703
704 View Code Duplication
			if ( $date instanceof DateTime ) {
705
				$value = $date->format( $new_format );
706
			} elseif ( false !== $date ) {
707
				$date = strtotime( (string) $value );
708
709
				$value = date_i18n( $new_format, $date );
710
			}
711
		} else {
712
			$value = date_i18n( $new_format );
713
		}
714
715
		// Return timestamp conversion result instead
716
		if ( $return_timestamp ) {
717
			return $date;
718
		}
719
720
		return $value;
721
	}
722
723
	/**
724
	 * Matches each symbol of PHP date format standard with jQuery equivalent codeword.
725
	 *
726
	 * @link http://stackoverflow.com/questions/16702398/convert-a-php-date-format-to-a-jqueryui-datepicker-date-format
727
	 * @link https://api.jqueryui.com/datepicker/
728
	 * @link http://trentrichardson.com/examples/timepicker/
729
	 *
730
	 * @since  2.7
731
	 *
732
	 * @param  string  $source_format
733
	 * @param  array   $args
734
	 * @return string
735
	 */
736
	public function convert_format( $source_format, $args = array() ) {
737
		// @todo Improve source/target logic.
738
		$args = array_merge( array(
739
			'source' => 'php', // 'jquery_ui' for reverse.
740
		), $args );
741
742
		// Keep keys and values sorted by string length.
743
		$symbols = array(
744
			// Day
745
			'd' => 'dd',
746
			'l' => 'DD',
747
			'D' => 'D',
748
			'j' => 'd',
749
			'N' => '',
750
			'S' => '',
751
			'w' => '',
752
			'z' => 'o',
753
			// Week
754
			'W' => '',
755
			// Month
756
			'F' => 'MM',
757
			'm' => 'mm',
758
			'M' => 'M',
759
			'n' => 'm',
760
			't' => '',
761
			// Year
762
			'L' => '',
763
			'o' => '',
764
			'Y' => 'yy',
765
			'y' => 'y',
766
			// AM/PM
767
			'a' => 'tt',
768
			'A' => 'TT',
769
			// Swatch internet time (not supported)
770
			'B' => '',
771
			// Hour
772
			'h' => 'hh',
773
			'H' => 'HH',
774
			'g' => 'h',
775
			'G' => 'H',
776
			// Minute
777
			'i' => 'mm',
778
			// Second
779
			's' => 'ss',
780
			// Microsecond
781
			'u' => 'c',
782
		);
783
		if ( version_compare( PHP_VERSION, '7.0.0' ) >= 0 ) {
784
			// Millisecond
785
			$symbols['v'] = 'l';
786
		}
787
		if ( 'jquery_ui' === $args[ 'source' ] ) {
788
			// Remove empty values.
789
			$symbols = array_filter( $symbols );
790
			$symbols = array_flip( $symbols );
791
		}
792
		$new_format = "";
793
		$escaping = false;
794
		for( $i = 0; $i < strlen( $source_format ); $i++ ) {
795
			$char = $source_format[ $i ];
796
			// PHP date format escaping character
797
			// @todo Do we want to support non-format characters?
798
			if( $char === '\\' ) {
799
				$i++;
800
				if( $escaping ) {
801
					$new_format .= $source_format[ $i ];
802
				}
803
				else {
804
					$new_format .= '\'' . $source_format[ $i ];
805
				}
806
				$escaping = true;
807
			} else {
808
				if( $escaping ) {
809
					$new_format .= "'"; $escaping = false;
810
				}
811
				// Support 2 characters.
812
				if ( isset( $source_format[ $i + 1 ] ) && isset( $symbols[ $char . $source_format[ $i + 1 ] ] ) ) {
813
					$new_format .= $symbols[ $char . $source_format[ $i + 1 ] ];
814
					$i++;
815
				}
816
				elseif ( isset ( $symbols[ $char ] ) ) {
817
					$new_format .= $symbols[ $char ];
818
				}
819
				else {
820
					$new_format .= $char;
821
				}
822
			}
823
		}
824
		return $new_format;
825
	}
826
827
	/**
828
	 * Enqueue the i18n files for jquery date/timepicker
829
	 *
830
	 * @since  2.7
831
	 */
832
	public function enqueue_jquery_ui_i18n() {
833
		static $done = array();
834
835
		$types = array();
836
		switch ( static::$type ) {
837
			case 'time':
838
				$types[] = 'time';
839
			break;
840
			case 'date':
841
				$types[] = 'date';
842
			break;
843
			case 'datetime':
844
				$types[] = 'time';
845
				$types[] = 'date';
846
			break;
847
		}
848
849
		if ( in_array( 'date', $types, true ) && ! in_array( 'date', $done, true ) ) {
850
851
			if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) {
852
				wp_localize_jquery_ui_datepicker();
853
			}
854
855
			$done[] = 'date';
856
		}
857
858
		if ( in_array( 'time', $types, true ) && ! in_array( 'time', $done, true ) ) {
859
860
			$locale = str_replace( '_', '-', get_locale() );
861
862
			// Local files.
863
			if ( ! file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) {
864
				// Fallback to the base language (non-region specific).
865
				$locale = substr( $locale, 0, strpos( $locale, '-' ) );
866
			}
867
868
			if ( ! wp_script_is( 'jquery-ui-timepicker-i18n-' . $locale, 'registered' ) &&
869
			     file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' )
870
			) {
871
				wp_enqueue_script(
872
					'jquery-ui-timepicker-i18n-' . $locale,
873
					PODS_URL . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js',
874
					array( 'jquery-ui-timepicker' ),
875
					'1.6.3'
876
				);
877
			}
878
879
			$done[] = 'time';
880
		}
881
	}
882
}
883