[TASK] Timestamp support for DateTimeConverter
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Property / TypeConverter / DateTimeConverter.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Property\TypeConverter;
3
4 /* *
5 * This script belongs to the Extbase 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 as published by the *
9 * Free Software Foundation, either version 3 of the License, or (at your *
10 * option) any later version. *
11 * *
12 * This script is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with the script. *
19 * If not, see http://www.gnu.org/licenses/lgpl.html *
20 * *
21 * The TYPO3 project - inspiring people to share! *
22 * */
23 /**
24 * Converter which transforms from different input formats into DateTime objects.
25 *
26 * Source can be either a string or an array.
27 * The date string is expected to be formatted according to DEFAULT_DATE_FORMAT
28 * But the default date format can be overridden in the initialize*Action() method like this:
29 * $this->arguments['<argumentName>']
30 * ->getPropertyMappingConfiguration()
31 * ->forProperty('<propertyName>') // this line can be skipped in order to specify the format for all properties
32 * ->setTypeConverterOption('TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\DateTimeConverter', \TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter::CONFIGURATION_DATE_FORMAT, '<dateFormat>');
33 *
34 * If the source is of type array, it is possible to override the format in the source:
35 * array(
36 * 'date' => '<dateString>',
37 * 'dateFormat' => '<dateFormat>'
38 * );
39 *
40 * By using an array as source you can also override time and timezone of the created DateTime object:
41 * array(
42 * 'date' => '<dateString>',
43 * 'hour' => '<hour>', // integer
44 * 'minute' => '<minute>', // integer
45 * 'seconds' => '<seconds>', // integer
46 * 'timezone' => '<timezone>', // string, see http://www.php.net/manual/timezones.php
47 * );
48 *
49 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
50 * @api
51 */
52 class DateTimeConverter extends \TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter implements \TYPO3\CMS\Core\SingletonInterface {
53
54 /**
55 * @var string
56 */
57 const CONFIGURATION_DATE_FORMAT = 'dateFormat';
58
59 /**
60 * The default date format is "YYYY-MM-DDT##:##:##+##:##", for example "2005-08-15T15:52:01+00:00"
61 * according to the W3C standard
62 *
63 * @see http://www.w3.org/TR/NOTE-datetime.html
64 *
65 * @var string
66 */
67 const DEFAULT_DATE_FORMAT = \DateTime::W3C;
68
69 /**
70 * @var array<string>
71 */
72 protected $sourceTypes = array('string', 'integer','array');
73
74 /**
75 * @var string
76 */
77 protected $targetType = 'DateTime';
78
79 /**
80 * @var integer
81 */
82 protected $priority = 1;
83
84 /**
85 * If conversion is possible.
86 *
87 * @param string $source
88 * @param string $targetType
89 *
90 * @return boolean
91 */
92 public function canConvertFrom($source, $targetType) {
93 if (!is_callable(array($targetType, 'createFromFormat'))) {
94 return FALSE;
95 }
96 if (is_array($source)) {
97 return TRUE;
98 }
99 if (is_integer($source)) {
100 return TRUE;
101 }
102 return is_string($source);
103 }
104
105 /**
106 * Converts $source to a \DateTime using the configured dateFormat
107 *
108 * @param string|integer|array $source the string to be converted to a DateTime object
109 * @param string $targetType must be "DateTime"
110 * @param array $convertedChildProperties not used currently
111 * @param \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration
112 *
113 * @return \DateTime
114 * @throws \TYPO3\CMS\Extbase\Property\Exception\TypeConverterException
115 */
116 public function convertFrom($source, $targetType, array $convertedChildProperties = array(), \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = NULL) {
117 $dateFormat = $this->getDefaultDateFormat($configuration);
118 if (is_string($source)) {
119 $dateAsString = $source;
120 } elseif (is_integer($source)) {
121 $dateAsString = strval($source);
122 } else {
123 if (isset($source['date']) && is_string($source['date'])) {
124 $dateAsString = $source['date'];
125 } elseif (isset($source['date']) && is_integer($source['date'])) {
126 $dateAsString = strval($source['date']);
127 } elseif ($this->isDatePartKeysProvided($source)) {
128 if ($source['day'] < 1 || $source['month'] < 1 || $source['year'] < 1) {
129 return new \TYPO3\CMS\Extbase\Error\Error('Could not convert the given date parts into a DateTime object because one or more parts were 0.', 1333032779);
130 }
131 $dateAsString = sprintf('%d-%d-%d', $source['year'], $source['month'], $source['day']);
132 } else {
133 throw new \TYPO3\CMS\Extbase\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);
134 }
135 if (isset($source['dateFormat']) && strlen($source['dateFormat']) > 0) {
136 $dateFormat = $source['dateFormat'];
137 }
138 }
139 if ($dateAsString === '') {
140 return NULL;
141 }
142 if (ctype_digit($dateAsString) && (!is_array($source) || !isset($source['dateFormat'])) && $configuration === NULL) {
143 $dateFormat = 'U';
144 }
145 if (is_array($source) && isset($source['timezone']) && strlen($source['timezone']) !== 0) {
146 try {
147 $timezone = new \DateTimeZone($source['timezone']);
148 } catch (\Exception $e) {
149 throw new \TYPO3\CMS\Extbase\Property\Exception\TypeConverterException('The specified timezone "' . $source['timezone'] . '" is invalid.', 1308240974);
150 }
151 $date = $targetType::createFromFormat($dateFormat, $dateAsString, $timezone);
152 } else {
153 $date = $targetType::createFromFormat($dateFormat, $dateAsString);
154 }
155 if ($date === FALSE) {
156 return new \TYPO3\CMS\Extbase\Error\Error('The date "%s" was not recognized (for format "%s").', 1307719788, array(
157 $dateAsString,
158 $dateFormat
159 ));
160 }
161 if (is_array($source)) {
162 $this->overrideTimeIfSpecified($date, $source);
163 }
164 return $date;
165 }
166
167 /**
168 * Returns whether date information (day, month, year) are present as keys in $source.
169 *
170 * @param array $source
171 *
172 * @return boolean
173 */
174 protected function isDatePartKeysProvided(array $source) {
175 return isset($source['day']) && ctype_digit((string)$source['day'])
176 && isset($source['month']) && ctype_digit((string)$source['month'])
177 && isset($source['year']) && ctype_digit((string)$source['year']);
178 }
179
180 /**
181 * Determines the default date format to use for the conversion.
182 * If no format is specified in the mapping configuration DEFAULT_DATE_FORMAT is used.
183 *
184 * @param \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration
185 *
186 * @return string
187 * @throws \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException
188 */
189 protected function getDefaultDateFormat(\TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = NULL) {
190 if ($configuration === NULL) {
191 return self::DEFAULT_DATE_FORMAT;
192 }
193 $dateFormat = $configuration->getConfigurationValue('TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\DateTimeConverter', self::CONFIGURATION_DATE_FORMAT);
194 if ($dateFormat === NULL) {
195 return self::DEFAULT_DATE_FORMAT;
196 } elseif ($dateFormat !== NULL && !is_string($dateFormat)) {
197 throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException('CONFIGURATION_DATE_FORMAT must be of type string, "' . (is_object($dateFormat) ? get_class($dateFormat) : gettype($dateFormat)) . '" given', 1307719569);
198 }
199 return $dateFormat;
200 }
201
202 /**
203 * Overrides hour, minute & second of the given date with the values in the $source array
204 *
205 * @param \DateTime $date
206 * @param array $source
207 *
208 * @return void
209 */
210 protected function overrideTimeIfSpecified(\DateTime $date, array $source) {
211 if (!isset($source['hour']) && !isset($source['minute']) && !isset($source['second'])) {
212 return;
213 }
214
215 $hour = isset($source['hour']) ? (integer)$source['hour'] : 0;
216 $minute = isset($source['minute']) ? (integer)$source['minute'] : 0;
217 $second = isset($source['second']) ? (integer)$source['second'] : 0;
218 $date->setTime($hour, $minute, $second);
219 }
220 }
221
222 ?>