Passed
Push — master ( 69797c...d32eb8 )
by Roman
01:42
created

DateInterval::__construct()   D

Complexity

Conditions 14
Paths 126

Size

Total Lines 43
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 14

Importance

Changes 0
Metric Value
dl 0
loc 43
ccs 33
cts 33
cp 1
rs 4.7877
c 0
b 0
f 0
cc 14
eloc 35
nc 126
nop 1
crap 14

How to fix   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 RM;
4
5
use DateTime;
6
use DateTimeImmutable;
7
8
/**
9
 * @author Roman Mátyus <[email protected]>
10
 */
11 1
class DateInterval extends \DateInterval
12
{
13
	/** @var DateTimeImmutable */
14
	private $refDT;
15
16
	public function __construct($interval = 'PT0S')
17
	{
18 1
		if ($interval === NULL)
19 1
			$interval = 'PT0S';
20 1
		$this->refDT = new DateTimeImmutable('midnight');
21 1
		$invert = FALSE;
22 1
		if ($interval instanceof \DateInterval) {
23 1
			if ($interval->invert)
24 1
				$invert = TRUE;
25 1
			$interval = self::parse($interval);
26 1
		} elseif (is_string($interval)) {
27 1
			if (strpos($interval, '-') === 0) {
28
				$invert = TRUE;
29 1
				$interval = substr($interval, 1);
30 1
			}
31 1
		} elseif (is_int($interval)) {
32 1
			if ($interval < 0)
33 1
				$invert = TRUE;
34 1
			$interval = sprintf("PT%uS", abs($interval));
35 1
		} elseif (is_float($interval)) {
36 1
			if ($interval < 0)
37
				$invert = TRUE;
38
			$interval = sprintf("PT%uS", abs(round($interval)));
39 1
		}
40 1
		try {
41 1
			parent::__construct($interval);
42 1
		} catch (\Exception $e) {
43 1
			$this->validateRelativeFormat($interval, $e);
44 1
			$d1 = $this->getRefDT();
45
			$d2 = $this->getRefDT()->modify($interval);
46 1
47 1
			$int = $d1->diff($d2);
48
			if ($int === FALSE) {
49 1
				$parse = date_parse($int);
0 ignored issues
show
Bug introduced by
$int of type false|DateInterval is incompatible with the type string expected by parameter $date of date_parse(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

49
				$parse = date_parse(/** @scrutinizer ignore-type */ $int);
Loading history...
50
				if ($parse['error_count']) {
51
					throw new DateInterval\InvalidArgumentException;
52
				}
53 1
			} else {
54 1
				parent::__construct(self::parse($int));
55 1
			}
56 1
		}
57 1
		if ($invert) {
58 1
			$this->invert = 1;
59 1
		}
60 1
	}
61
62
	public function add($interval) : self
63
	{
64
		$d1 = $this->getRefDT();
65 1
		$d1->add($this);
66 1
		$d1->add(new self($interval));
67 1
		$int = ($this->getRefDT())->diff($d1);
68 1
		$this->__construct(self::parse(/** @scrutinizer ignore-type */$int));
69 1
		if ($d1 < $this->getRefDT())
70 1
			$this->invert = 1;
71 1
		return $this;
72 1
	}
73
74
	public function sub($interval) : self
75
	{
76
		$d1 = $this->getRefDT();
77 1
		$d1->add($this);
78 1
		$d1->sub(new self($interval));
79 1
		$int = ($this->getRefDT())->diff($d1);
80 1
		$this->__construct(self::parse(/** @scrutinizer ignore-type */$int));
81 1
		if ($d1 < $this->getRefDT())
82 1
			$this->invert = 1;
83
		return $this;
84
	}
85
86
	public function toSeconds() : int
87 1
	{
88 1
		return (($this->y * 365 * 24 * 60 * 60) +
89 1
			($this->m * 30 * 24 * 60 * 60) +
90 1
			($this->d * 24 * 60 * 60) +
91
			($this->h * 60 * 60) +
92
			($this->i * 60) +
93 1
			$this->s) * (($this->invert) ? -1 : 1);
94 1
	}
95 1
96 1
	public static function parse(\DateInterval $dateInterval) : string
97
	{
98
		$date = array(
99 1
			'Y' => $dateInterval->y,
100
			'M' => $dateInterval->m,
101 1
			'D' => $dateInterval->d
102 1
		);
103
104 1
		$time = array(
105 1
			'H' => $dateInterval->h,
106 1
			'M' => $dateInterval->i,
107 1
			'S' => $dateInterval->s
108
		);
109
110
		if (isset($time['H']) && $time['H'] < 0) {
111 1
			$time['H'] = 24 + $time['H'];
112 1
			if ($date['D'] >= 1)
113
				$date['D']--;
114
			elseif ($date['M'] >= 1)
115 1
				$date['M']--;
116
			elseif ($date['Y'] >= 1)
117
				$date['Y']--;
118
		}
119
120 1
		if ($time['H'] === 24) {
121
			$date['D']++;
122
			$time['H'] = 0;
123
		}
124
125 1
		$specString = 'P';
126
127
		foreach (array_filter($date) as $key => $value) {
128
			$specString .= $value . $key;
129
		}
130 1
		if (count(array_filter($time)) > 0) {
131 1
			$specString .= 'T';
132 1
			foreach (array_filter($time) as $key => $value) {
133 1
				$specString .= $value . $key;
134 1
			}
135 1
		}
136
137 1
		if (strlen($specString) === 1) {
138
			$specString .= 'T0S';
139
		}
140
141
		return $specString;
142
	}
143
144
	public function __toString()
145
	{
146
		return self::parse($this);
147
	}
148
149
	public function getRefDT()
150
	{
151
		return new DateTime($this->refDT->format(DateTime::ISO8601));
152
	}
153
154
	private function validateRelativeFormat($interval, \Exception $e = NULL)
155
	{
156
		$parse = date_parse($interval);
157
		if ($parse['error_count'])
158
			throw new DateInterval\InvalidArgumentException(($e) ? $e->getMessage() : NULL, ($e) ? $e->getCode() : NULL, ($e) ? $e : NULL);
159
		if (!isset($parse['relative']))
160
			throw new DateInterval\InvalidArgumentException(sprintf("First argument '%s' is not in supported relative date format.", $interval), ($e) ? $e->getCode() : NULL, ($e) ? $e : NULL);
161
	}
162
}
163