Completed
Push — master ( d26279...002333 )
by Jakub
01:52
created

TCollection::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Nexendrie\Utils;
5
6
/**
7
 * TCollection
8
 * Target class has to implement \ArrayAccess, \Countable, \IteratorAggregate interfaces
9
 *
10
 * @author Jakub Konečný
11
 */
12 1
trait TCollection {
13
  protected $items = [];
14
  /** @var string Type of items in the collection */
15
  protected $class;
16
  /** @var string|NULL */
17
  protected $uniqueProperty = NULL;
18
  /** @var int */
19
  protected $maxSize = 0;
20
  /** @var bool */
21
  protected $locked = false;
22
  /** @var callable[] */
23
  protected $checkers = [];
24
  
25
  public function __construct() {
26 1
    $this->addChecker([$this, "checkLock"]);
27 1
    $this->addChecker([$this, "checkType"]);
28 1
    $this->addChecker([$this, "checkUniqueness"]);
29 1
    $this->addChecker([$this, "checkSize"]);
30 1
  }
31
  
32
  public function isLocked(): bool {
33 1
    return $this->locked;
34
  }
35
  
36
  public function lock(): void {
37 1
    $this->locked = true;
38 1
  }
39
  
40
  public function count(): int {
41 1
    return count($this->items);
42
  }
43
  
44
  public function getIterator(): \ArrayIterator {
45 1
    return new \ArrayIterator($this->items);
46
  }
47
  
48
  /**
49
   * @param int $index
50
   */
51
  public function offsetExists($index): bool {
52 1
    return $index >= 0 AND $index < count($this->items);
53
  }
54
  
55
  /**
56
   * @param int|NULL $index
57
   * @throws \OutOfRangeException
58
   */
59
  public function offsetGet($index) {
60 1
    if($index < 0 OR $index >= count($this->items)) {
61 1
      throw new \OutOfRangeException("Offset invalid or out of range.");
62
    }
63 1
    return $this->items[$index];
64
  }
65
  
66
  public function addChecker(callable $checker): void {
67 1
    $this->checkers[] = $checker;
68 1
  }
69
  
70
  /**
71
   * @param object $newItem
72
   */
73
  protected function checkLock($newItem, self $collection): void {
1 ignored issue
show
introduced by
The method parameter $newItem is never used
Loading history...
74 1
    if($collection->locked) {
75 1
      throw new \RuntimeException("Cannot add items to locked collection.");
76
    }
77 1
  }
78
  
79
  /**
80
   * @param object $newItem
81
   */
82
  protected function checkType($newItem, self $collection): void {
83 1
    if(!$newItem instanceof $collection->class) {
84 1
      throw new \InvalidArgumentException("Argument must be of $this->class type.");
85
    }
86 1
  }
87
  
88
  /**
89
   * @param object $newItem
90
   */
91
  protected function checkUniqueness($newItem, self $collection): void {
92 1
    $uniqueProperty = $collection->uniqueProperty;
93 1
    if(is_null($uniqueProperty)) {
94 1
      return;
95
    }
96 1
    foreach($collection->items as $item) {
97 1
      if($newItem->$uniqueProperty === $item->$uniqueProperty) {
98 1
        throw new \RuntimeException("Duplicate $uniqueProperty {$item->$uniqueProperty}.");
99
      }
100
    }
101 1
  }
102
  
103
  /**
104
   * @param object $newItem
105
   */
106
  protected function checkSize($newItem, self $collection): void {
1 ignored issue
show
introduced by
The method parameter $newItem is never used
Loading history...
107 1
    if($collection->maxSize < 1) {
108 1
      return;
109
    }
110 1
    if($collection->count() + 1 > $collection->maxSize) {
111 1
      throw new \RuntimeException("Collection reached its max size. Cannot add more items.");
112
    }
113 1
  }
114
  
115
  /**
116
   * @param object $item
117
   */
118
  protected function performChecks($item): void {
119 1
    foreach($this->checkers as $checker) {
120 1
      call_user_func($checker, $item, $this);
121
    }
122 1
  }
123
  
124
  /**
125
   * @param int|NULL $index
126
   * @param object $item
127
   * @throws \OutOfRangeException
128
   * @throws \InvalidArgumentException
129
   * @throws \RuntimeException
130
   */
131
  public function offsetSet($index, $item): void {
132 1
    $this->performChecks($item);
133 1
    if($index === NULL) {
134 1
      $this->items[] = & $item;
135 1
    } elseif($index < 0 OR $index >= count($this->items)) {
136 1
      throw new \OutOfRangeException("Offset invalid or out of range.");
137
    } else {
138 1
      $this->items[$index] = & $item;
139
    }
140 1
  }
141
  
142
  /**
143
   * @param int $index
144
   * @throws \OutOfRangeException
145
   */
146
  public function offsetUnset($index): void {
147 1
    if($this->locked) {
148 1
      throw new \RuntimeException("Cannot remove items from locked collection.");
149 1
    } elseif($index < 0 OR $index >= count($this->items)) {
150 1
      throw new \OutOfRangeException("Offset invalid or out of range.");
151
    }
152 1
    array_splice($this->items, $index, 1);
153 1
  }
154
  
155
  public function toArray(): array {
156 1
    return $this->items;
157
  }
158
}
159
?>