Range::offsetUnset()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
/**
3
 * Copyright (c) 2018 Mattheu Racine
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace mracine\IPTools\IPv4;
10
11
use OutOfBoundsException;
12
use InvalidArgumentException;
13
use BadMethodCallException;
14
15
use mracine\IPTools\Iterators\RangeIterator;
16
use mracine\IPTools\IPv4\Address;
17
use mracine\IPTools\IPVersion;
18
19
/**
20
 * Represents a range of IPv4 addresses
21
 *
22
 * A range of IPv4 address are consecutives addresses
23
 *
24
 * A range implements :
25
 *  * Countable : number of addresses
26
 *  * ArrayAccess : Address can be acceesed by offset (ex : $range[10])
27
 *  * IteratorAggregate :   range can be itrated (foreach)
28
 * 
29
 * @package IPTools
30
 */
31
32
class Range implements IPVersion, \Countable, \ArrayAccess, \IteratorAggregate
33
{
34
35
    /**
36
     * @var Address $baseAddress The first address of the range
37
     */
38
    protected $baseAddress;
39
40
    /**
41
     * @var Address upperBound The last address of the range
42
     */
43
    // private $upperBound;
44
    /**
45
     * @var int $count the address count in the range
46
     */
47
    protected $count;
48
49
    use IPv4;
50
51
    /**
52
     * Creates an IP range from a couple of IP addresses
53
     *
54
     * Lower and upper bound are automaticly choosen, no need to choose wich one to pas first.
55
     *
56
     * @param Address $baseAddress the first address of the range
57
     * @param int $count the number  other bound
58
     */
59 7
    public function __construct(Address $lowerBound, Address $upperBound)
60
    {
61 7
        $lower = $lowerBound->int();
62 7
        $upper = $upperBound->int();
63 7
        if ($lower > $upper)
64
        {
65 2
            $temp = $lower;
66 2
            $lower = $upper;
67 2
            $upper = $temp;
68
        }
69 7
        $this->baseAddress = new Address($lower);
70 7
        $this->count = $upper - $lower + 1;
71 7
    } 
72
73
    /**
74
     * Returns an Range object from a base Address and a count of Addresses in the range 
75
     *
76
     * Negative count values rearange the lower bound Address
77
     * @param Address $baseAddress the lower bound
78
     * @param int $count the number of addresses in the Range
79
     * @return self
80
     */
81 9
    public static function fromCount(Address $baseAddress, int $count)
82
    {
83 9
        if ($count == 0)
84
        {
85 1
            throw new InvalidArgumentException("Cannot assign a range of 0 addresses");
86
        }
87 8
        if ($count<0)
88
        {
89 4
            $delta = $count+1;
90
        }
91
        else
92
        {
93 4
            $delta = $count-1;
94
        }
95 8
        $upperBound = $baseAddress->shift($delta);
96 8
        return new static($baseAddress, $upperBound);
97
    }
98
99
100
    /**
101
     * Get the first address of the range
102
     *
103
     * NOTICE : The returned address is a newly created address instance.
104
     * 
105
     * @return Address
106
     */
107 3
    public function getLowerBound()
108
    {
109 3
        return clone($this->baseAddress);
110
    }
111
112
    /**
113
     * Returns the last address of the range
114
     *
115
     * NOTICE : The returned address is a newly created address instance.   
116
     *
117
     * @return Address
118
     */
119 3
    public function getUpperBound()
120
    {
121 3
        return new Address($this->getLowerBound()->int()+$this->count-1);
122
    }
123
124
    /**
125
     * Tells if an address is contained in the range
126
     *
127
     * Return true if the provided address is between the boundaries of the range.  
128
     *
129
     * @deprecated Use Address::isIn
130
     * @see Address::isIn
131
     * @param Address $ip
132
     * @return bool
133
     */
134 12
    public function contains(Address $ip)
135
    {
136 12
        return $ip->isIn($this);
137
    }
138
139
    /**
140
     * Tells if the range is contained in an other range
141
     *
142
     * Return true if the provided address is between the boundaries of the range.  
143
     *
144
     * @param Address $ip 
145
     * @return bool
146
     */
147 8
    public function isIn(Range $container)
148
    {
149 8
        return ($container->getLowerBound()->int()<=$this->getLowerBound()->int()) && ($this->getUpperBound()->int()<=$container->getUpperBound()->int());
150
    }
151
152
153
154
    /**
155
     * Tells if two ranges are equals (sames boundaries)
156
     *
157
     * Return true if the provided range is the same as this one.  
158
     *
159
     * @param Range $range 
160
     * @return bool
161
     */
162 4
    public function match(Range $range)
163
    {
164 4
        return ( ($this->getLowerBound()->int()==$range->getLowerBound()->int()) && ($this->getUpperBound()->int()==$range->getUpperBound()->int()));
165
    }
166
167
    /**
168
     * Return the number of Addresses in the range (including boundaries)
169
     *
170
     * @return int
171
     */
172 4
    public function count()
173
    {
174 4
        return $this->count; 
175
    }
176
177
    /**
178
     * Returns a range shifted by an amount of units (count)
179
     *
180
     * Need explain...
181
     *
182
     * @param int $offset
183
     * @throws OutOfBounsException when the resulting subet is invalid
184
     * @return Subnet
185
     */  
186 1
    public function shift(int $offset)
187
    {
188 1
        return static::fromCount($this->getLowerBound()->shift($offset*count($this)), count($this));
189
    }
190
191
    /**
192
     * Returns a subnet with the same netmask having network addres one more than broadcast address of the original subnet ($this)
193
     *
194
     * Need explain...
195
     *
196
     * @param int $offset
197
     * @throws OutOfBounsException when the resulting subet is invalid (when braodcast address of self = 255.255.255.255)
198
     * @return Subnet
199
     */  
200 1
    public function next()
201
    {
202 1
        return $this->shift(1);
203
    }
204
205
    /**
206
     * Returns a subnet with the same netmask having broacast addres one less than network address of the original subnet ($this)
207
     *
208
     * Need explain...
209
     *
210
     * @param int $offset
211
     * @throws OutOfBounsException when the resulting subet is invalid (when braodcast address of self = 255.255.255.255)
212
     * @return Subnet
213
     */  
214 1
    public function previous()
215
    {
216 1
        return $this->shift(-1);
217
    }
218
219
    /*
220
     * interface ArrayAccess
221
     */
222
223
    /**
224
     * Checks if there is an Address at the given index within the Range.
225
     *
226
     * @param int|string $offset address index
227
     * @throws InvalidArgumentException when $offset is not an integer
228
     * @return boolean
229
     */
230 12
    public function offsetExists($offset)
231
    {
232 12
         if (is_string($offset))
233
        {
234 2
            if (!preg_match('/^-?[0-9]+$/', $offset))
235
            {
236 1
                throw new InvalidArgumentException(sprintf('Invalid key type (%s), only integers or strings representing integers can be used to acces address in a Range', gettype($offset)));
237
            }           
238 1
            $offset = (int)$offset;
239
        }
240 11
       if (!is_int($offset))
241
        {
242 3
            throw new InvalidArgumentException(sprintf('Invalid key type (%s), only integers or strings representing integers can be used to acces address in a Range', gettype($offset)));
243
        }
244 8
        if ($offset<0 || $offset>=count($this))
245
        {
246 4
            return false;
247
        }
248 4
        return true;
249
    }
250
251
    /**
252
     * Return the Address at the given index within the Range.
253
     *
254
     * NOTICE : a fresh instance of Address is returned each time the method is called
255
     *
256
     * @param int $offset address index
257
     * @throws InvalidArgumentException when $offset is not an integer
258
     * @throws OutOfBoundsException when $offset is negative or is greater than range size
259
     * @return Address a fresh instance that represents the address at $offset  
260
     */
261 5
    public function offsetGet($offset)
262
    {
263 5
        if (!$this->offsetExists($offset))
264
        {
265 1
            throw new OutOfBoundsException();
266
        }
267
268 5
        return $this->getLowerBound()->shift($offset);
269
    }
270
271
    /**
272
     * Set the value of the address at a particular offset in a Range
273
     *
274
     * Unsupported : non-sense
275
     *
276
     * @param int $offset
277
     * @param Address $value
278
     * @throws BadMethodCallException always
279
     */ 
280 1
    public function offsetSet($offset,  $value)
281
    {
282 1
        throw new BadMethodCallException(sprintf("class %s is immutable, cannot modify an address value in a Range", self::class));
283
    }
284
    
285
    /**
286
     * Remove an address at a particular offset in a range
287
     *
288
     * Unsupported : non-sense
289
     *
290
     * @param int $offset
291
     * @throws BadMethodCallException always
292
     */ 
293 1
    public function offsetUnset($offset)
294
    {
295 1
        throw new BadMethodCallException(sprintf("class %s is immutable, cannot unset an address value in a Range", self::class));
296
    }
297
298
    /*
299
     * interface IteratorAggregate
300
     */
301
302
    /**
303
     * Obtain an iterator to traverse the range
304
     *
305
     * Allows to iterate in the range (foreach ($subnet as $address) {...} )
306
     *
307
     * @return RangeIterator
308
     */
309
310 1
    public function getIterator()
311
    {
312 1
        return new RangeIterator($this);
313
    }
314
}
315