|
1
|
|
|
<?php |
|
2
|
|
|
declare(strict_types=1); |
|
3
|
|
|
|
|
4
|
|
|
namespace Nexendrie\Utils; |
|
5
|
|
|
|
|
6
|
|
|
use Nette\Utils\Arrays; |
|
7
|
|
|
|
|
8
|
|
|
/** |
|
9
|
|
|
* TCollection |
|
10
|
|
|
* Target class has to implement \ArrayAccess, \Countable, \IteratorAggregate interfaces |
|
11
|
|
|
* |
|
12
|
|
|
* @author Jakub Konečný |
|
13
|
|
|
*/ |
|
14
|
1 |
|
trait TCollection { |
|
15
|
|
|
protected $items = []; |
|
16
|
|
|
/** @var string Type of items in the collection */ |
|
17
|
|
|
protected $class; |
|
18
|
|
|
/** @var string|NULL */ |
|
19
|
|
|
protected $uniqueProperty = NULL; |
|
20
|
|
|
|
|
21
|
|
|
public function count(): int { |
|
22
|
1 |
|
return count($this->items); |
|
23
|
|
|
} |
|
24
|
|
|
|
|
25
|
|
|
public function getIterator(): \ArrayIterator { |
|
26
|
1 |
|
return new \ArrayIterator($this->items); |
|
27
|
|
|
} |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* @param int $index |
|
31
|
|
|
*/ |
|
32
|
|
|
public function offsetExists($index): bool { |
|
|
|
|
|
|
33
|
1 |
|
return $index >= 0 AND $index < count($this->items); |
|
34
|
|
|
} |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* @param int|NULL $index |
|
38
|
|
|
* @throws \OutOfRangeException |
|
39
|
|
|
*/ |
|
40
|
|
|
public function offsetGet($index) { |
|
41
|
1 |
|
if($index < 0 OR $index >= count($this->items)) { |
|
42
|
1 |
|
throw new \OutOfRangeException("Offset invalid or out of range."); |
|
43
|
|
|
} |
|
44
|
1 |
|
return $this->items[$index]; |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* @param object $newItem |
|
49
|
|
|
*/ |
|
50
|
|
|
protected function checkType($newItem): bool { |
|
|
|
|
|
|
51
|
1 |
|
return ($newItem instanceof $this->class); |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* @param object $newItem |
|
56
|
|
|
*/ |
|
57
|
|
|
protected function checkUniqueness($newItem): bool { |
|
|
|
|
|
|
58
|
1 |
|
if(is_null($this->uniqueProperty)) { |
|
59
|
1 |
|
return true; |
|
60
|
|
|
} |
|
61
|
1 |
|
return !Arrays::some($this->items, function($value) use($newItem) { |
|
62
|
1 |
|
return ($newItem->{$this->uniqueProperty} === $value->{$this->uniqueProperty}); |
|
63
|
1 |
|
}); |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* @param int|NULL $index |
|
68
|
|
|
* @param object $item |
|
69
|
|
|
* @throws \OutOfRangeException |
|
70
|
|
|
* @throws \InvalidArgumentException |
|
71
|
|
|
*/ |
|
72
|
|
|
public function offsetSet($index, $item): void { |
|
73
|
1 |
|
if(!$this->checkType($item)) { |
|
74
|
1 |
|
throw new \InvalidArgumentException("Argument must be of $this->class type."); |
|
75
|
1 |
|
} elseif(!$this->checkUniqueness($item)) { |
|
76
|
1 |
|
$property = $this->uniqueProperty; |
|
77
|
1 |
|
throw new \RuntimeException("Duplicate $property {$item->$property}."); |
|
78
|
|
|
} |
|
79
|
1 |
|
if($index === NULL) { |
|
80
|
1 |
|
$this->items[] = & $item; |
|
81
|
1 |
|
} elseif($index < 0 OR $index >= count($this->items)) { |
|
82
|
1 |
|
throw new \OutOfRangeException("Offset invalid or out of range."); |
|
83
|
|
|
} else { |
|
84
|
1 |
|
$this->items[$index] = & $item; |
|
85
|
|
|
} |
|
86
|
1 |
|
} |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* @param int $index |
|
90
|
|
|
* @throws \OutOfRangeException |
|
91
|
|
|
*/ |
|
92
|
|
|
public function offsetUnset($index): void { |
|
93
|
1 |
|
if($index < 0 OR $index >= count($this->items)) { |
|
94
|
1 |
|
throw new \OutOfRangeException("Offset invalid or out of range."); |
|
95
|
|
|
} |
|
96
|
1 |
|
array_splice($this->items, $index, 1); |
|
97
|
1 |
|
} |
|
98
|
|
|
} |
|
99
|
|
|
?> |
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.