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

NumberInterval::withEnd()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 4
Ratio 100 %

Importance

Changes 0
Metric Value
dl 4
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\Number;
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 View Code Duplication
class NumberInterval implements ComparableIntervalInterface
0 ignored issues
show
Duplication introduced by
This class seems to be duplicated in your project.

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.

Loading history...
20
{
21
    /**
22
     * @var string
23
     */
24
    const REGEXP = '/^
25
        (?:\(|\[)        # start type char
26
        \s*
27
        (?<start>\-?\d+) # start point
28
        \s*,\s*          # separator
29
        (?<end>\-?\d+)   # 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 NumberIntervalPoint
46
     */
47
    private $start;
48
49
    /**
50
     * @var NumberIntervalPoint
51
     */
52
    private $end;
53
54
    /**
55
     * @param NumberIntervalPoint $start
56
     * @param NumberIntervalPoint $end
57
     * @param IntervalType $type
58
     */
59
    private function __construct(NumberIntervalPoint $start, NumberIntervalPoint $end, IntervalType $type)
60
    {
61
        if ($start->gte($end)) {
62
            throw IncorrectIntervalException::create();
63
        }
64
65
        $this->start = $start;
66
        $this->end = $end;
67
        $this->type = $type;
68
        $this->comparator = new IntervalComparator($this);
69
    }
70
71
    /**
72
     * @param int|float $start
73
     * @param int|float $end
74
     * @param IntervalType $type
75
     *
76
     * @return self
77
     */
78
    public static function create($start, $end, IntervalType $type)
79
    {
80
        return new self(new NumberIntervalPoint($start), new NumberIntervalPoint($end), $type);
81
    }
82
83
    /**
84
     * @param int|float $start
85
     * @param int|float $end
86
     *
87
     * @return self
88
     */
89
    public static function closed($start, $end)
90
    {
91
        return self::create($start, $end, IntervalType::closed());
92
    }
93
94
    /**
95
     * @param int|float $start
96
     * @param int|float $end
97
     *
98
     * @return self
99
     */
100
    public static function halfClosed($start, $end)
101
    {
102
        return self::create($start, $end, IntervalType::halfClosed());
103
    }
104
105
    /**
106
     * @param int|float $start
107
     * @param int|float $end
108
     *
109
     * @return self
110
     */
111
    public static function halfOpen($start, $end)
112
    {
113
        return self::create($start, $end, IntervalType::halfOpen());
114
    }
115
116
    /**
117
     * @param int|float $start
118
     * @param int|float $end
119
     *
120
     * @return self
121
     */
122
    public static function open($start, $end)
123
    {
124
        return self::create($start, $end, IntervalType::open());
125
    }
126
127
    /**
128
     * Create interval from string.
129
     *
130
     * Example formats:
131
     *   [0, 5]
132
     *   (-3, 2]
133
     *   [-3, -1)
134
     *   (3, 9)
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('[N, N]', $string);
146
        }
147
148
        return self::create($match['start'], $match['end'], IntervalType::fromString($string));
149
    }
150
151
    /**
152
     * @param int|float $point
153
     *
154
     * @return bool
155
     */
156
    public function contains($point)
157
    {
158
        return $this->comparator->contains(new NumberIntervalPoint($point));
159
    }
160
161
    /**
162
     * @param NumberInterval $interval
163
     * @param bool $check_interval_type
164
     *
165
     * @return bool
166
     */
167
    public function intersects(NumberInterval $interval, $check_interval_type = true)
168
    {
169
        return $this->comparator->intersects($interval, $check_interval_type);
170
    }
171
172
    /**
173
     * @param NumberInterval $interval
174
     *
175
     * @return NumberInterval|null
176
     */
177
    public function intersection(NumberInterval $interval)
178
    {
179
        return $this->comparator->intersection($interval);
180
    }
181
182
    /**
183
     * The point is before the interval
184
     *
185
     * @param int|float $point
186
     *
187
     * @return bool
188
     */
189
    public function before($point)
190
    {
191
        return $this->comparator->before(new NumberIntervalPoint($point));
192
    }
193
194
    /**
195
     * The point is after the interval
196
     *
197
     * @param int|float $point
198
     *
199
     * @return bool
200
     */
201
    public function after($point)
202
    {
203
        return $this->comparator->after(new NumberIntervalPoint($point));
204
    }
205
206
    /**
207
     * @return IntervalType
208
     */
209
    public function type()
210
    {
211
        return $this->type;
212
    }
213
214
    /**
215
     * @return int|float
216
     */
217
    public function start()
218
    {
219
        return $this->start->value();
220
    }
221
222
    /**
223
     * @return int|float
224
     */
225
    public function end()
226
    {
227
        return $this->end->value();
228
    }
229
230
    /**
231
     * @return NumberIntervalPoint
232
     */
233
    public function startPoint()
234
    {
235
        return $this->start;
236
    }
237
238
    /**
239
     * @return NumberIntervalPoint
240
     */
241
    public function endPoint()
242
    {
243
        return $this->end;
244
    }
245
246
    /**
247
     * Returns a copy of this Interval with the start point altered.
248
     *
249
     * @param IntervalPointInterface|NumberIntervalPoint $start
250
     *
251
     * @return self
252
     */
253
    public function withStart(IntervalPointInterface $start)
254
    {
255
        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\...er\NumberIntervalPoint>. 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...
256
    }
257
258
    /**
259
     * Returns a copy of this Interval with the end point altered.
260
     *
261
     * @param IntervalPointInterface|NumberIntervalPoint $end
262
     *
263
     * @return self
264
     */
265
    public function withEnd(IntervalPointInterface $end)
266
    {
267
        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\...er\NumberIntervalPoint>. 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...
268
    }
269
270
    /**
271
     * Returns a copy of this Interval with the interval type altered.
272
     *
273
     * @param IntervalType $type
274
     *
275
     * @return self
276
     */
277
    public function withType(IntervalType $type)
278
    {
279
        return new self($this->start, $this->end, $type);
280
    }
281
282
    /**
283
     * @return string
284
     */
285
    public function __toString()
286
    {
287
        return $this->type->getReadable($this);
288
    }
289
}
290