DutchStringToDateTimeTransformer::transform()   F
last analyzed

Complexity

Conditions 27
Paths 34

Size

Total Lines 109

Duplication

Lines 6
Ratio 5.5 %

Code Coverage

Tests 50
CRAP Score 27.2966

Importance

Changes 0
Metric Value
dl 6
loc 109
ccs 50
cts 54
cp 0.9259
rs 3.3333
c 0
b 0
f 0
cc 27
nc 34
nop 1
crap 27.2966

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace TreeHouse\IoBundle\Item\Modifier\Data\Transformer;
4
5
use TreeHouse\Feeder\Modifier\Data\Transformer\StringToDateTimeTransformer as FallbackTransformer;
6
use TreeHouse\Feeder\Modifier\Data\Transformer\TransformerInterface;
7
8
class DutchStringToDateTimeTransformer implements TransformerInterface
9
{
10
    protected $monthNames = [
11
        1 => 'januari',
12
        2 => 'februari',
13
        3 => 'maart',
14
        4 => 'april',
15
        5 => 'mei',
16
        6 => 'juni',
17
        7 => 'juli',
18
        8 => 'augustus',
19
        9 => 'september',
20
        10 => 'oktober',
21
        11 => 'november',
22
        12 => 'december',
23
    ];
24
25
    /**
26
     * @var \DateTimeZone
27
     */
28
    protected $timezone;
29
30
    /**
31
     * @var string
32
     */
33
    protected $monthRegex;
34
35
    /**
36
     * @param array         $monthNames
37
     * @param \DateTimeZone $timezone
38
     */
39 92
    public function __construct(array $monthNames = [], \DateTimeZone $timezone = null)
40
    {
41 92
        if (!empty($monthNames)) {
42
            $this->monthNames = $monthNames;
43
        }
44
45 92
        $this->monthRegex = implode('|', array_values($this->monthNames));
46 92
        $this->timezone = $timezone ?: new \DateTimeZone('UTC');
47 92
    }
48
49
    /**
50
     * @inheritdoc
51
     */
52 92
    public function transform($value)
53
    {
54 92
        if (is_null($value) || empty($value)) {
55 4
            return null;
56
        }
57
58 88
        if ($value instanceof \DateTime) {
59 2
            return $value;
60
        }
61
62
        // "per direct" => now
63 86 View Code Duplication
        if (preg_match('/(per )?dire(c|k)t/i', $value) || preg_match('/(gelijk|heden)/i', $value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
64 12
            return new \DateTime('now', $this->timezone);
65
        }
66
67
        // [sinds] 2 [mnd|maand|maanden]
68 74 View Code Duplication
        if (preg_match('/^(sinds\s)?(?P<months>\d+)\s(maand|maanden|mnd)\s?\+?/i', $value, $matches)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69 12
            return new \DateTime(sprintf('-%s months', $matches['months']), $this->timezone);
70
        }
71
72
        // [12] oktober 2012|'12
73 62
        $regex = '/^(?P<day>\d*\s?)?(?P<month>' . $this->monthRegex . ')\s+(?P<year>\d{4}|\\\'\d{2})/i';
74 62
        if (preg_match($regex, $value, $matches)) {
75 10
            $year = $matches['year'];
76 10
            $month = array_search(mb_strtolower($matches['month']), $this->monthNames);
77 10
            $day = (isset($matches['day']) && ($matches['day'] !== '')) ? $matches['day'] : 1;
78
79 10
            return $this->createDate($year, $month, $day);
80
        }
81
82
        // 12 oktober [2012|'12]
83 52
        $regex = '/^(?P<day>\d{1,2})\s?(?P<month>' . $this->monthRegex . ')(\s+(?P<year>\d{4}|\\\'\d{2}))?/i';
84 52
        if (preg_match($regex, $value, $matches)) {
85 2
            $year = isset($matches['year']) ? $matches['year'] : date('Y');
86 2
            $month = array_search(mb_strtolower($matches['month']), $this->monthNames);
87 2
            $day = $matches['day'];
88
89 2
            return $this->createDate($year, $month, $day);
90
        }
91
92
        // oktober [12|2012]
93 50
        $regex = '/^(?P<month>' . $this->monthRegex . ')(\s+(?P<day_or_year>\d{4}|\d{1,2}))?/i';
94 50
        if (preg_match($regex, $value, $matches)) {
95 4
            $month = array_search(mb_strtolower($matches['month']), $this->monthNames);
96 4
            $year = date('Y');
97 4
            $day = 1;
98
99 4
            if (isset($matches['day_or_year'])) {
100 2
                if (strlen($matches['day_or_year']) === 2) {
101 2
                    $day = $matches['day_or_year'];
102
                } elseif (strlen($matches['day_or_year']) === 4) {
103
                    $year = $matches['day_or_year'];
104
                }
105
            }
106
107 4
            return $this->createDate($year, $month, $day);
108
        }
109
110
        // [begin|eind] mei [2013]
111 46
        $regex = '/^(?P<day>begin|eind)?\s?(?P<month>' . $this->monthRegex . ')(?P<year>\s+\d{4})?/i';
112 46
        if (preg_match($regex, $value, $matches)) {
113 4
            $year = isset($matches['year']) ? $matches['year'] : date('Y');
114 4
            $month = array_search(mb_strtolower($matches['month']), $this->monthNames);
115 4
            if (isset($matches['day'])) {
116 4
                $day = $matches['day'] === 'begin' ? 5 : 25;
117
            } else {
118
                $day = 1;
119
            }
120
121 4
            return $this->createDate($year, $month, $day);
122
        }
123
124
        $regexes = [
125
            // 12-10-[2012|'12]
126 42
            '/^(?P<day>\d{1,2})[\-\/](?P<month>\d{1,2})[\-\/](?P<year>\d{4}|\\\'?\d{2})/i' => [null, null, null],
127
            // 2012-10-26
128
            '/^(?P<year>\d{4})[\-\/](?P<month>\d{1,2})[\-\/](?P<day>\d{1,2})/i' => [null, null, null],
129
            // 2012-10 (defaults the day to 1)
130
            '/^(?P<year>\d{4})[\-\/](?P<month>\d{1,2})/i' => [null, null, 1],
131
            // 2012 (defaults to jan. 1st)
132
            '/^(?P<year>\d{4})/i' => [null, 1, 1],
133
        ];
134
135 42
        foreach ($regexes as $regex => $defaults) {
136 42
            if (preg_match($regex, $value, $matches)) {
137 36
                list($defaultYear, $defaultMonth, $defaultDay) = $defaults;
138 36
                $year = isset($matches['year'])  ? $matches['year']  : $defaultYear;
139 36
                $month = isset($matches['month']) ? $matches['month'] : $defaultMonth;
140 36
                $day = isset($matches['day'])   ? $matches['day']   : $defaultDay;
141
142 42
                return $this->createDate($year, $month, $day);
143
            }
144
        }
145
146
        // check if strtotime matches
147 6
        if (false !== strtotime($value)) {
148 2
            return new \DateTime($value, $this->timezone);
149
        }
150
151
        // 26/03/2013
152 4
        if (preg_match('/^(?P<day>\d{1,2})\/(?P<month>\d{1,2})\/(?<year>\d{4})/i', $value, $matches)) {
153
            return $this->createDate($matches['year'], $matches['month'], $matches['day']);
154
        }
155
156
        // last resort
157 4
        $transformer = new FallbackTransformer('d-m-Y H:i:s', null, $this->timezone->getName());
158
159 4
        return $transformer->transform($value);
160
    }
161
162
    /**
163
     * @param string $year
164
     * @param string $month
165
     * @param string $day
166
     *
167
     * @return \DateTime
168
     */
169 56
    protected function createDate($year, $month, $day)
170
    {
171
        // year can have a quote prefix ('12)
172 56
        $year = str_replace("'", '', $year);
173
174
        // test for positive integer
175 56
        foreach (['year', 'month', 'day'] as $test) {
176 56
            $$test = intval($$test);
177 56
            if ($$test < 1) {
178 56
                return null;
179
            }
180
        }
181
182
        // year can be 2-digit notation ('12)
183 44
        if (strlen($year) === 2) {
184
            // use the 21st century until 2020, after that use the 20th century (1921-1999)
185 8
            $prefix = $year <= 20 ? 20 : 19;
186 8
            $year = (int) $prefix . $year;
187
        }
188
189
        // test if year seems valid
190 44
        if ((strlen($year) !== 4) || ($year > 2100)) {
191
            return null;
192
        }
193
194
        // check whether this is a valid date
195 44
        if (false === checkdate($month, $day, $year)) {
196 6
            return null;
197
        }
198
199 38
        return \DateTime::createFromFormat(
200 38
            'Y-n-j H:i:s',
201 38
            sprintf('%d-%d-%d 00:00:00', $year, $month, $day),
202 38
            $this->timezone
203
        );
204
    }
205
}
206