Completed
Push — master ( 0c820c...9912c8 )
by Asmir
9s
created

DateHandler   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 92.04%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 3
dl 0
loc 229
ccs 104
cts 113
cp 0.9204
rs 8.439
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
B getSubscribingMethods() 0 28 4
A __construct() 0 6 1
A serializeDateTimeInterface() 0 18 4
A serializeDateTime() 0 4 1
A serializeDateTimeImmutable() 0 9 1
A serializeDateInterval() 0 10 3
A isDataXmlNull() 0 5 2
A deserializeDateTimeFromXml() 0 8 2
A deserializeDateTimeImmutableFromXml() 0 8 2
A deserializeDateIntervalFromXml() 0 8 2
A deserializeDateTimeFromJson() 0 8 2
A deserializeDateTimeImmutableFromJson() 0 8 2
A deserializeDateIntervalFromJson() 0 8 2
A parseDateTime() 0 17 4
A parseDateInterval() 0 11 2
A getFormat() 0 4 2
F format() 0 38 11

How to fix   Complexity   

Complex Class

Complex classes like DateHandler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DateHandler, and based on these observations, apply Extract Interface, too.

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\Context;
22
use JMS\Serializer\Exception\RuntimeException;
23
use JMS\Serializer\GraphNavigator;
24
use JMS\Serializer\JsonDeserializationVisitor;
25
use JMS\Serializer\VisitorInterface;
26
use JMS\Serializer\XmlDeserializationVisitor;
27
use JMS\Serializer\XmlSerializationVisitor;
28
29
class DateHandler implements SubscribingHandlerInterface
30
{
31
    private $defaultFormat;
32
    private $defaultTimezone;
33
    private $xmlCData;
34
35 306
    public static function getSubscribingMethods()
36
    {
37 306
        $methods = array();
38 306
        $deserialisationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval');
39 306
        $serialisationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval');
40
41 306
        foreach (array('json', 'xml', 'yml') as $format) {
42
43 306
            foreach ($deserialisationTypes as $type) {
44 306
                $methods[] = [
45 306
                    'type'      => $type,
46 306
                    'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
47 306
                    'format'    => $format,
48
                ];
49 306
            }
50
51 306
            foreach ($serialisationTypes as $type) {
52 306
                $methods[] = array(
53 306
                    'type' => $type,
54 306
                    'format' => $format,
55 306
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
56 306
                    'method' => 'serialize'.$type,
57
                );
58 306
            }
59 306
        }
60
61 306
        return $methods;
62
    }
63
64 307
    public function __construct($defaultFormat = \DateTime::ISO8601, $defaultTimezone = 'UTC', $xmlCData = true)
65
    {
66 307
        $this->defaultFormat = $defaultFormat;
67 307
        $this->defaultTimezone = new \DateTimeZone($defaultTimezone);
68 307
        $this->xmlCData = $xmlCData;
69 307
    }
70
71 27
    private function serializeDateTimeInterface(
72
        VisitorInterface $visitor,
73
        \DateTimeInterface $date,
74
        array $type,
75
        Context $context
76
    )
77
    {
78 27
        if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) {
79 2
            return $visitor->visitSimpleString($date->format($this->getFormat($type)), $type, $context);
80
        }
81
82 25
        $format = $this->getFormat($type);
83 25
        if ('U' === $format) {
84 3
            return $visitor->visitInteger($date->format($format), $type, $context);
85
        }
86
87 22
        return $visitor->visitString($date->format($this->getFormat($type)), $type, $context);
88
    }
89
90 21
    public function serializeDateTime(VisitorInterface $visitor, \DateTime $date, array $type, Context $context)
91
    {
92 21
        return $this->serializeDateTimeInterface($visitor, $date, $type, $context);
93
    }
94
95 6
    public function serializeDateTimeImmutable(
96
        VisitorInterface $visitor,
97
        \DateTimeImmutable $date,
98
        array $type,
99
        Context $context
100
    )
101
    {
102 6
        return $this->serializeDateTimeInterface($visitor, $date, $type, $context);
103
    }
104
105 3
    public function serializeDateInterval(VisitorInterface $visitor, \DateInterval $date, array $type, Context $context)
106
    {
107 3
        $iso8601DateIntervalString = $this->format($date);
108
109 3
        if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) {
110
            return $visitor->visitSimpleString($iso8601DateIntervalString, $type, $context);
111
        }
112
113 3
        return $visitor->visitString($iso8601DateIntervalString, $type, $context);
114
    }
115
116 8
    private function isDataXmlNull($data)
117
    {
118 8
        $attributes = $data->attributes('xsi', true);
119 8
        return isset($attributes['nil'][0]) && (string) $attributes['nil'][0] === 'true';
120
    }
121
122 6
    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...
123
    {
124 6
        if ($this->isDataXmlNull($data)) {
125 1
            return null;
126
        }
127
128 5
        return $this->parseDateTime($data, $type);
129
    }
130
131 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...
132
    {
133 1
        if ($this->isDataXmlNull($data)) {
134
            return null;
135
        }
136
137 1
        return $this->parseDateTime($data, $type, true);
138
    }
139
140 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...
141
    {
142 1
        if ($this->isDataXmlNull($data)) {
143
            return null;
144
        }
145
146 1
        return $this->parseDateInterval($data);
147
    }
148
149 7
    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...
150
    {
151 7
        if (null === $data) {
152 1
            return null;
153
        }
154
155 6
        return $this->parseDateTime($data, $type);
156
    }
157
158 2
    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...
159
    {
160 2
        if (null === $data) {
161
            return null;
162
        }
163
164 2
        return $this->parseDateTime($data, $type, true);
165
    }
166
167 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...
168
    {
169 1
        if (null === $data) {
170
            return null;
171
        }
172
173 1
        return $this->parseDateInterval($data);
174
    }
175
176 14
    private function parseDateTime($data, array $type, $immutable = false)
177
    {
178 14
        $timezone = isset($type['params'][1]) ? new \DateTimeZone($type['params'][1]) : $this->defaultTimezone;
179 14
        $format = $this->getFormat($type);
180
181 14
        if ($immutable) {
182 3
            $datetime = \DateTimeImmutable::createFromFormat($format, (string) $data, $timezone);
183 3
        } else {
184 11
            $datetime = \DateTime::createFromFormat($format, (string) $data, $timezone);
185
        }
186
187 14
        if (false === $datetime) {
188
            throw new RuntimeException(sprintf('Invalid datetime "%s", expected format %s.', $data, $format));
189
        }
190
191 14
        return $datetime;
192
    }
193
194 2
    private function parseDateInterval($data)
195
    {
196 2
        $dateInterval = null;
197
        try {
198 2
            $dateInterval = new \DateInterval($data);
199 2
        } catch (\Exception $e) {
200
            throw new RuntimeException(sprintf('Invalid dateinterval "%s", expected ISO 8601 format', $data), null, $e);
201
        }
202
203 2
        return $dateInterval;
204
    }
205
206
    /**
207
     * @return string
208
     * @param array $type
209
     */
210 27
    private function getFormat(array $type)
211
    {
212 27
        return isset($type['params'][0]) ? $type['params'][0] : $this->defaultFormat;
213
    }
214
215
    /**
216
     * @param \DateInterval $dateInterval
217
     * @return string
218
     */
219 4
    public function format(\DateInterval $dateInterval)
220
    {
221 4
        $format = 'P';
222
223 4
        if (0 < $dateInterval->y) {
224 1
            $format .= $dateInterval->y.'Y';
225 1
        }
226
227 4
        if (0 < $dateInterval->m) {
228
            $format .= $dateInterval->m.'M';
229
        }
230
231 4
        if (0 < $dateInterval->d) {
232 1
            $format .= $dateInterval->d.'D';
233 1
        }
234
235 4
        if (0 < $dateInterval->h || 0 < $dateInterval->i || 0 < $dateInterval->s) {
236 4
            $format .= 'T';
237 4
        }
238
239 4
        if (0 < $dateInterval->h) {
240 1
            $format .= $dateInterval->h.'H';
241 1
        }
242
243 4
        if (0 < $dateInterval->i) {
244 4
            $format .= $dateInterval->i.'M';
245 4
        }
246
247 4
        if (0 < $dateInterval->s) {
248 1
            $format .= $dateInterval->s.'S';
249 1
        }
250
251 4
        if ($format === 'P') {
252 1
            $format = 'P0DT0S';
253 1
        }
254
255 4
        return $format;
256
    }
257
}
258