1 | <?php |
||
18 | abstract class AbstractArray implements CompositableInterface, \Countable, \IteratorAggregate |
||
19 | { |
||
20 | use SolidableTrait; |
||
21 | |||
22 | /** |
||
23 | * @var array |
||
24 | */ |
||
25 | protected $values = []; |
||
26 | |||
27 | /** |
||
28 | * Low level atomic operations. |
||
29 | * |
||
30 | * @var array |
||
31 | */ |
||
32 | protected $atomics = []; |
||
33 | |||
34 | /** |
||
35 | * @param mixed $values |
||
36 | */ |
||
37 | public function __construct($values) |
||
46 | |||
47 | /** |
||
48 | * Check if value presented in array. |
||
49 | * |
||
50 | * @param mixed $needle |
||
51 | * @param bool $strict |
||
52 | * |
||
53 | * @return bool |
||
54 | */ |
||
55 | public function has($needle, bool $strict = true): bool |
||
69 | |||
70 | /** |
||
71 | * Alias for atomic operation $push. Only values passed type filter will be added. |
||
72 | * |
||
73 | * @param mixed $value |
||
74 | * |
||
75 | * @return self|$this |
||
76 | */ |
||
77 | public function push($value): AbstractArray |
||
89 | |||
90 | /** |
||
91 | * Alias for atomic operation $addToSet. Only values passed type filter will be added. |
||
92 | * |
||
93 | * @param mixed $value |
||
94 | * |
||
95 | * @return self|$this |
||
96 | */ |
||
97 | public function add($value): AbstractArray |
||
98 | { |
||
99 | $value = $this->filterValue($value); |
||
100 | if (is_null($value)) { |
||
101 | return $this; |
||
102 | } |
||
103 | |||
104 | if (!in_array($value, $this->values)) { |
||
105 | array_push($this->values, $value); |
||
106 | } |
||
107 | |||
108 | $this->atomics['$addToSet']['$each'][] = $value; |
||
109 | |||
110 | return $this; |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * Alias for atomic operation $pull. Only values passed type filter will be added. |
||
115 | * |
||
116 | * @param mixed $value |
||
117 | * |
||
118 | * @return self|$this |
||
119 | */ |
||
120 | public function pull($value): AbstractArray |
||
121 | { |
||
122 | $value = $this->filterValue($value); |
||
123 | if (is_null($value)) { |
||
124 | return $this; |
||
125 | } |
||
126 | |||
127 | //Removing values from array (non strict) |
||
128 | $this->values = array_filter($this->values, function ($item) use ($value) { |
||
129 | return $item != $value; |
||
130 | }); |
||
131 | |||
132 | $this->atomics['$pull']['$in'][] = $value; |
||
133 | |||
134 | return $this; |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * {@inheritdoc} |
||
139 | */ |
||
140 | public function stateValue($data) |
||
151 | |||
152 | /** |
||
153 | * {@inheritdoc} |
||
154 | */ |
||
155 | public function hasChanges(): bool |
||
156 | { |
||
157 | return !empty($this->atomics); |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * {@inheritdoc} |
||
162 | */ |
||
163 | public function flushChanges() |
||
164 | { |
||
165 | $this->atomics = []; |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * {@inheritdoc} |
||
170 | */ |
||
171 | public function buildAtomics(string $container = ''): array |
||
172 | { |
||
173 | if (!$this->hasChanges()) { |
||
174 | return []; |
||
175 | } |
||
176 | |||
177 | //Mongo does not support multiple operations for one field, switching to $set (make sure it's |
||
178 | //reasonable) |
||
179 | if ($this->solidState || count($this->atomics) > 1) { |
||
180 | //We don't care about atomics in solid state |
||
181 | return ['$set' => [$container => $this->packValue()]]; |
||
182 | } |
||
183 | |||
184 | $atomics = []; |
||
185 | foreach ($this->atomics as $operation => $values) { |
||
186 | $atomics[$operation] = [$container => $values]; |
||
187 | } |
||
188 | |||
189 | return $atomics; |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * @return array |
||
194 | */ |
||
195 | public function packValue(): array |
||
199 | |||
200 | /** |
||
201 | * @return int |
||
202 | */ |
||
203 | public function count(): int |
||
207 | |||
208 | /** |
||
209 | * @return \ArrayIterator |
||
210 | */ |
||
211 | public function getIterator() |
||
215 | |||
216 | /** |
||
217 | * Clone accessor and ensure that it state is updated. |
||
218 | */ |
||
219 | public function __clone() |
||
224 | |||
225 | /** |
||
226 | * @return array |
||
227 | */ |
||
228 | public function __debugInfo() |
||
235 | |||
236 | /** |
||
237 | * @return array |
||
238 | */ |
||
239 | public function jsonSerialize() |
||
243 | |||
244 | /** |
||
245 | * Add values matched with filter. |
||
246 | * |
||
247 | * @param mixed $values |
||
248 | */ |
||
249 | protected function addValues($values) |
||
264 | |||
265 | /** |
||
266 | * Filter value, MUST return null if value is invalid. |
||
267 | * |
||
268 | * @param mixed $value |
||
269 | * |
||
270 | * @return mixed|null |
||
271 | */ |
||
272 | abstract protected function filterValue($value); |
||
273 | } |