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