Passed
Push — feature/issue-272 ( 82ab60 )
by Mikaël
03:20
created

AbstractObjectContainer   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Test Coverage

Coverage 97.83%

Importance

Changes 4
Bugs 0 Features 1
Metric Value
wmc 23
eloc 43
c 4
b 0
f 1
dl 0
loc 147
ccs 45
cts 46
cp 0.9783
rs 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A offsetExists() 0 5 1
A add() 0 6 1
A getObjectKey() 0 13 3
A jsonSerialize() 0 3 1
A valid() 0 3 1
A beforeObjectIsStored() 0 6 2
A get() 0 7 4
A offsetSet() 0 4 1
A key() 0 4 1
A count() 0 4 1
A offsetUnset() 0 5 2
A rewind() 0 4 1
A next() 0 4 1
A current() 0 6 1
A offsetGet() 0 6 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace WsdlToPhp\PackageGenerator\Container;
6
7
use ArrayAccess;
8
use Countable;
9
use InvalidArgumentException;
10
use Iterator;
11
use JsonSerializable;
12
use WsdlToPhp\PackageGenerator\Generator\AbstractGeneratorAware;
13
14
abstract class AbstractObjectContainer extends AbstractGeneratorAware implements ArrayAccess, Iterator, Countable, JsonSerializable
15
{
16
    public const PROPERTY_NAME = 'name';
17
18
    protected array $objects = [];
19
20
    protected int $offset = 0;
21
22 20
    public function offsetExists($offset): bool
23
    {
24 20
        $element = array_slice($this->objects, $offset, 1);
25
26 20
        return !empty($element);
27
    }
28
29
    /**
30
     * @param mixed $offset
31
     *
32
     * @return mixed
33
     */
34 20
    #[\ReturnTypeWillChange]
35
    public function offsetGet($offset)
36
    {
37 20
        $element = array_slice($this->objects, $offset, 1);
38
39 20
        return $this->offsetExists($offset) ? array_shift($element) : null;
40
    }
41
42
    /**
43
     * @param mixed $offset
44
     * @param mixed $value
45
     *
46
     * @return mixed
47
     */
48 2
    #[\ReturnTypeWillChange]
49
    public function offsetSet($offset, $value)
50
    {
51 2
        throw new InvalidArgumentException('This method can\'t be used as object are stored with a string as array index', __LINE__);
52
    }
53
54 2
    #[\ReturnTypeWillChange]
55
    public function offsetUnset($offset): void
56
    {
57 2
        if ($this->offsetExists($offset)) {
58 2
            unset($this->objects[$this->getObjectKey($this->offsetGet($offset))]);
59
        }
60
    }
61
62
    /**
63
     * @return mixed
64
     */
65 320
    #[\ReturnTypeWillChange]
66
    public function current()
67
    {
68 320
        $current = array_slice($this->objects, $this->offset, 1);
69
70 320
        return array_shift($current);
71
    }
72
73 320
    #[\ReturnTypeWillChange]
74
    public function next(): void
75
    {
76 320
        ++$this->offset;
77
    }
78
79 104
    #[\ReturnTypeWillChange]
80
    public function key(): int
81
    {
82 104
        return $this->offset;
83
    }
84
85 354
    public function valid(): bool
86
    {
87 354
        return 0 < count(array_slice($this->objects, $this->offset, 1));
88
    }
89
90 354
    #[\ReturnTypeWillChange]
91
    public function rewind(): void
92
    {
93 354
        $this->offset = 0;
94
    }
95
96 340
    #[\ReturnTypeWillChange]
97
    public function count(): int
98
    {
99 340
        return count($this->objects);
100
    }
101
102 562
    public function add(object $object): self
103
    {
104 562
        $this->beforeObjectIsStored($object);
105 550
        $this->objects[$this->getObjectKey($object)] = $object;
106
107 548
        return $this;
108
    }
109
110 556
    public function get($value)
111
    {
112 556
        if (!is_scalar($value)) {
113 2
            throw new InvalidArgumentException(sprintf('Value "%s" can\'t be used to get an object from "%s"', is_object($value) ? get_class($value) : var_export($value, true), get_class($this)), __LINE__);
114
        }
115
116 554
        return array_key_exists($value, $this->objects) ? $this->objects[$value] : null;
117
    }
118
119 4
    public function jsonSerialize(): array
120
    {
121 4
        return array_values($this->objects);
122
    }
123
124
    /**
125
     * Must return the object class name that this container is made to contain.
126
     */
127
    abstract protected function objectClass(): string;
128
129
    /**
130
     * Must return the object's property name that this container is using to store the object.
131
     */
132
    abstract protected function objectProperty(): string;
133
134
    /**
135
     * This method is called before the object has been stored.
136
     *
137
     * @throws InvalidArgumentException
138
     */
139 562
    protected function beforeObjectIsStored(object $object): void
140
    {
141 562
        $objectClass = $this->objectClass();
142
143 562
        if (!$object instanceof $objectClass) {
144 12
            throw new InvalidArgumentException(sprintf('Model of type "%s" does not match the object contained by this class: "%s"', get_class($object), $objectClass), __LINE__);
145
        }
146
    }
147
148 550
    protected function getObjectKey(object $object)
149
    {
150 550
        $get = sprintf('get%s', ucfirst($this->objectProperty()));
151 550
        if (!method_exists($object, $get)) {
152 2
            throw new InvalidArgumentException(sprintf('Method "%s" is required in "%s" in order to be stored in "%s"', $get, get_class($object), get_class($this)), __LINE__);
153
        }
154
155 548
        $key = $object->{$get}();
156 548
        if (!is_scalar($key)) {
157
            throw new InvalidArgumentException(sprintf('Property "%s" of "%s" must be scalar, "%s" returned', $this->objectProperty(), get_class($object), gettype($key)), __LINE__);
158
        }
159
160 548
        return $key;
161
    }
162
}
163