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)) { |
|
|
|
|
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)) { |
|
|
|
|
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
|
|
|
|
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.