Feature #37294 ยป DateTimeConverter.php

Carsten Bleicker, 2012-05-19 11:52

 
1
<?php
2
namespace TYPO3\FLOW3\Property\TypeConverter;
3

    
4
/*                                                                        *
5
 * This script belongs to the FLOW3 framework.                            *
6
 *                                                                        *
7
 * It is free software; you can redistribute it and/or modify it under    *
8
 * the terms of the GNU Lesser General Public License, either version 3   *
9
 * of the License, or (at your option) any later version.                 *
10
 *                                                                        *
11
 * The TYPO3 project - inspiring people to share!                         *
12
 *                                                                        */
13

    
14
use TYPO3\FLOW3\Annotations as FLOW3;
15

    
16
/**
17
 * Converter which transforms from different input formats into DateTime objects.
18
 *
19
 * Source can be either a string or an array.
20
 * The date string is expected to be formatted according to DEFAULT_DATE_FORMAT
21
 * But the default date format can be overridden in the initialize*Action() method like this:
22
 * $this->arguments['<argumentName>']
23
 *   ->getPropertyMappingConfiguration()
24
 *   ->forProperty('<propertyName>') // this line can be skipped in order to specify the format for all properties
25
 *   ->setTypeConverterOption('TYPO3\FLOW3\Property\TypeConverter\DateTimeConverter', \TYPO3\FLOW3\Property\TypeConverter\DateTimeConverter::CONFIGURATION_DATE_FORMAT, '<dateFormat>');
26
 *
27
 * If the source is of type array, it is possible to override the format in the source:
28
 * array(
29
 *  'date' => '<dateString>',
30
 *  'dateFormat' => '<dateFormat>'
31
 * );
32
 *
33
 * By using an array as source you can also override time and timezone of the created DateTime object:
34
 * array(
35
 *  'date' => '<dateString>',
36
 *  'hour' => '<hour>', // integer
37
 *  'minute' => '<minute>', // integer
38
 *  'seconds' => '<seconds>', // integer
39
 *  'timezone' => '<timezone>', // string, see http://www.php.net/manual/timezones.php
40
 * );
41
 *
42
 * @api
43
 * @FLOW3\Scope("singleton")
44
 */
45
class DateTimeConverter extends \TYPO3\FLOW3\Property\TypeConverter\AbstractTypeConverter {
46

    
47
	/**
48
	 * @var string
49
	 */
50
	const CONFIGURATION_DATE_FORMAT = 'dateFormat';
51

    
52
	/**
53
	 * The default date format is "YYYY-MM-DDT##:##:##+##:##", for example "2005-08-15T15:52:01+00:00"
54
	 * according to the W3C standard @see http://www.w3.org/TR/NOTE-datetime.html
55
	 *
56
	 * @var string
57
	 */
58
	const DEFAULT_DATE_FORMAT = \DateTime::W3C;
59

    
60
	/**
61
	 * @var array<string>
62
	 */
63
	protected $sourceTypes = array('string', 'array');
64

    
65
	/**
66
	 * @var string
67
	 */
68
	protected $targetType = 'DateTime';
69

    
70
	/**
71
	 * @var integer
72
	 */
73
	protected $priority = 1;
74

    
75
	/**
76
	 * Empty strings can't be converted
77
	 *
78
	 * @param string $source
79
	 * @param string $targetType
80
	 * @return boolean
81
	 */
82
	public function canConvertFrom($source, $targetType) {
83
		
84
		if (!is_callable(array($targetType, 'createFromFormat'))) {
85
			return FALSE;
86
		}
87
		if (is_array($source)) {
88
			return TRUE;
89
		}
90
		return is_string($source);
91
	}
92

    
93
	/**
94
	 * Converts $source to a \DateTime using the configured dateFormat
95
	 *
96
	 * @param string $source the string to be converted to a \DateTime object
97
	 * @param string $targetType must be "DateTime"
98
	 * @param array $convertedChildProperties not used currently
99
	 * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration
100
	 * @return \DateTime
101
	 * @throws \TYPO3\FLOW3\Property\Exception\TypeConverterException
102
	 */
103
	public function convertFrom($source, $targetType, array $convertedChildProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) {
104
		
105
		$dateFormat = $this->getDefaultDateFormat($configuration);
106
		if (is_string($source)) {
107
			$dateAsString = $source;
108
		} else {
109
			if (!isset($source['date']) || !is_string($source['date'])) {
110
				throw new \TYPO3\FLOW3\Property\Exception\TypeConverterException('Could not convert the given source into a DateTime object because it was not an array with a valid date as a string', 1308003914);
111
			}
112
			$dateAsString = $source['date'];
113
			if (isset($source['dateFormat']) && strlen($source['dateFormat']) > 0) {
114
				$dateFormat = $source['dateFormat'];
115
			}
116
		}
117
		if ($dateAsString === '') {
118
			return NULL;
119
		}
120
		$date = $targetType::createFromFormat($dateFormat, $dateAsString);
121
		if ($date === FALSE) {
122
			return new \TYPO3\FLOW3\Validation\Error('The date "%s" was not recognized (for format "%s").', 1307719788, array($dateAsString, $dateFormat));
123
		}
124
		if (is_array($source)) {
125
			$this->overrideTimeIfSpecified($date, $source);
126
			$this->overrideTimezoneIfSpecified($date, $source);
127
		}
128
		
129
		return $date;
130
	}
131

    
132
	/**
133
	 * Determines the default date format to use for the conversion.
134
	 * If no format is specified in the mapping configuration DEFAULT_DATE_FORMAT is used.
135
	 *
136
	 * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration
137
	 * @return string
138
	 * @throws \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException
139
	 */
140
	protected function getDefaultDateFormat(\TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) {
141
		if ($configuration === NULL) {
142
			return self::DEFAULT_DATE_FORMAT;
143
		}
144
		$dateFormat = $configuration->getConfigurationValue('TYPO3\FLOW3\Property\TypeConverter\DateTimeConverter', self::CONFIGURATION_DATE_FORMAT);
145
		if ($dateFormat === NULL) {
146
			return self::DEFAULT_DATE_FORMAT;
147
		} elseif ($dateFormat !== NULL && !is_string($dateFormat)) {
148
			throw new \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException('CONFIGURATION_DATE_FORMAT must be of type string, "' . (is_object($dateFormat) ? get_class($dateFormat) : gettype($dateFormat)) . '" given', 1307719569);
149
		}
150
		return $dateFormat;
151
	}
152

    
153
	/**
154
	 * Overrides hour, minute & second of the given date with the values in the $source array
155
	 *
156
	 * @param \DateTime $date
157
	 * @param array $source
158
	 * @return void
159
	 */
160
	protected function overrideTimeIfSpecified(\DateTime $date, array $source) {
161
		if (!isset($source['hour']) && !isset($source['minute']) && !isset($source['second'])) {
162
			return;
163
		}
164
		$hour = isset($source['hour']) ? (integer)$source['hour'] : 0;
165
		$minute = isset($source['minute']) ? (integer)$source['minute'] : 0;
166
		$second = isset($source['second']) ? (integer)$source['second'] : 0;
167
		$date->setTime($hour, $minute, $second);
168
	}
169

    
170
	/**
171
	 * Overrides timezone of the given date with $source['timezone']
172
	 *
173
	 * @param \DateTime $date
174
	 * @param array $source
175
	 * @return void
176
	 * @throws \TYPO3\FLOW3\Property\Exception\TypeConverterException
177
	 */
178
	protected function overrideTimezoneIfSpecified(\DateTime $date, array $source) {
179
		if (!isset($source['timezone']) || strlen($source['timezone']) === 0) {
180
			return;
181
		}
182
		try {
183
			$timezone = new \DateTimeZone($source['timezone']);
184
		} catch (\Exception $e) {
185
			throw new \TYPO3\FLOW3\Property\Exception\TypeConverterException('The specified timezone "' . $source['timezone'] . '" is invalid', 1308240974);
186
		}
187
		$date->setTimezone($timezone);
188
	}
189
}
190
?>
    (1-1/1)