Total Complexity | 101 |
Total Lines | 574 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like DateFormat 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.
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 DateFormat, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
51 | class DateFormat |
||
52 | { |
||
53 | /** |
||
54 | * A list of tokens and their function call. |
||
55 | * @var array |
||
56 | */ |
||
57 | protected $tokens = [ |
||
58 | 'G' => 'Era', |
||
59 | 'y' => 'Year', |
||
60 | 'M' => 'Month', |
||
61 | 'd' => 'Day', |
||
62 | 'h' => 'Hour12', |
||
63 | 'H' => 'Hour24', |
||
64 | 'm' => 'Minutes', |
||
65 | 's' => 'Seconds', |
||
66 | 'E' => 'DayInWeek', |
||
67 | 'D' => 'DayInYear', |
||
68 | 'F' => 'DayInMonth', |
||
69 | 'w' => 'WeekInYear', |
||
70 | 'W' => 'WeekInMonth', |
||
71 | 'a' => 'AMPM', |
||
72 | 'k' => 'HourInDay', |
||
73 | 'K' => 'HourInAMPM', |
||
74 | 'z' => 'TimeZone' |
||
75 | ]; |
||
76 | |||
77 | /** |
||
78 | * A list of methods, to be used by the token function calls. |
||
79 | * @var array |
||
80 | */ |
||
81 | protected $methods = []; |
||
82 | |||
83 | /** |
||
84 | * The DateTimeFormatInfo, containing culture specific patterns and names. |
||
85 | * @var DateTimeFormatInfo |
||
86 | */ |
||
87 | protected $formatInfo; |
||
88 | |||
89 | /** |
||
90 | * Initialize a new DateFormat. |
||
91 | * @param mixed either, null, a CultureInfo instance, |
||
|
|||
92 | * a DateTimeFormatInfo instance, or a locale. |
||
93 | * @return DateFormat instance |
||
94 | */ |
||
95 | public function __construct($formatInfo = null) |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Format a date according to the pattern. |
||
111 | * @param mixed the time as integer or string in strtotime format. |
||
112 | * @return string formatted date time. |
||
113 | */ |
||
114 | public function format($time, $pattern = 'F', $charset = 'UTF-8') |
||
115 | { |
||
116 | if (is_numeric($time)) //assumes unix epoch |
||
117 | $time = floatval($time); |
||
118 | elseif(is_string($time)) |
||
119 | $time = @strtotime($time); |
||
120 | |||
121 | if($pattern === null) |
||
122 | $pattern = 'F'; |
||
123 | |||
124 | $date = new \DateTime; |
||
125 | $date->setTimestamp($time); |
||
126 | |||
127 | $pattern = $this->getPattern($pattern); |
||
128 | |||
129 | $tokens = $this->getTokens($pattern); |
||
130 | |||
131 | for($i = 0, $k = count($tokens); $i < $k; ++$i) |
||
132 | { |
||
133 | $pattern = $tokens[$i]; |
||
134 | if($pattern{0} == "'" |
||
135 | && $pattern{strlen($pattern) - 1} == "'") |
||
136 | { |
||
137 | $sub = preg_replace('/(^\')|(\'$)/', '', $pattern); |
||
138 | $tokens[$i] = str_replace('``````', '\'', $sub); |
||
139 | } |
||
140 | elseif($pattern == '``````') |
||
141 | { |
||
142 | $tokens[$i] = '\''; |
||
143 | } |
||
144 | else |
||
145 | { |
||
146 | $function = $this->getFunctionName($pattern); |
||
147 | if($function != null) |
||
148 | { |
||
149 | $fName = 'get' . $function; |
||
150 | if(in_array($fName, $this->methods)) |
||
151 | { |
||
152 | $rs = $this->$fName($date, $pattern); |
||
153 | $tokens[$i] = $rs; |
||
154 | } |
||
155 | else |
||
156 | throw new |
||
157 | Exception('function ' . $function . ' not found.'); |
||
158 | } |
||
159 | } |
||
160 | } |
||
161 | |||
162 | return I18N_toEncoding(implode('', $tokens), $charset); |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * For a particular token, get the corresponding function to call. |
||
167 | * @param string token |
||
168 | * @return mixed the function if good token, null otherwise. |
||
169 | */ |
||
170 | protected function getFunctionName($token) |
||
171 | { |
||
172 | if(isset($this->tokens[$token{0}])) |
||
173 | return $this->tokens[$token{0}]; |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * Get the pattern from DateTimeFormatInfo or some predefined patterns. |
||
178 | * If the $pattern parameter is an array of 2 element, it will assume |
||
179 | * that the first element is the date, and second the time |
||
180 | * and try to find an appropriate pattern and apply |
||
181 | * DateTimeFormatInfo::formatDateTime |
||
182 | * See the tutorial documentation for futher details on the patterns. |
||
183 | * @param mixed a pattern. |
||
184 | * @return string a pattern. |
||
185 | * @see DateTimeFormatInfo::formatDateTime() |
||
186 | */ |
||
187 | protected function getPattern($pattern) |
||
188 | { |
||
189 | if(is_array($pattern) && count($pattern) == 2) |
||
190 | { |
||
191 | return $this->formatInfo->formatDateTime( |
||
192 | $this->getPattern($pattern[0]), |
||
193 | $this->getPattern($pattern[1])); |
||
194 | } |
||
195 | |||
196 | switch($pattern) |
||
197 | { |
||
198 | case 'd': |
||
199 | return $this->formatInfo->ShortDatePattern; |
||
200 | break; |
||
201 | case 'D': |
||
202 | return $this->formatInfo->LongDatePattern; |
||
203 | break; |
||
204 | case 'p': |
||
205 | return $this->formatInfo->MediumDatePattern; |
||
206 | break; |
||
207 | case 'P': |
||
208 | return $this->formatInfo->FullDatePattern; |
||
209 | break; |
||
210 | case 't': |
||
211 | return $this->formatInfo->ShortTimePattern; |
||
212 | break; |
||
213 | case 'T': |
||
214 | return $this->formatInfo->LongTimePattern; |
||
215 | break; |
||
216 | case 'q': |
||
217 | return $this->formatInfo->MediumTimePattern; |
||
218 | break; |
||
219 | case 'Q': |
||
220 | return $this->formatInfo->FullTimePattern; |
||
221 | break; |
||
222 | case 'f': |
||
223 | return $this->formatInfo->formatDateTime( |
||
224 | $this->formatInfo->LongDatePattern, |
||
225 | $this->formatInfo->ShortTimePattern); |
||
226 | break; |
||
227 | case 'F': |
||
228 | return $this->formatInfo->formatDateTime( |
||
229 | $this->formatInfo->LongDatePattern, |
||
230 | $this->formatInfo->LongTimePattern); |
||
231 | break; |
||
232 | case 'g': |
||
233 | return $this->formatInfo->formatDateTime( |
||
234 | $this->formatInfo->ShortDatePattern, |
||
235 | $this->formatInfo->ShortTimePattern); |
||
236 | break; |
||
237 | case 'G': |
||
238 | return $this->formatInfo->formatDateTime( |
||
239 | $this->formatInfo->ShortDatePattern, |
||
240 | $this->formatInfo->LongTimePattern); |
||
241 | break; |
||
242 | case 'M': |
||
243 | case 'm': |
||
244 | return 'MMMM dd'; |
||
245 | break; |
||
246 | case 'R': |
||
247 | case 'r': |
||
248 | return 'EEE, dd MMM yyyy HH:mm:ss'; |
||
249 | break; |
||
250 | case 's': |
||
251 | return 'yyyy-MM-ddTHH:mm:ss'; |
||
252 | break; |
||
253 | case 'u': |
||
254 | return 'yyyy-MM-dd HH:mm:ss z'; |
||
255 | break; |
||
256 | case 'U': |
||
257 | return 'EEEE dd MMMM yyyy HH:mm:ss'; |
||
258 | break; |
||
259 | case 'Y': |
||
260 | case 'y': |
||
261 | return 'yyyy MMMM'; |
||
262 | break; |
||
263 | default : |
||
264 | return $pattern; |
||
265 | } |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Tokenize the pattern. The tokens are delimited by group of |
||
270 | * similar characters, e.g. 'aabb' will form 2 tokens of 'aa' and 'bb'. |
||
271 | * Any substrings, starting and ending with a single quote (') |
||
272 | * will be treated as a single token. |
||
273 | * @param string pattern. |
||
274 | * @return array string tokens in an array. |
||
275 | */ |
||
276 | protected function getTokens($pattern) |
||
277 | { |
||
278 | $char = null; |
||
279 | $tokens = []; |
||
280 | $token = null; |
||
281 | |||
282 | $text = false; |
||
283 | $pattern = preg_replace("/''/", '``````', $pattern); |
||
284 | |||
285 | for($i = 0; $i < strlen($pattern); $i++) |
||
286 | { |
||
287 | if($char == null || $pattern{$i} == $char || $text) |
||
288 | { |
||
289 | $token .= $pattern{$i}; |
||
290 | } |
||
291 | else |
||
292 | { |
||
293 | $tokens[] = str_replace("", "'", $token); |
||
294 | $token = $pattern{$i}; |
||
295 | } |
||
296 | |||
297 | if($pattern{$i} == "'" && $text == false) |
||
298 | $text = true; |
||
299 | elseif($text && $pattern{$i} == "'" && $char == "'") |
||
300 | $text = true; |
||
301 | elseif($text && $char != "'" && $pattern{$i} == "'") |
||
302 | $text = false; |
||
303 | |||
304 | $char = $pattern{$i}; |
||
305 | |||
306 | } |
||
307 | $tokens[] = $token; |
||
308 | return $tokens; |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Get the year. |
||
313 | * "yy" will return the last two digits of year. |
||
314 | * "yyyy" will return the full integer year. |
||
315 | * @param array getdate format. |
||
316 | * @param string a pattern. |
||
317 | * @return string year |
||
318 | */ |
||
319 | protected function getYear($date, $pattern = 'yyyy') |
||
320 | { |
||
321 | switch($pattern) |
||
322 | { |
||
323 | case 'yy': |
||
324 | return $date->format('y'); |
||
325 | case 'yyyy': |
||
326 | return $date->format('Y'); |
||
327 | default: |
||
328 | throw new Exception('The pattern for year is either "yy" or "yyyy".'); |
||
329 | } |
||
330 | } |
||
331 | |||
332 | /** |
||
333 | * Get the month. |
||
334 | * "M" will return integer 1 through 12 |
||
335 | * "MM" will return the narrow month name, e.g. "J" |
||
336 | * "MMM" will return the abrreviated month name, e.g. "Jan" |
||
337 | * "MMMM" will return the month name, e.g. "January" |
||
338 | * @param array getdate format. |
||
339 | * @param string a pattern. |
||
340 | * @return string month name |
||
341 | */ |
||
342 | protected function getMonth($date, $pattern = 'M') |
||
343 | { |
||
344 | switch($pattern) |
||
345 | { |
||
346 | case 'M': |
||
347 | return $date->format('n'); |
||
348 | case 'MM': |
||
349 | return $date->format('m'); |
||
350 | case 'MMM': |
||
351 | return $this->formatInfo->AbbreviatedMonthNames[$date->format('n') - 1]; |
||
352 | case 'MMMM': |
||
353 | return $this->formatInfo->MonthNames[$date->format('n') - 1]; |
||
354 | default: |
||
355 | throw new Exception('The pattern for month is "M", "MM", "MMM", or "MMMM".'); |
||
356 | } |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * Get the day of the week. |
||
361 | * "E" will return integer 0 (for Sunday) through 6 (for Saturday). |
||
362 | * "EE" will return the narrow day of the week, e.g. "M" |
||
363 | * "EEE" will return the abrreviated day of the week, e.g. "Mon" |
||
364 | * "EEEE" will return the day of the week, e.g. "Monday" |
||
365 | * @param array getdate format. |
||
366 | * @param string a pattern. |
||
367 | * @return string day of the week. |
||
368 | */ |
||
369 | protected function getDayInWeek($date, $pattern = 'EEEE') |
||
370 | { |
||
371 | $day = $date->format('w'); |
||
372 | switch($pattern) |
||
373 | { |
||
374 | case 'E': |
||
375 | return $day; |
||
376 | case 'EE': |
||
377 | return $this->formatInfo->NarrowDayNames[$day]; |
||
378 | case 'EEE': |
||
379 | return $this->formatInfo->AbbreviatedDayNames[$day]; |
||
380 | case 'EEEE': |
||
381 | return $this->formatInfo->DayNames[$day]; |
||
382 | default: |
||
383 | throw new Exception('The pattern for day of the week is "E", "EE", "EEE", or "EEEE".'); |
||
384 | } |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * Get the day of the month. |
||
389 | * "d" for non-padding, "dd" will always return 2 characters. |
||
390 | * @param array getdate format. |
||
391 | * @param string a pattern. |
||
392 | * @return string day of the month |
||
393 | */ |
||
394 | protected function getDay($date, $pattern = 'd') |
||
395 | { |
||
396 | switch($pattern) |
||
397 | { |
||
398 | case 'd': |
||
399 | return $date->format('j'); |
||
400 | case 'dd': |
||
401 | return $date->format('d'); |
||
402 | default: |
||
403 | throw new Exception('The pattern for day of the month is "d" or "dd".'); |
||
404 | } |
||
405 | } |
||
406 | |||
407 | |||
408 | /** |
||
409 | * Get the era. i.e. in gregorian, year > 0 is AD, else BC. |
||
410 | * @todo How to support multiple Eras?, e.g. Japanese. |
||
411 | * @param array getdate format. |
||
412 | * @param string a pattern. |
||
413 | * @return string era |
||
414 | */ |
||
415 | protected function getEra($date, $pattern = 'G') |
||
416 | { |
||
417 | if($pattern != 'G') |
||
418 | throw new Exception('The pattern for era is "G".'); |
||
419 | |||
420 | $year = $date->format('Y'); |
||
421 | if($year > 0) |
||
422 | return $this->formatInfo->getEra(1); |
||
423 | else |
||
424 | return $this->formatInfo->getEra(0); |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Get the hours in 24 hour format, i.e. [0-23]. |
||
429 | * "H" for non-padding, "HH" will always return 2 characters. |
||
430 | * @param array getdate format. |
||
431 | * @param string a pattern. |
||
432 | * @return string hours in 24 hour format. |
||
433 | */ |
||
434 | protected function getHour24($date, $pattern = 'H') |
||
435 | { |
||
436 | switch($pattern) |
||
437 | { |
||
438 | case 'H': |
||
439 | return $date->format('G'); |
||
440 | case 'HH': |
||
441 | return $date->format('H'); |
||
442 | default: |
||
443 | throw new Exception('The pattern for 24 hour format is "H" or "HH".'); |
||
444 | } |
||
445 | } |
||
446 | |||
447 | /** |
||
448 | * Get the AM/PM designator, 12 noon is PM, 12 midnight is AM. |
||
449 | * @param array getdate format. |
||
450 | * @param string a pattern. |
||
451 | * @return string AM or PM designator |
||
452 | */ |
||
453 | protected function getAMPM($date, $pattern = 'a') |
||
454 | { |
||
455 | if($pattern != 'a') |
||
456 | throw new Exception('The pattern for AM/PM marker is "a".'); |
||
457 | |||
458 | $hour = $date->format('G'); |
||
459 | $ampm = (int)($hour / 12); |
||
460 | return $this->formatInfo->AMPMMarkers[$ampm]; |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * Get the hours in 12 hour format. |
||
465 | * "h" for non-padding, "hh" will always return 2 characters. |
||
466 | * @param array getdate format. |
||
467 | * @param string a pattern. |
||
468 | * @return string hours in 12 hour format. |
||
469 | */ |
||
470 | protected function getHour12($date, $pattern = 'h') |
||
471 | { |
||
472 | switch($pattern) |
||
473 | { |
||
474 | case 'h': |
||
475 | return $date->format('g'); |
||
476 | case 'hh': |
||
477 | return $date->format('h'); |
||
478 | default: |
||
479 | throw new Exception('The pattern for 24 hour format is "H" or "HH".'); |
||
480 | } |
||
481 | } |
||
482 | |||
483 | /** |
||
484 | * Get the minutes. |
||
485 | * "m" for non-padding, "mm" will always return 2 characters. |
||
486 | * @param array getdate format. |
||
487 | * @param string a pattern. |
||
488 | * @return string minutes. |
||
489 | */ |
||
490 | protected function getMinutes($date, $pattern = 'm') |
||
491 | { |
||
492 | switch($pattern) |
||
493 | { |
||
494 | case 'm': |
||
495 | return (int) $date->format('i'); |
||
496 | case 'mm': |
||
497 | return $date->format('i'); |
||
498 | default: |
||
499 | throw new Exception('The pattern for minutes is "m" or "mm".'); |
||
500 | } |
||
501 | } |
||
502 | |||
503 | /** |
||
504 | * Get the seconds. |
||
505 | * "s" for non-padding, "ss" will always return 2 characters. |
||
506 | * @param array getdate format. |
||
507 | * @param string a pattern. |
||
508 | * @return string seconds |
||
509 | */ |
||
510 | protected function getSeconds($date, $pattern = 's') |
||
511 | { |
||
512 | switch($pattern) |
||
513 | { |
||
514 | case 's': |
||
515 | return (int) $date->format('s'); |
||
516 | case 'ss': |
||
517 | return $date->format('s'); |
||
518 | default: |
||
519 | throw new Exception('The pattern for seconds is "s" or "ss".'); |
||
520 | } |
||
521 | } |
||
522 | |||
523 | /** |
||
524 | * Get the timezone from the server machine. |
||
525 | * @todo How to get the timezone for a different region? |
||
526 | * @param array getdate format. |
||
527 | * @param string a pattern. |
||
528 | * @return string time zone |
||
529 | */ |
||
530 | protected function getTimeZone($date, $pattern = 'z') |
||
531 | { |
||
532 | if($pattern != 'z') |
||
533 | throw new Exception('The pattern for time zone is "z".'); |
||
534 | |||
535 | return $date->format('T'); |
||
536 | } |
||
537 | |||
538 | /** |
||
539 | * Get the day in the year, e.g. [1-366] |
||
540 | * @param array getdate format. |
||
541 | * @param string a pattern. |
||
542 | * @return int hours in AM/PM format. |
||
543 | */ |
||
544 | protected function getDayInYear($date, $pattern = 'D') |
||
545 | { |
||
546 | if($pattern != 'D') |
||
547 | throw new Exception('The pattern for day in year is "D".'); |
||
548 | |||
549 | return $date->format('z'); |
||
550 | } |
||
551 | |||
552 | /** |
||
553 | * Get day in the month. |
||
554 | * @param array getdate format. |
||
555 | * @param string a pattern. |
||
556 | * @return int day in month |
||
557 | */ |
||
558 | protected function getDayInMonth($date, $pattern = 'FF') |
||
559 | { |
||
560 | switch ($pattern) { |
||
561 | case 'F': |
||
562 | return $date->format('j'); |
||
563 | case 'FF': |
||
564 | return $date->format('d'); |
||
565 | default: |
||
566 | throw new Exception('The pattern for day in month is "F" or "FF".'); |
||
567 | } |
||
568 | } |
||
569 | |||
570 | /** |
||
571 | * Get the week in the year. |
||
572 | * @param array getdate format. |
||
573 | * @param string a pattern. |
||
574 | * @return int week in year |
||
575 | */ |
||
576 | protected function getWeekInYear($date, $pattern = 'w') |
||
577 | { |
||
578 | if($pattern != 'w') |
||
579 | throw new Exception('The pattern for week in year is "w".'); |
||
580 | |||
581 | return $date->format('W'); |
||
582 | } |
||
583 | |||
584 | /** |
||
585 | * Get week in the month. |
||
586 | * @param array getdate format. |
||
587 | * @return int week in month |
||
588 | */ |
||
589 | protected function getWeekInMonth($date, $pattern = 'W') |
||
590 | { |
||
591 | if($pattern != 'W') |
||
592 | throw new Exception('The pattern for week in month is "W".'); |
||
593 | |||
594 | $firstInMonth = clone($date); |
||
595 | $firstInMonth->setDate($firstInMonth->format('Y'), $firstInMonth->format('m'), 1); |
||
596 | return $date->format('W') - $firstInMonth->format('W'); |
||
597 | } |
||
598 | |||
599 | /** |
||
600 | * Get the hours [1-24]. |
||
601 | * @param array getdate format. |
||
602 | * @param string a pattern. |
||
603 | * @return int hours [1-24] |
||
604 | */ |
||
605 | protected function getHourInDay($date, $pattern = 'k') |
||
606 | { |
||
607 | if($pattern != 'k') |
||
608 | throw new Exception('The pattern for hour in day is "k".'); |
||
609 | |||
610 | return $date->format('G') + 1; |
||
611 | } |
||
612 | |||
613 | /** |
||
614 | * Get the hours in AM/PM format, e.g [1-12] |
||
615 | * @param array getdate format. |
||
616 | * @param string a pattern. |
||
617 | * @return int hours in AM/PM format. |
||
618 | */ |
||
619 | protected function getHourInAMPM($date, $pattern = 'K') |
||
625 | } |
||
626 | } |
||
627 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths