DateTimeConverter.php

Carsten Bleicker, 2012-05-19 11:52

Download (6.9 kB)

 
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
?>