Completed
Push — master ( bb0f5a...762a3e )
by Igor
02:04
created

DateRange   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 41
lcom 2
cbo 6
dl 0
loc 204
ccs 67
cts 67
cp 1
rs 8.2769
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 11 6
A getStartDate() 0 4 1
A getEndDate() 0 4 1
B containsDate() 0 10 5
B containsDateRange() 0 10 5
A overlapsDateRange() 0 4 1
A isBefore() 0 8 2
A isNow() 0 4 1
A isAfter() 0 8 2
A intersect() 0 11 4
A getShort() 0 4 1
A getLong() 0 4 1
A getAllDates() 0 19 4
A getDuration() 0 8 3
A __toString() 0 4 1
A __clone() 0 5 3

How to fix   Complexity   

Complex Class

Complex classes like DateRange 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 DateRange, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Arbor\Moment;
6
7
use Arbor\Moment\Comparator\DateTimeComparator;
8
use Arbor\Moment\Exception\InvalidArgumentException;
9
use Arbor\Moment\Formatter\DateRangeFormatter;
10
use Arbor\Moment\Formatter\FormatterInterface;
11
12
/**
13
 * Class DateRange
14
 *
15
 * @package Arbor\Moment
16
 * @author Igor Vuckovic <[email protected]>
17
 */
18
class DateRange
19
{
20
    /** @var DateTime */
21
    private $startDate;
22
23
    /** @var DateTime */
24
    private $endDate;
25
26
    /** @var FormatterInterface */
27
    private $formatter;
28
29
    /**
30
     * @param DateTime|null $startDate
31
     * @param DateTime|null $endDate
32
     * @throws \InvalidArgumentException
33
     */
34 18
    public function __construct(DateTime $startDate = null, DateTime $endDate = null)
35
    {
36 18
        $this->startDate = $startDate ? clone $startDate : null;
37 18
        $this->endDate = $endDate ? clone $endDate : null;
38
39 18
        if ($startDate && $endDate && $endDate < $startDate) {
40 1
            throw InvalidArgumentException::startDateNotBeforeEndDate($startDate, $endDate);
41
        }
42
43 17
        $this->formatter = new DateRangeFormatter($this);
44 17
    }
45
46
    /**
47
     * @return DateTime|null
48
     */
49 26
    public function getStartDate()
50
    {
51 26
        return $this->startDate;
52
    }
53
54
    /**
55
     * @return DateTime|null
56
     */
57 22
    public function getEndDate()
58
    {
59 22
        return $this->endDate;
60
    }
61
62
    /**
63
     * @param DateTime $date
64
     * @return bool
65
     */
66 8
    public function containsDate(DateTime $date) : bool
67
    {
68 8
        if ($this->startDate === null) {
69 3
            return $this->endDate === null || $this->endDate >= $date;
70 5
        } elseif ($this->endDate === null) {
71 2
            return $this->startDate <= $date;
72
        }
73
74 3
        return $this->startDate <= $date && $this->endDate >= $date;
75
    }
76
77
    /**
78
     * @param DateRange $dateRange
79
     * @return bool
80
     */
81 10
    public function containsDateRange(DateRange $dateRange) : bool
82
    {
83 10
        if ($this->startDate === null && $this->endDate === null) {
84 4
            return true;
85
        }
86
87 6
        return $this->startDate <= $dateRange->getStartDate()
88 6
            && $dateRange->getEndDate() !== null
89 6
            && $this->endDate >= $dateRange->getEndDate();
90
    }
91
92
    /**
93
     * @param DateRange $dateRange
94
     * @return bool
95
     */
96 6
    public function overlapsDateRange(DateRange $dateRange) : bool
97
    {
98 6
        return $this->intersect($dateRange) !== null;
99
    }
100
101
    /**
102
     * @param DateTime $date
103
     * @return bool
104
     */
105 5
    public function isBefore(DateTime $date) : bool
106
    {
107 5
        if ($this->endDate === null) {
108 1
            return false;
109
        }
110
111 4
        return $this->endDate <= $date;
112
    }
113
114
    /**
115
     * @return bool
116
     */
117 1
    public function isNow() : bool
118
    {
119 1
        return $this->containsDate(new DateTime());
120
    }
121
122
    /**
123
     * @param DateTime $date
124
     * @return bool
125
     */
126 5
    public function isAfter(DateTime $date) : bool
127
    {
128 5
        if ($this->startDate === null) {
129 1
            return false;
130
        }
131
132 4
        return $this->startDate >= $date;
133
    }
134
135
    /**
136
     * @param DateRange $dateRange
137
     * @return DateRange|null
138
     */
139 9
    public function intersect(DateRange $dateRange)
140
    {
141 9
        $latestStartDate = DateTimeComparator::getLatestDate($this->startDate, $dateRange->startDate);
142 9
        $earliestEndDate = DateTimeComparator::getEarliestDate($this->endDate, $dateRange->endDate);
143
144 9
        if ($latestStartDate && $earliestEndDate && ($latestStartDate >= $earliestEndDate)) {
145 2
            return null;
146
        }
147
148 7
        return new DateRange($latestStartDate, $earliestEndDate);
149
    }
150
151
    /**
152
     * @param string $nullPlaceholder
153
     * @return string
154
     */
155 10
    public function getShort(string $nullPlaceholder = 'Ongoing') : string
156
    {
157 10
        return $this->formatter->getShort($nullPlaceholder);
0 ignored issues
show
Unused Code introduced by
The call to FormatterInterface::getShort() has too many arguments starting with $nullPlaceholder.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
158
    }
159
160
    /**
161
     * @param string $nullPlaceholder
162
     * @return string
163
     */
164 21
    public function getLong(string $nullPlaceholder = 'Ongoing') : string
165
    {
166 21
        return $this->formatter->getLong($nullPlaceholder);
0 ignored issues
show
Unused Code introduced by
The call to FormatterInterface::getLong() has too many arguments starting with $nullPlaceholder.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
167
    }
168
169
    /**
170
     * @return DateTime[]
171
     * @throws InvalidArgumentException
172
     */
173 4
    public function getAllDates() : array
174
    {
175 4
        if ($this->getStartDate() === null || $this->getEndDate() === null) {
176 3
            throw InvalidArgumentException::dateRangeWithoutBoundaries();
177
        }
178
179 1
        $startDate = $this->startDate;
180 1
        $endDate = $this->endDate;
181 1
        $referenceDate = clone $startDate;
182 1
        $referenceDate->setDateType(DateTime::TYPE_DATE);
183
184 1
        $dates = [];
185 1
        while ($referenceDate <= $endDate) {
186 1
            $dates[$referenceDate->getUnixTimestamp()] = clone $referenceDate;
187 1
            $referenceDate->add(new \DateInterval('P1D'));
188
        }
189
190 1
        return array_values($dates);
191
    }
192
193
    /**
194
     * @return Time|null
195
     */
196 4
    public function getDuration()
197
    {
198 4
        if ($this->startDate && $this->endDate) {
199 1
            return Time::fromSeconds($this->endDate->getTimestamp() - $this->startDate->getTimestamp());
200
        }
201
202 3
        return null;
203
    }
204
205
    /**
206
     * @return string
207
     */
208 7
    public function __toString() : string
209
    {
210 7
        return $this->getLong();
211
    }
212
213
    /**
214
     *
215
     */
216 1
    public function __clone()
217
    {
218 1
        $this->startDate = ($this->startDate ? clone $this->startDate : null);
219 1
        $this->endDate = ($this->endDate ? clone $this->endDate : null);
220 1
    }
221
}
222