Completed
Push — master ( 16c929...217223 )
by Peter
06:17
created

YearInterval::withEnd()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php 
2
/**
3
 * GpsLab component.
4
 *
5
 * @author    Peter Gribanov <[email protected]>
6
 * @copyright Copyright (c) 2016, Peter Gribanov
7
 * @license   http://opensource.org/licenses/MIT
8
 */
9
10
namespace GpsLab\Component\Interval\Year;
11
12
use GpsLab\Component\Interval\Exception\IncorrectIntervalException;
13
use GpsLab\Component\Interval\Exception\InvalidIntervalFormatException;
14
use GpsLab\Component\Interval\IntervalComparator;
15
use GpsLab\Component\Interval\ComparableIntervalInterface;
16
use GpsLab\Component\Interval\IntervalPointInterface;
17
use GpsLab\Component\Interval\IntervalType;
18
19
class YearInterval implements ComparableIntervalInterface
20
{
21
    /**
22
     * @var string
23
     */
24
    const REGEXP = '/^
25
        (?:\(|\[)       # start type char
26
        \s*
27
        (?<start>\d{4}) # start point
28
        \s*,\s*         # separator
29
        (?<end>\d{4})   # end point
30
        \s*
31
        (?:\)|\])       # end type char
32
    $/x';
33
34
    /**
35
     * @var IntervalType
36
     */
37
    private $type;
38
39
    /**
40
     * @var IntervalComparator
41
     */
42
    private $comparator;
43
44
    /**
45
     * @var YearIntervalPoint
46
     */
47
    private $start;
48
49
    /**
50
     * @var YearIntervalPoint
51
     */
52
    private $end;
53
54
    /**
55
     * @param YearIntervalPoint $start
56
     * @param YearIntervalPoint $end
57
     * @param IntervalType $type
58
     */
59
    private function __construct(YearIntervalPoint $start, YearIntervalPoint $end, IntervalType $type)
60
    {
61
        if ($start->gte($end)) {
62
            throw IncorrectIntervalException::create();
63
        }
64
65
        $this->type = $type;
66
        $this->start = $start;
67
        $this->end = $end;
68
        $this->comparator = new IntervalComparator($this);
69
    }
70
71
    /**
72
     * @param \DateTime $start
73
     * @param \DateTime $end
74
     * @param IntervalType $type
75
     *
76
     * @return self
77
     */
78
    public static function create(\DateTime $start, \DateTime $end, IntervalType $type)
79
    {
80
        return new self(new YearIntervalPoint($start), new YearIntervalPoint($end), $type);
81
    }
82
83
    /**
84
     * @param \DateTime $start
85
     * @param \DateTime $end
86
     *
87
     * @return self
88
     */
89
    public static function closed(\DateTime $start, \DateTime $end)
90
    {
91
        return static::create($start, $end, IntervalType::closed());
92
    }
93
94
    /**
95
     * @param \DateTime $start
96
     * @param \DateTime $end
97
     *
98
     * @return self
99
     */
100
    public static function halfClosed(\DateTime $start, \DateTime $end)
101
    {
102
        return static::create($start, $end, IntervalType::halfClosed());
103
    }
104
105
    /**
106
     * @param \DateTime $start
107
     * @param \DateTime $end
108
     *
109
     * @return self
110
     */
111
    public static function halfOpen(\DateTime $start, \DateTime $end)
112
    {
113
        return static::create($start, $end, IntervalType::halfOpen());
114
    }
115
116
    /**
117
     * @param \DateTime $start
118
     * @param \DateTime $end
119
     *
120
     * @return self
121
     */
122
    public static function open(\DateTime $start, \DateTime $end)
123
    {
124
        return static::create($start, $end, IntervalType::open());
125
    }
126
127
    /**
128
     * Create interval from string.
129
     *
130
     * Example formats for all interval types:
131
     *   [2016, 2017]
132
     *   (2015, 2016]
133
     *   [2014, 2015)
134
     *   (2013, 2014)
135
     *
136
     * Spaces are ignored in format.
137
     *
138
     * @param string $string
139
     *
140
     * @return self
141
     */
142
    public static function fromString($string)
143
    {
144
        if (!preg_match(self::REGEXP, $string, $match)) {
145
            throw InvalidIntervalFormatException::create('[YYYY, YYYY]', $string);
146
        }
147
148
        return self::create(
149
            (new \DateTime())->setDate($match['start'], 1, 1),
150
            (new \DateTime())->setDate($match['end'], 1, 1),
151
            IntervalType::fromString($string)
152
        );
153
    }
154
155
    /**
156
     * @param \DateTime $point
157
     *
158
     * @return bool
159
     */
160
    public function contains(\DateTime $point)
161
    {
162
        return $this->comparator->contains(new YearIntervalPoint($point));
163
    }
164
165
    /**
166
     * @param YearInterval $interval
167
     * @param bool $check_interval_type
168
     *
169
     * @return bool
170
     */
171
    public function intersects(YearInterval $interval, $check_interval_type = true)
172
    {
173
        return $this->comparator->intersects($interval, $check_interval_type);
174
    }
175
176
    /**
177
     * @param YearInterval $interval
178
     *
179
     * @return YearInterval|null
180
     */
181
    public function intersection(YearInterval $interval)
182
    {
183
        return $this->comparator->intersection($interval);
184
    }
185
186
    /**
187
     * The point is before the interval
188
     *
189
     * @param \DateTime $point
190
     *
191
     * @return bool
192
     */
193
    public function before(\DateTime $point)
194
    {
195
        return $this->comparator->before(new YearIntervalPoint($point));
196
    }
197
198
    /**
199
     * The point is after the interval
200
     *
201
     * @param \DateTime $point
202
     *
203
     * @return bool
204
     */
205
    public function after(\DateTime $point)
206
    {
207
        return $this->comparator->after(new YearIntervalPoint($point));
208
    }
209
210
    /**
211
     * @return IntervalType
212
     */
213
    public function type()
214
    {
215
        return $this->type;
216
    }
217
218
    /**
219
     * @return \DateTime
220
     */
221
    public function start()
222
    {
223
        return $this->start->value();
224
    }
225
226
    /**
227
     * @return \DateTime
228
     */
229
    public function end()
230
    {
231
        return $this->end->value();
232
    }
233
234
    /**
235
     * @return YearIntervalPoint
236
     */
237
    public function startPoint()
238
    {
239
        return $this->start;
240
    }
241
242
    /**
243
     * @return YearIntervalPoint
244
     */
245
    public function endPoint()
246
    {
247
        return $this->end;
248
    }
249
250
    /**
251
     * Returns a copy of this Interval with the start point altered.
252
     *
253
     * @param IntervalPointInterface|YearIntervalPoint $start
254
     *
255
     * @return self
256
     */
257
    public function withStart(IntervalPointInterface $start)
258
    {
259
        return new self($start, $this->end, $this->type);
0 ignored issues
show
Compatibility introduced by
$start of type object<GpsLab\Component\...IntervalPointInterface> is not a sub-type of object<GpsLab\Component\...Year\YearIntervalPoint>. It seems like you assume a concrete implementation of the interface GpsLab\Component\Interval\IntervalPointInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
260
    }
261
262
    /**
263
     * Returns a copy of this Interval with the end point altered.
264
     *
265
     * @param IntervalPointInterface|YearIntervalPoint $end
266
     *
267
     * @return self
268
     */
269
    public function withEnd(IntervalPointInterface $end)
270
    {
271
        return new self($this->start, $end, $this->type);
0 ignored issues
show
Compatibility introduced by
$end of type object<GpsLab\Component\...IntervalPointInterface> is not a sub-type of object<GpsLab\Component\...Year\YearIntervalPoint>. It seems like you assume a concrete implementation of the interface GpsLab\Component\Interval\IntervalPointInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
272
    }
273
274
    /**
275
     * Returns a copy of this Interval with the interval type altered.
276
     *
277
     * @param IntervalType $type
278
     *
279
     * @return self
280
     */
281
    public function withType(IntervalType $type)
282
    {
283
        return new self($this->start, $this->end, $type);
284
    }
285
286
    /**
287
     * @return string
288
     */
289
    public function __toString()
290
    {
291
        return $this->type->getReadable($this);
292
    }
293
}
294