]>
Commit | Line | Data |
---|---|---|
4f5b44bd NL |
1 | <?php |
2 | ||
3 | /* | |
4 | * This file is part of the Symfony package. | |
5 | * | |
6 | * (c) Fabien Potencier <fabien@symfony.com> | |
7 | * | |
8 | * For the full copyright and license information, please view the LICENSE | |
9 | * file that was distributed with this source code. | |
10 | */ | |
11 | ||
12 | namespace Symfony\Component\Form\Extension\Core\DataTransformer; | |
13 | ||
14 | use Symfony\Component\Form\Exception\TransformationFailedException; | |
15 | use Symfony\Component\Form\Exception\UnexpectedTypeException; | |
16 | ||
17 | /** | |
18 | * Transforms between a normalized time and a localized time string/array. | |
19 | * | |
20 | * @author Bernhard Schussek <bschussek@gmail.com> | |
21 | * @author Florian Eckerstorfer <florian@eckerstorfer.org> | |
22 | */ | |
23 | class DateTimeToArrayTransformer extends BaseDateTimeTransformer | |
24 | { | |
25 | private $pad; | |
26 | ||
27 | private $fields; | |
28 | ||
29 | /** | |
30 | * Constructor. | |
31 | * | |
32 | * @param string $inputTimezone The input timezone | |
33 | * @param string $outputTimezone The output timezone | |
34 | * @param array $fields The date fields | |
35 | * @param Boolean $pad Whether to use padding | |
36 | * | |
37 | * @throws UnexpectedTypeException if a timezone is not a string | |
38 | */ | |
39 | public function __construct($inputTimezone = null, $outputTimezone = null, array $fields = null, $pad = false) | |
40 | { | |
41 | parent::__construct($inputTimezone, $outputTimezone); | |
42 | ||
43 | if (null === $fields) { | |
44 | $fields = array('year', 'month', 'day', 'hour', 'minute', 'second'); | |
45 | } | |
46 | ||
47 | $this->fields = $fields; | |
48 | $this->pad = (Boolean) $pad; | |
49 | } | |
50 | ||
51 | /** | |
52 | * Transforms a normalized date into a localized date. | |
53 | * | |
54 | * @param \DateTime $dateTime Normalized date. | |
55 | * | |
56 | * @return array Localized date. | |
57 | * | |
58 | * @throws TransformationFailedException If the given value is not an | |
59 | * instance of \DateTime or if the | |
60 | * output timezone is not supported. | |
61 | */ | |
62 | public function transform($dateTime) | |
63 | { | |
64 | if (null === $dateTime) { | |
65 | return array_intersect_key(array( | |
66 | 'year' => '', | |
67 | 'month' => '', | |
68 | 'day' => '', | |
69 | 'hour' => '', | |
70 | 'minute' => '', | |
71 | 'second' => '', | |
72 | ), array_flip($this->fields)); | |
73 | } | |
74 | ||
75 | if (!$dateTime instanceof \DateTime) { | |
76 | throw new TransformationFailedException('Expected a \DateTime.'); | |
77 | } | |
78 | ||
79 | $dateTime = clone $dateTime; | |
80 | if ($this->inputTimezone !== $this->outputTimezone) { | |
81 | try { | |
82 | $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); | |
83 | } catch (\Exception $e) { | |
84 | throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); | |
85 | } | |
86 | } | |
87 | ||
88 | $result = array_intersect_key(array( | |
89 | 'year' => $dateTime->format('Y'), | |
90 | 'month' => $dateTime->format('m'), | |
91 | 'day' => $dateTime->format('d'), | |
92 | 'hour' => $dateTime->format('H'), | |
93 | 'minute' => $dateTime->format('i'), | |
94 | 'second' => $dateTime->format('s'), | |
95 | ), array_flip($this->fields)); | |
96 | ||
97 | if (!$this->pad) { | |
98 | foreach ($result as &$entry) { | |
99 | // remove leading zeros | |
100 | $entry = (string) (int) $entry; | |
101 | } | |
102 | } | |
103 | ||
104 | return $result; | |
105 | } | |
106 | ||
107 | /** | |
108 | * Transforms a localized date into a normalized date. | |
109 | * | |
110 | * @param array $value Localized date | |
111 | * | |
112 | * @return \DateTime Normalized date | |
113 | * | |
114 | * @throws TransformationFailedException If the given value is not an array, | |
115 | * if the value could not be transformed | |
116 | * or if the input timezone is not | |
117 | * supported. | |
118 | */ | |
119 | public function reverseTransform($value) | |
120 | { | |
121 | if (null === $value) { | |
122 | return null; | |
123 | } | |
124 | ||
125 | if (!is_array($value)) { | |
126 | throw new TransformationFailedException('Expected an array.'); | |
127 | } | |
128 | ||
129 | if ('' === implode('', $value)) { | |
130 | return null; | |
131 | } | |
132 | ||
133 | $emptyFields = array(); | |
134 | ||
135 | foreach ($this->fields as $field) { | |
136 | if (!isset($value[$field])) { | |
137 | $emptyFields[] = $field; | |
138 | } | |
139 | } | |
140 | ||
141 | if (count($emptyFields) > 0) { | |
142 | throw new TransformationFailedException( | |
143 | sprintf('The fields "%s" should not be empty', implode('", "', $emptyFields) | |
144 | )); | |
145 | } | |
146 | ||
147 | if (isset($value['month']) && !ctype_digit($value['month']) && !is_int($value['month'])) { | |
148 | throw new TransformationFailedException('This month is invalid'); | |
149 | } | |
150 | ||
151 | if (isset($value['day']) && !ctype_digit($value['day']) && !is_int($value['day'])) { | |
152 | throw new TransformationFailedException('This day is invalid'); | |
153 | } | |
154 | ||
155 | if (isset($value['year']) && !ctype_digit($value['year']) && !is_int($value['year'])) { | |
156 | throw new TransformationFailedException('This year is invalid'); | |
157 | } | |
158 | ||
159 | if (!empty($value['month']) && !empty($value['day']) && !empty($value['year']) && false === checkdate($value['month'], $value['day'], $value['year'])) { | |
160 | throw new TransformationFailedException('This is an invalid date'); | |
161 | } | |
162 | ||
163 | try { | |
164 | $dateTime = new \DateTime(sprintf( | |
165 | '%s-%s-%s %s:%s:%s %s', | |
166 | empty($value['year']) ? '1970' : $value['year'], | |
167 | empty($value['month']) ? '1' : $value['month'], | |
168 | empty($value['day']) ? '1' : $value['day'], | |
169 | empty($value['hour']) ? '0' : $value['hour'], | |
170 | empty($value['minute']) ? '0' : $value['minute'], | |
171 | empty($value['second']) ? '0' : $value['second'], | |
172 | $this->outputTimezone | |
173 | )); | |
174 | ||
175 | if ($this->inputTimezone !== $this->outputTimezone) { | |
176 | $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); | |
177 | } | |
178 | } catch (\Exception $e) { | |
179 | throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); | |
180 | } | |
181 | ||
182 | return $dateTime; | |
183 | } | |
184 | } |