Completed
Pull Request — master (#743)
by Asmir
07:41
created

DateHandler::serializeDateTimeInterface()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 7
cts 7
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 3
nop 4
crap 4
1
<?php
2
3
/*
4
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace JMS\Serializer\Handler;
20
21
use JMS\Serializer\Exception\RuntimeException;
22
use JMS\Serializer\GraphNavigatorInterface;
23
use JMS\Serializer\JsonDeserializationVisitor;
24
use JMS\Serializer\SerializationContext;
25
use JMS\Serializer\SerializationVisitorInterface;
26
use JMS\Serializer\XmlDeserializationVisitor;
27
use JMS\Serializer\XmlSerializationVisitor;
28
use JMS\Serializer\YamlDeserializationVisitor;
29
30
final class DateHandler implements SubscribingHandlerInterface
31
{
32
    private $defaultFormat;
33
    private $defaultTimezone;
34
    private $xmlCData;
35
36 381
    public static function getSubscribingMethods()
37
    {
38 381
        $methods = array();
39 381
        $deserializationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval');
40 381
        $serialisationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval');
41
42 381
        foreach (array('json', 'xml', 'yml') as $format) {
43
44 381
            foreach ($deserializationTypes as $type) {
45 381
                $methods[] = [
46 381
                    'type' => $type,
47 381
                    'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
48 381
                    'format' => $format,
49
                ];
50
            }
51
52 381
            foreach ($serialisationTypes as $type) {
53 381
                $methods[] = array(
54 381
                    'type' => $type,
55 381
                    'format' => $format,
56 381
                    'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
57 381
                    'method' => 'serialize' . $type,
58
                );
59
            }
60
        }
61
62 381
        return $methods;
63
    }
64
65 386
    public function __construct($defaultFormat = \DateTime::ATOM, $defaultTimezone = 'UTC', $xmlCData = true)
66
    {
67 386
        $this->defaultFormat = $defaultFormat;
68 386
        $this->defaultTimezone = new \DateTimeZone($defaultTimezone);
69 386
        $this->xmlCData = $xmlCData;
70 386
    }
71
72 27
    private function serializeDateTimeInterface(
73
        SerializationVisitorInterface $visitor,
74
        \DateTimeInterface $date,
75
        array $type,
76
        SerializationContext $context
77
    )
78
    {
79 27
        if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) {
80 2
            return $visitor->visitSimpleString($date->format($this->getFormat($type)), $type, $context);
81
        }
82
83 25
        $format = $this->getFormat($type);
84 25
        if ('U' === $format) {
85 3
            return $visitor->visitInteger($date->format($format), $type, $context);
86
        }
87
88 22
        return $visitor->visitString($date->format($this->getFormat($type)), $type, $context);
89
    }
90
91 21
    public function serializeDateTime(SerializationVisitorInterface $visitor, \DateTime $date, array $type, SerializationContext $context)
92
    {
93 21
        return $this->serializeDateTimeInterface($visitor, $date, $type, $context);
94
    }
95
96 6
    public function serializeDateTimeImmutable(
97
        SerializationVisitorInterface $visitor,
98
        \DateTimeImmutable $date,
99
        array $type,
100
        SerializationContext $context
101
    )
102
    {
103 6
        return $this->serializeDateTimeInterface($visitor, $date, $type, $context);
104
    }
105
106 3
    public function serializeDateInterval(SerializationVisitorInterface $visitor, \DateInterval $date, array $type, SerializationContext $context)
107
    {
108 3
        $iso8601DateIntervalString = $this->format($date);
109
110 3
        if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) {
111
            return $visitor->visitSimpleString($iso8601DateIntervalString, $type, $context);
112
        }
113
114 3
        return $visitor->visitString($iso8601DateIntervalString, $type, $context);
115
    }
116
117 7
    private function isDataXmlNull($data)
118
    {
119 7
        $attributes = $data->attributes('xsi', true);
120 7
        return isset($attributes['nil'][0]) && (string)$attributes['nil'][0] === 'true';
121
    }
122
123 5
    public function deserializeDateTimeFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
124
    {
125 5
        if ($this->isDataXmlNull($data)) {
126
            return null;
127
        }
128
129 5
        return $this->parseDateTime($data, $type);
130
    }
131
132 1
    public function deserializeDateTimeImmutableFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
133
    {
134 1
        if ($this->isDataXmlNull($data)) {
135
            return null;
136
        }
137
138 1
        return $this->parseDateTime($data, $type, true);
139
    }
140
141 1
    public function deserializeDateIntervalFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
142
    {
143 1
        if ($this->isDataXmlNull($data)) {
144
            return null;
145
        }
146
147 1
        return $this->parseDateInterval($data);
148
    }
149
150 10
    public function deserializeDateTimeFromJson(JsonDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
151
    {
152 10
        if (null === $data) {
153 1
            return null;
154
        }
155
156 9
        return $this->parseDateTime($data, $type);
157
    }
158
159 3
    public function deserializeDateTimeImmutableFromJson(JsonDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
160
    {
161 3
        if (null === $data) {
162
            return null;
163
        }
164
165 3
        return $this->parseDateTime($data, $type, true);
166
    }
167
168 1
    public function deserializeDateIntervalFromJson(JsonDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
169
    {
170 1
        if (null === $data) {
171
            return null;
172
        }
173
174 1
        return $this->parseDateInterval($data);
175
    }
176
177 7
    public function deserializeDateTimeFromYml(YamlDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
178
    {
179 7
        if (null === $data) {
180 1
            return null;
181
        }
182
183 6
        return $this->parseDateTime($data, $type);
184
    }
185
186 2
    public function deserializeDateTimeImmutableFromYml(YamlDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
187
    {
188 2
        if (null === $data) {
189
            return null;
190
        }
191
192 2
        return $this->parseDateTime($data, $type, true);
193
    }
194
195 1
    public function deserializeDateIntervalFromYml(YamlDeserializationVisitor $visitor, $data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
196
    {
197 1
        if (null === $data) {
198
            return null;
199
        }
200
201 1
        return $this->parseDateInterval($data);
202
    }
203
204 26
    private function parseDateTime($data, array $type, $immutable = false)
205
    {
206 26
        $timezone = !empty($type['params'][1]) ? new \DateTimeZone($type['params'][1]) : $this->defaultTimezone;
207 26
        $format = $this->getDeserializationFormat($type);
208
209 26
        if ($immutable) {
210 6
            $datetime = \DateTimeImmutable::createFromFormat($format, (string)$data, $timezone);
211
        } else {
212 20
            $datetime = \DateTime::createFromFormat($format, (string)$data, $timezone);
213
        }
214
215 26
        if (false === $datetime) {
216
            throw new RuntimeException(sprintf('Invalid datetime "%s", expected format %s.', $data, $format));
217
        }
218
219 26
        if ($format === 'U') {
220 5
            $datetime = $datetime->setTimezone($timezone);
221
        }
222
223 26
        return $datetime;
224
    }
225
226 3
    private function parseDateInterval($data)
227
    {
228 3
        $dateInterval = null;
229
        try {
230 3
            $dateInterval = new \DateInterval($data);
231
        } catch (\Exception $e) {
232
            throw new RuntimeException(sprintf('Invalid dateinterval "%s", expected ISO 8601 format', $data), null, $e);
233
        }
234
235 3
        return $dateInterval;
236
    }
237
238
    /**
239
     * @param array $type
240
     *  @return string
241
     */
242 26
    private function getDeserializationFormat(array $type)
243
    {
244 26
        if (isset($type['params'][2])) {
245 2
            return $type['params'][2];
246
        }
247 25
        if (isset($type['params'][0])) {
248 13
            return $type['params'][0];
249
        }
250 15
        return $this->defaultFormat;
251
    }
252
253
    /**
254
     * @return string
255
     * @param array $type
256
     */
257 27
    private function getFormat(array $type)
258
    {
259 27
        return isset($type['params'][0]) ? $type['params'][0] : $this->defaultFormat;
260
    }
261
262
    /**
263
     * @param \DateInterval $dateInterval
264
     * @return string
265
     */
266 4
    public function format(\DateInterval $dateInterval)
267
    {
268 4
        $format = 'P';
269
270 4
        if (0 < $dateInterval->y) {
271 1
            $format .= $dateInterval->y . 'Y';
272
        }
273
274 4
        if (0 < $dateInterval->m) {
275
            $format .= $dateInterval->m . 'M';
276
        }
277
278 4
        if (0 < $dateInterval->d) {
279 1
            $format .= $dateInterval->d . 'D';
280
        }
281
282 4
        if (0 < $dateInterval->h || 0 < $dateInterval->i || 0 < $dateInterval->s) {
283 4
            $format .= 'T';
284
        }
285
286 4
        if (0 < $dateInterval->h) {
287 1
            $format .= $dateInterval->h . 'H';
288
        }
289
290 4
        if (0 < $dateInterval->i) {
291 4
            $format .= $dateInterval->i . 'M';
292
        }
293
294 4
        if (0 < $dateInterval->s) {
295 1
            $format .= $dateInterval->s . 'S';
296
        }
297
298 4
        if ($format === 'P') {
299 1
            $format = 'P0DT0S';
300
        }
301
302 4
        return $format;
303
    }
304
}
305