1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Nip\Collections\Typed; |
4
|
|
|
|
5
|
|
|
use Nip\Collections\Exceptions\InvalidTypeException; |
6
|
|
|
use TypeError; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Trait AbstractTypedCollectionTrait |
10
|
|
|
* @package Nip\Collections\Typed |
11
|
|
|
*/ |
12
|
|
|
trait TypedCollectionTrait |
13
|
|
|
{ |
14
|
|
|
protected $type; |
15
|
|
|
protected $typeChecker; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @inheritDoc |
19
|
|
|
*/ |
20
|
27 |
|
public function offsetSet($offset, $value) |
21
|
|
|
{ |
22
|
27 |
|
$this->validateItem($value); |
23
|
13 |
|
parent::offsetSet($offset, $value); |
24
|
13 |
|
} |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @inheritDoc |
28
|
|
|
*/ |
29
|
27 |
|
public function unshift($value, $key = null) |
30
|
|
|
{ |
31
|
27 |
|
$this->validateItem($value); |
32
|
13 |
|
parent::unshift($value, $key); |
33
|
13 |
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @param mixed $type |
37
|
|
|
*/ |
38
|
|
|
public function setType($type): void |
39
|
|
|
{ |
40
|
|
|
if (is_string($type)) { |
41
|
|
|
$this->type = $type; |
42
|
|
|
switch (strtolower($type)) { |
43
|
|
|
case 'string': |
44
|
|
|
case 'text': |
45
|
|
|
$this->type = StringCollection::TYPE; |
46
|
|
|
$this->typeChecker = StringCollection::CHECKER; |
47
|
|
|
break; |
48
|
|
|
case 'double': |
49
|
|
|
case 'float': |
50
|
|
|
$this->type = FloatCollection::TYPE; |
51
|
|
|
$this->typeChecker = FloatCollection::CHECKER; |
52
|
|
|
break; |
53
|
|
|
case 'array': |
54
|
|
|
$this->type = ArrayCollection::TYPE; |
55
|
|
|
$this->typeChecker = ArrayCollection::CHECKER; |
56
|
|
|
break; |
57
|
|
|
case 'resource': |
58
|
|
|
case 'resource (closed)': |
59
|
|
|
$this->type = ResourceCollection::TYPE; |
60
|
|
|
$this->typeChecker = ResourceCollection::CHECKER; |
61
|
|
|
break; |
62
|
|
|
case 'integer': |
63
|
|
|
case 'int': |
64
|
|
|
$this->type = IntCollection::TYPE; |
65
|
|
|
$this->typeChecker = IntCollection::CHECKER; |
66
|
|
|
break; |
67
|
|
|
case 'number': |
68
|
|
|
$this->type = NumberCollection::TYPE; |
69
|
|
|
$this->typeChecker = NumberCollection::CHECKER; |
70
|
|
|
break; |
71
|
|
|
case 'object': |
72
|
|
|
$this->type = ObjectCollection::TYPE; |
73
|
|
|
$this->typeChecker = ObjectCollection::CHECKER; |
74
|
|
|
break; |
75
|
|
|
case 'callable': |
76
|
|
|
case 'closure': |
77
|
|
|
case 'callback': |
78
|
|
|
case 'function': |
79
|
|
|
$this->type = CallableCollection::TYPE; |
80
|
|
|
$this->typeChecker = CallableCollection::CHECKER; |
81
|
|
|
break; |
82
|
|
|
case 'boolean': |
83
|
|
|
case 'bool': |
84
|
|
|
$this->type = BooleanCollection::TYPE; |
85
|
|
|
$this->typeChecker = BooleanCollection::CHECKER; |
86
|
|
|
break; |
87
|
|
|
case 'json': |
88
|
|
|
$this->typeChecker = function ($element) { |
89
|
|
|
if (!is_string($element)) { |
90
|
|
|
return false; |
91
|
|
|
} |
92
|
|
|
if (strcasecmp($element, 'null') == 0) { |
93
|
|
|
return true; |
94
|
|
|
} |
95
|
|
|
return (json_decode($element) !== null); |
96
|
|
|
}; |
97
|
|
|
break; |
98
|
|
|
default: |
99
|
|
|
// Class name |
100
|
|
|
$this->type = $type; |
101
|
|
|
$this->typeChecker = function ($element) use ($type) { |
102
|
|
|
return ($element instanceof $type); |
103
|
|
|
}; |
104
|
|
|
} |
105
|
|
|
} elseif (is_callable($type)) { |
106
|
|
|
$this->typeChecker = $type; |
107
|
|
|
} else { |
108
|
|
|
throw new TypeError('Invalid criteria to check elements of the collection.'); |
109
|
|
|
} |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @param $sample |
114
|
|
|
*/ |
115
|
|
|
public function setTypeLike($sample) |
116
|
|
|
{ |
117
|
|
|
if ($sample === null) { |
118
|
|
|
throw new \InvalidArgumentException('Sample element cannot be NULL'); |
119
|
|
|
} elseif (is_object($sample)) { |
120
|
|
|
$this->setType(get_class($sample)); |
121
|
|
|
return; |
122
|
|
|
} |
123
|
|
|
$this->setType(gettype($sample)); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
protected function validateItems(array $array): void |
127
|
|
|
{ |
128
|
|
|
foreach ($array as $value) { |
129
|
|
|
$this->validateItem($value); |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* @param $value |
135
|
|
|
*/ |
136
|
27 |
|
protected function validateItem($value): void |
137
|
|
|
{ |
138
|
27 |
|
if (!$this->validItem($value)) { |
139
|
14 |
|
$message = $this->getErrorMessage($value) ?? "%s not valid type. Expected [%s] for %s collection!"; |
|
|
|
|
140
|
|
|
|
141
|
14 |
|
$valueType = gettype($value); |
142
|
|
|
|
143
|
14 |
|
if ($valueType === 'object') { |
144
|
2 |
|
$valueType = get_class($value); |
145
|
|
|
} |
146
|
|
|
|
147
|
14 |
|
$message = sprintf( |
148
|
14 |
|
$message, |
149
|
|
|
$valueType, |
150
|
14 |
|
$this->type, |
151
|
14 |
|
get_called_class() |
152
|
|
|
); |
153
|
|
|
|
154
|
|
|
|
155
|
14 |
|
throw new InvalidTypeException( |
156
|
14 |
|
$message |
157
|
|
|
); |
158
|
|
|
} |
159
|
13 |
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Is the item valid - overwrite if you need another check |
163
|
|
|
* |
164
|
|
|
* @param $item |
165
|
|
|
* @return bool |
166
|
|
|
*/ |
167
|
27 |
|
protected function validItem($item): bool |
168
|
|
|
{ |
169
|
27 |
|
return ($this->typeChecker)($item); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @param $value |
174
|
|
|
* @return string|null |
175
|
|
|
*/ |
176
|
14 |
|
protected function getErrorMessage($value): ?string |
|
|
|
|
177
|
|
|
{ |
178
|
14 |
|
return null; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.