These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Doctrine\ODM\MongoDB\Persisters; |
||
6 | |||
7 | use Doctrine\ODM\MongoDB\DocumentManager; |
||
8 | use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; |
||
9 | use Doctrine\ODM\MongoDB\Mapping\MappingException; |
||
10 | use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionInterface; |
||
11 | use Doctrine\ODM\MongoDB\Types\Type; |
||
12 | use Doctrine\ODM\MongoDB\UnitOfWork; |
||
13 | use Doctrine\ODM\MongoDB\Utility\CollectionHelper; |
||
14 | use InvalidArgumentException; |
||
15 | use UnexpectedValueException; |
||
16 | use function array_search; |
||
17 | use function array_values; |
||
18 | use function get_class; |
||
19 | |||
20 | /** |
||
21 | * PersistenceBuilder builds the queries used by the persisters to update and insert |
||
22 | * documents when a DocumentManager is flushed. It uses the changeset information in the |
||
23 | * UnitOfWork to build queries using atomic operators like $set, $unset, etc. |
||
24 | */ |
||
25 | class PersistenceBuilder |
||
26 | { |
||
27 | /** |
||
28 | * The DocumentManager instance. |
||
29 | * |
||
30 | * @var DocumentManager |
||
31 | */ |
||
32 | private $dm; |
||
33 | |||
34 | /** |
||
35 | * The UnitOfWork instance. |
||
36 | * |
||
37 | * @var UnitOfWork |
||
38 | */ |
||
39 | private $uow; |
||
40 | |||
41 | /** |
||
42 | * Initializes a new PersistenceBuilder instance. |
||
43 | */ |
||
44 | 1130 | public function __construct(DocumentManager $dm, UnitOfWork $uow) |
|
45 | { |
||
46 | 1130 | $this->dm = $dm; |
|
47 | 1130 | $this->uow = $uow; |
|
48 | 1130 | } |
|
49 | |||
50 | /** |
||
51 | * Prepares the array that is ready to be inserted to mongodb for a given object document. |
||
52 | * |
||
53 | * @param object $document |
||
54 | * |
||
55 | * @return array $insertData |
||
56 | */ |
||
57 | 523 | public function prepareInsertData($document) |
|
58 | { |
||
59 | 523 | $class = $this->dm->getClassMetadata(get_class($document)); |
|
60 | 523 | $changeset = $this->uow->getDocumentChangeSet($document); |
|
61 | |||
62 | 523 | $insertData = []; |
|
63 | 523 | foreach ($class->fieldMappings as $mapping) { |
|
64 | 523 | $new = $changeset[$mapping['fieldName']][1] ?? null; |
|
65 | |||
66 | 523 | if ($new === null && $mapping['nullable']) { |
|
67 | 160 | $insertData[$mapping['name']] = null; |
|
68 | } |
||
69 | |||
70 | /* Nothing more to do for null values, since we're either storing |
||
71 | * them (if nullable was true) or not. |
||
72 | */ |
||
73 | 523 | if ($new === null) { |
|
74 | 366 | continue; |
|
75 | } |
||
76 | |||
77 | // @Field, @String, @Date, etc. |
||
78 | 521 | if (! isset($mapping['association'])) { |
|
79 | 521 | $insertData[$mapping['name']] = Type::getType($mapping['type'])->convertToDatabaseValue($new); |
|
80 | |||
81 | // @ReferenceOne |
||
82 | 416 | } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE) { |
|
83 | 99 | $insertData[$mapping['name']] = $this->prepareReferencedDocumentValue($mapping, $new); |
|
84 | |||
85 | // @EmbedOne |
||
86 | 392 | } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::EMBED_ONE) { |
|
87 | 60 | $insertData[$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new); |
|
88 | |||
89 | // @ReferenceMany, @EmbedMany |
||
90 | // We're excluding collections using addToSet since there is a risk |
||
91 | // of duplicated entries stored in the collection |
||
92 | 374 | } elseif ($mapping['type'] === ClassMetadata::MANY && ! $mapping['isInverseSide'] |
|
93 | 374 | && $mapping['strategy'] !== ClassMetadata::STORAGE_STRATEGY_ADD_TO_SET && ! $new->isEmpty()) { |
|
94 | 216 | $insertData[$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true); |
|
95 | } |
||
96 | } |
||
97 | |||
98 | // add discriminator if the class has one |
||
99 | 512 | if (isset($class->discriminatorField)) { |
|
100 | 26 | if ($class->discriminatorValue === null) { |
|
101 | 5 | if (! empty($class->discriminatorMap)) { |
|
102 | 4 | throw MappingException::unlistedClassInDiscriminatorMap($class->name); |
|
103 | } |
||
104 | 1 | $class->discriminatorValue = $class->name; |
|
105 | } |
||
106 | 25 | $insertData[$class->discriminatorField] = $class->discriminatorValue; |
|
107 | } |
||
108 | |||
109 | 512 | return $insertData; |
|
110 | } |
||
111 | |||
112 | /** |
||
113 | * Prepares the update query to update a given document object in mongodb. |
||
114 | * |
||
115 | * @param object $document |
||
116 | * |
||
117 | * @return array $updateData |
||
118 | */ |
||
119 | 228 | public function prepareUpdateData($document) |
|
120 | { |
||
121 | 228 | $class = $this->dm->getClassMetadata(get_class($document)); |
|
122 | 228 | $changeset = $this->uow->getDocumentChangeSet($document); |
|
123 | |||
124 | 228 | $updateData = []; |
|
125 | 228 | foreach ($changeset as $fieldName => $change) { |
|
126 | 227 | $mapping = $class->fieldMappings[$fieldName]; |
|
127 | |||
128 | // skip non embedded document identifiers |
||
129 | 227 | if (! $class->isEmbeddedDocument && ! empty($mapping['id'])) { |
|
130 | 2 | continue; |
|
131 | } |
||
132 | |||
133 | 226 | [$old, $new] = $change; |
|
134 | |||
135 | // Scalar fields |
||
136 | 226 | if (! isset($mapping['association'])) { |
|
137 | 115 | if ($new === null && $mapping['nullable'] !== true) { |
|
138 | 1 | $updateData['$unset'][$mapping['name']] = true; |
|
139 | } else { |
||
140 | 115 | if ($new !== null && isset($mapping['strategy']) && $mapping['strategy'] === ClassMetadata::STORAGE_STRATEGY_INCREMENT) { |
|
141 | 4 | $operator = '$inc'; |
|
142 | 4 | $value = Type::getType($mapping['type'])->convertToDatabaseValue($new - $old); |
|
143 | } else { |
||
144 | 112 | $operator = '$set'; |
|
145 | 112 | $value = $new === null ? null : Type::getType($mapping['type'])->convertToDatabaseValue($new); |
|
146 | } |
||
147 | |||
148 | 115 | $updateData[$operator][$mapping['name']] = $value; |
|
149 | } |
||
150 | |||
151 | // @EmbedOne |
||
152 | 153 | } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::EMBED_ONE) { |
|
153 | // If we have a new embedded document then lets set the whole thing |
||
154 | 29 | if ($new && $this->uow->isScheduledForInsert($new)) { |
|
155 | 10 | $updateData['$set'][$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new); |
|
156 | |||
157 | // If we don't have a new value then lets unset the embedded document |
||
158 | 22 | } elseif (! $new) { |
|
159 | 3 | $updateData['$unset'][$mapping['name']] = true; |
|
160 | |||
161 | // Update existing embedded document |
||
162 | } else { |
||
163 | 19 | $update = $this->prepareUpdateData($new); |
|
164 | 29 | foreach ($update as $cmd => $values) { |
|
165 | 15 | foreach ($values as $key => $value) { |
|
166 | 15 | $updateData[$cmd][$mapping['name'] . '.' . $key] = $value; |
|
167 | } |
||
168 | } |
||
169 | } |
||
170 | |||
171 | // @ReferenceMany, @EmbedMany |
||
172 | 136 | } elseif (isset($mapping['association']) && $mapping['type'] === 'many' && $new) { |
|
173 | 126 | if (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForUpdate($new)) { |
|
0 ignored issues
–
show
|
|||
174 | 20 | $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true); |
|
175 | 108 | } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($new)) { |
|
0 ignored issues
–
show
$new is of type integer|double , but the function expects a object<Doctrine\ODM\Mong...entCollectionInterface> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
176 | 2 | $updateData['$unset'][$mapping['name']] = true; |
|
177 | 2 | $this->uow->unscheduleCollectionDeletion($new); |
|
0 ignored issues
–
show
$new is of type integer|double , but the function expects a object<Doctrine\ODM\Mong...entCollectionInterface> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
178 | 106 | } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($old)) { |
|
179 | 2 | $updateData['$unset'][$mapping['name']] = true; |
|
180 | 2 | $this->uow->unscheduleCollectionDeletion($old); |
|
181 | 104 | } elseif ($mapping['association'] === ClassMetadata::EMBED_MANY) { |
|
182 | 126 | foreach ($new as $key => $embeddedDoc) { |
|
183 | 58 | if ($this->uow->isScheduledForInsert($embeddedDoc)) { |
|
184 | 42 | continue; |
|
185 | } |
||
186 | |||
187 | 45 | $update = $this->prepareUpdateData($embeddedDoc); |
|
188 | 45 | foreach ($update as $cmd => $values) { |
|
189 | 14 | foreach ($values as $name => $value) { |
|
190 | 14 | $updateData[$cmd][$mapping['name'] . '.' . $key . '.' . $name] = $value; |
|
191 | } |
||
192 | } |
||
193 | } |
||
194 | } |
||
195 | |||
196 | // @ReferenceOne |
||
197 | 16 | } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE) { |
|
198 | 12 | if (isset($new) || $mapping['nullable'] === true) { |
|
199 | 12 | $updateData['$set'][$mapping['name']] = $new === null ? null : $this->prepareReferencedDocumentValue($mapping, $new); |
|
200 | } else { |
||
201 | 2 | $updateData['$unset'][$mapping['name']] = true; |
|
202 | } |
||
203 | } |
||
204 | } |
||
205 | // collections that aren't dirty but could be subject to update are |
||
206 | // excluded from change set, let's go through them now |
||
207 | 228 | foreach ($this->uow->getScheduledCollections($document) as $coll) { |
|
208 | 105 | $mapping = $coll->getMapping(); |
|
209 | 105 | if (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForUpdate($coll)) { |
|
210 | 3 | $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($coll, true); |
|
211 | 102 | } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($coll)) { |
|
212 | 1 | $updateData['$unset'][$mapping['name']] = true; |
|
213 | 1 | $this->uow->unscheduleCollectionDeletion($coll); |
|
214 | } |
||
215 | // @ReferenceMany is handled by CollectionPersister |
||
216 | } |
||
217 | 228 | return $updateData; |
|
218 | } |
||
219 | |||
220 | /** |
||
221 | * Prepares the update query to upsert a given document object in mongodb. |
||
222 | * |
||
223 | * @param object $document |
||
224 | * |
||
225 | * @return array $updateData |
||
226 | */ |
||
227 | 86 | public function prepareUpsertData($document) |
|
228 | { |
||
229 | 86 | $class = $this->dm->getClassMetadata(get_class($document)); |
|
230 | 86 | $changeset = $this->uow->getDocumentChangeSet($document); |
|
231 | |||
232 | 86 | $updateData = []; |
|
233 | 86 | foreach ($changeset as $fieldName => $change) { |
|
234 | 86 | $mapping = $class->fieldMappings[$fieldName]; |
|
235 | |||
236 | 86 | [$old, $new] = $change; |
|
237 | |||
238 | // Scalar fields |
||
239 | 86 | if (! isset($mapping['association'])) { |
|
240 | 86 | if ($new !== null) { |
|
241 | 86 | if (empty($mapping['id']) && isset($mapping['strategy']) && $mapping['strategy'] === ClassMetadata::STORAGE_STRATEGY_INCREMENT) { |
|
242 | 3 | $operator = '$inc'; |
|
243 | 3 | $value = Type::getType($mapping['type'])->convertToDatabaseValue($new - $old); |
|
244 | } else { |
||
245 | 86 | $operator = '$set'; |
|
246 | 86 | $value = Type::getType($mapping['type'])->convertToDatabaseValue($new); |
|
247 | } |
||
248 | |||
249 | 86 | $updateData[$operator][$mapping['name']] = $value; |
|
250 | 11 | } elseif ($mapping['nullable'] === true) { |
|
251 | 86 | $updateData['$setOnInsert'][$mapping['name']] = null; |
|
252 | } |
||
253 | |||
254 | // @EmbedOne |
||
255 | 27 | } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::EMBED_ONE) { |
|
256 | // If we don't have a new value then do nothing on upsert |
||
257 | // If we have a new embedded document then lets set the whole thing |
||
258 | 8 | if ($new && $this->uow->isScheduledForInsert($new)) { |
|
259 | 5 | $updateData['$set'][$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new); |
|
260 | 3 | } elseif ($new) { |
|
261 | // Update existing embedded document |
||
262 | $update = $this->prepareUpsertData($new); |
||
263 | 8 | foreach ($update as $cmd => $values) { |
|
264 | foreach ($values as $key => $value) { |
||
265 | $updateData[$cmd][$mapping['name'] . '.' . $key] = $value; |
||
266 | } |
||
267 | } |
||
268 | } |
||
269 | |||
270 | // @ReferenceOne |
||
271 | 24 | } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE) { |
|
272 | 13 | if (isset($new) || $mapping['nullable'] === true) { |
|
273 | 13 | $updateData['$set'][$mapping['name']] = $new === null ? null : $this->prepareReferencedDocumentValue($mapping, $new); |
|
274 | } |
||
275 | |||
276 | // @ReferenceMany, @EmbedMany |
||
277 | 15 | } elseif ($mapping['type'] === ClassMetadata::MANY && ! $mapping['isInverseSide'] |
|
278 | 15 | && $new instanceof PersistentCollectionInterface && $new->isDirty() |
|
279 | 15 | && CollectionHelper::isAtomic($mapping['strategy'])) { |
|
280 | 1 | $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true); |
|
281 | } |
||
282 | // @EmbedMany and @ReferenceMany are handled by CollectionPersister |
||
283 | } |
||
284 | |||
285 | // add discriminator if the class has one |
||
286 | 86 | if (isset($class->discriminatorField)) { |
|
287 | 5 | if ($class->discriminatorValue === null) { |
|
288 | if (! empty($class->discriminatorMap)) { |
||
289 | throw MappingException::unlistedClassInDiscriminatorMap($class->name); |
||
290 | } |
||
291 | $class->discriminatorValue = $class->name; |
||
292 | } |
||
293 | 5 | $updateData['$set'][$class->discriminatorField] = $class->discriminatorValue; |
|
294 | } |
||
295 | |||
296 | 86 | return $updateData; |
|
297 | } |
||
298 | |||
299 | /** |
||
300 | * Returns the reference representation to be stored in MongoDB. |
||
301 | * |
||
302 | * If the document does not have an identifier and the mapping calls for a |
||
303 | * simple reference, null may be returned. |
||
304 | * |
||
305 | * @param array $referenceMapping |
||
306 | * @param object $document |
||
307 | * |
||
308 | * @return array|null |
||
309 | */ |
||
310 | 212 | public function prepareReferencedDocumentValue(array $referenceMapping, $document) |
|
311 | { |
||
312 | 212 | return $this->dm->createReference($document, $referenceMapping); |
|
313 | } |
||
314 | |||
315 | /** |
||
316 | * Returns the embedded document to be stored in MongoDB. |
||
317 | * |
||
318 | * The return value will usually be an associative array with string keys |
||
319 | * corresponding to field names on the embedded document. An object may be |
||
320 | * returned if the document is empty, to ensure that a BSON object will be |
||
321 | * stored in lieu of an array. |
||
322 | * |
||
323 | * If $includeNestedCollections is true, nested collections will be included |
||
324 | * in this prepared value and the option will cascade to all embedded |
||
325 | * associations. If any nested PersistentCollections (embed or reference) |
||
326 | * within this value were previously scheduled for deletion or update, they |
||
327 | * will also be unscheduled. |
||
328 | * |
||
329 | * @param array $embeddedMapping |
||
330 | * @param object $embeddedDocument |
||
331 | * @param bool $includeNestedCollections |
||
332 | * |
||
333 | * @return array|object |
||
334 | * |
||
335 | * @throws UnexpectedValueException If an unsupported associating mapping is found. |
||
336 | */ |
||
337 | 186 | public function prepareEmbeddedDocumentValue(array $embeddedMapping, $embeddedDocument, $includeNestedCollections = false) |
|
338 | { |
||
339 | 186 | $embeddedDocumentValue = []; |
|
340 | 186 | $class = $this->dm->getClassMetadata(get_class($embeddedDocument)); |
|
341 | |||
342 | 186 | foreach ($class->fieldMappings as $mapping) { |
|
343 | // Skip notSaved fields |
||
344 | 184 | if (! empty($mapping['notSaved'])) { |
|
345 | 1 | continue; |
|
346 | } |
||
347 | |||
348 | // Inline ClassMetadata::getFieldValue() |
||
349 | 184 | $rawValue = $class->reflFields[$mapping['fieldName']]->getValue($embeddedDocument); |
|
350 | |||
351 | 184 | $value = null; |
|
352 | |||
353 | 184 | if ($rawValue !== null) { |
|
354 | 181 | switch ($mapping['association'] ?? null) { |
|
355 | // @Field, @String, @Date, etc. |
||
356 | case null: |
||
357 | 175 | $value = Type::getType($mapping['type'])->convertToDatabaseValue($rawValue); |
|
358 | 175 | break; |
|
359 | |||
360 | 72 | case ClassMetadata::EMBED_ONE: |
|
361 | 69 | case ClassMetadata::REFERENCE_ONE: |
|
362 | // Nested collections should only be included for embedded relationships |
||
363 | 21 | $value = $this->prepareAssociatedDocumentValue($mapping, $rawValue, $includeNestedCollections && isset($mapping['embedded'])); |
|
364 | 21 | break; |
|
365 | |||
366 | 53 | case ClassMetadata::EMBED_MANY: |
|
367 | 4 | case ClassMetadata::REFERENCE_MANY: |
|
368 | // Skip PersistentCollections already scheduled for deletion |
||
369 | 53 | if (! $includeNestedCollections && $rawValue instanceof PersistentCollectionInterface |
|
370 | 53 | && $this->uow->isCollectionScheduledForDeletion($rawValue)) { |
|
371 | break; |
||
372 | } |
||
373 | |||
374 | 53 | $value = $this->prepareAssociatedCollectionValue($rawValue, $includeNestedCollections); |
|
375 | 53 | break; |
|
376 | |||
377 | default: |
||
378 | throw new UnexpectedValueException('Unsupported mapping association: ' . $mapping['association']); |
||
379 | } |
||
380 | } |
||
381 | |||
382 | // Omit non-nullable fields that would have a null value |
||
383 | 184 | if ($value === null && $mapping['nullable'] === false) { |
|
384 | 63 | continue; |
|
385 | } |
||
386 | |||
387 | 181 | $embeddedDocumentValue[$mapping['name']] = $value; |
|
388 | } |
||
389 | |||
390 | /* Add a discriminator value if the embedded document is not mapped |
||
391 | * explicitly to a targetDocument class. |
||
392 | */ |
||
393 | 186 | if (! isset($embeddedMapping['targetDocument'])) { |
|
394 | 16 | $discriminatorField = $embeddedMapping['discriminatorField']; |
|
395 | 16 | if (! empty($embeddedMapping['discriminatorMap'])) { |
|
396 | 5 | $discriminatorValue = array_search($class->name, $embeddedMapping['discriminatorMap']); |
|
397 | |||
398 | 5 | if ($discriminatorValue === false) { |
|
399 | 5 | throw MappingException::unlistedClassInDiscriminatorMap($class->name); |
|
400 | } |
||
401 | } else { |
||
402 | 11 | $discriminatorValue = $class->name; |
|
403 | } |
||
404 | |||
405 | 15 | $embeddedDocumentValue[$discriminatorField] = $discriminatorValue; |
|
406 | } |
||
407 | |||
408 | /* If the class has a discriminator (field and value), use it. A child |
||
409 | * class that is not defined in the discriminator map may only have a |
||
410 | * discriminator field and no value, so default to the full class name. |
||
411 | */ |
||
412 | 185 | if (isset($class->discriminatorField)) { |
|
413 | 8 | if ($class->discriminatorValue === null) { |
|
414 | 4 | if (! empty($class->discriminatorMap)) { |
|
415 | 4 | throw MappingException::unlistedClassInDiscriminatorMap($class->name); |
|
416 | } |
||
417 | $class->discriminatorValue = $class->name; |
||
418 | } |
||
419 | 6 | $embeddedDocumentValue[$class->discriminatorField] = $class->discriminatorValue; |
|
420 | } |
||
421 | |||
422 | // Ensure empty embedded documents are stored as BSON objects |
||
423 | 183 | if (empty($embeddedDocumentValue)) { |
|
424 | 6 | return (object) $embeddedDocumentValue; |
|
425 | } |
||
426 | |||
427 | /* @todo Consider always casting the return value to an object, or |
||
428 | * building $embeddedDocumentValue as an object instead of an array, to |
||
429 | * handle the edge case where all database field names are sequential, |
||
430 | * numeric keys. |
||
431 | */ |
||
432 | 179 | return $embeddedDocumentValue; |
|
433 | } |
||
434 | |||
435 | /** |
||
436 | * Returns the embedded document or reference representation to be stored. |
||
437 | * |
||
438 | * @param array $mapping |
||
439 | * @param object $document |
||
440 | * @param bool $includeNestedCollections |
||
441 | * |
||
442 | * @return array|object|null |
||
443 | * |
||
444 | * @throws InvalidArgumentException If the mapping is neither embedded nor reference. |
||
445 | */ |
||
446 | 21 | public function prepareAssociatedDocumentValue(array $mapping, $document, $includeNestedCollections = false) |
|
447 | { |
||
448 | 21 | if (isset($mapping['embedded'])) { |
|
449 | 8 | return $this->prepareEmbeddedDocumentValue($mapping, $document, $includeNestedCollections); |
|
450 | } |
||
451 | |||
452 | 17 | if (isset($mapping['reference'])) { |
|
453 | 17 | return $this->prepareReferencedDocumentValue($mapping, $document); |
|
454 | } |
||
455 | |||
456 | throw new InvalidArgumentException('Mapping is neither embedded nor reference.'); |
||
457 | } |
||
458 | |||
459 | /** |
||
460 | * Returns the collection representation to be stored and unschedules it afterwards. |
||
461 | * |
||
462 | * @param bool $includeNestedCollections |
||
463 | * |
||
464 | * @return array |
||
465 | */ |
||
466 | 232 | public function prepareAssociatedCollectionValue(PersistentCollectionInterface $coll, $includeNestedCollections = false) |
|
467 | { |
||
468 | 232 | $mapping = $coll->getMapping(); |
|
469 | 232 | $pb = $this; |
|
470 | 232 | $callback = isset($mapping['embedded']) |
|
471 | ? static function ($v) use ($pb, $mapping, $includeNestedCollections) { |
||
472 | 125 | return $pb->prepareEmbeddedDocumentValue($mapping, $v, $includeNestedCollections); |
|
473 | 129 | } |
|
474 | : static function ($v) use ($pb, $mapping) { |
||
475 | 117 | return $pb->prepareReferencedDocumentValue($mapping, $v); |
|
476 | 232 | }; |
|
477 | |||
478 | 232 | $setData = $coll->map($callback)->toArray(); |
|
479 | 227 | if (CollectionHelper::isList($mapping['strategy'])) { |
|
480 | 206 | $setData = array_values($setData); |
|
481 | } |
||
482 | |||
483 | 227 | $this->uow->unscheduleCollectionDeletion($coll); |
|
484 | 227 | $this->uow->unscheduleCollectionUpdate($coll); |
|
485 | |||
486 | 227 | return $setData; |
|
487 | } |
||
488 | } |
||
489 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: