Completed
Pull Request — master (#1331)
by Maciej
10:31
created

PersistenceBuilder::prepareUpsertData()   C

Complexity

Conditions 27
Paths 42

Size

Total Lines 68
Code Lines 36

Duplication

Lines 20
Ratio 29.41 %

Code Coverage

Tests 36
CRAP Score 30.1455
Metric Value
dl 20
loc 68
ccs 36
cts 43
cp 0.8372
rs 5.5849
cc 27
eloc 36
nc 42
nop 1
crap 30.1455

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
namespace Doctrine\ODM\MongoDB\Persisters;
20
21
use Doctrine\ODM\MongoDB\DocumentManager;
22
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
23
use Doctrine\ODM\MongoDB\PersistentCollection;
24
use Doctrine\ODM\MongoDB\Types\Type;
25
use Doctrine\ODM\MongoDB\UnitOfWork;
26
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
27
28
/**
29
 * PersistenceBuilder builds the queries used by the persisters to update and insert
30
 * documents when a DocumentManager is flushed. It uses the changeset information in the
31
 * UnitOfWork to build queries using atomic operators like $set, $unset, etc.
32
 *
33
 * @since       1.0
34
 * @author      Jonathan H. Wage <[email protected]>
35
 */
36
class PersistenceBuilder
37
{
38
    /**
39
     * The DocumentManager instance.
40
     *
41
     * @var DocumentManager
42
     */
43
    private $dm;
44
45
    /**
46
     * The UnitOfWork instance.
47
     *
48
     * @var UnitOfWork
49
     */
50
    private $uow;
51
52
    /**
53
     * Initializes a new PersistenceBuilder instance.
54
     *
55
     * @param DocumentManager $dm
56
     * @param UnitOfWork $uow
57
     */
58 675
    public function __construct(DocumentManager $dm, UnitOfWork $uow)
59
    {
60 675
        $this->dm = $dm;
61 675
        $this->uow = $uow;
62 675
    }
63
64
    /**
65
     * Prepares the array that is ready to be inserted to mongodb for a given object document.
66
     *
67
     * @param object $document
68
     * @return array $insertData
69
     */
70 478
    public function prepareInsertData($document)
71
    {
72 478
        $class = $this->dm->getClassMetadata(get_class($document));
73 478
        $changeset = $this->uow->getDocumentChangeSet($document);
74
75 478
        $insertData = array();
76 478
        foreach ($class->fieldMappings as $mapping) {
77
78 478
            $new = isset($changeset[$mapping['fieldName']][1]) ? $changeset[$mapping['fieldName']][1] : null;
79
80 478
            if ($new === null && $mapping['nullable']) {
81 145
                $insertData[$mapping['name']] = null;
82 145
            }
83
84
            /* Nothing more to do for null values, since we're either storing
85
             * them (if nullable was true) or not.
86
             */
87 478
            if ($new === null) {
88 333
                continue;
89
            }
90
91
            // @Field, @String, @Date, etc.
92 478
            if ( ! isset($mapping['association'])) {
93 478
                $insertData[$mapping['name']] = Type::getType($mapping['type'])->convertToDatabaseValue($new);
94
95
            // @ReferenceOne
96 478
            } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE) {
97 78
                $insertData[$mapping['name']] = $this->prepareReferencedDocumentValue($mapping, $new);
98
99
            // @EmbedOne
100 389
            } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::EMBED_ONE) {
101 62
                $insertData[$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new);
102
103
            // @ReferenceMany, @EmbedMany
104
            // We're excluding collections using addToSet since there is a risk
105
            // of duplicated entries stored in the collection
106 365
            } elseif ($mapping['type'] === ClassMetadata::MANY && ! $mapping['isInverseSide']
107 343
                    && $mapping['strategy'] !== 'addToSet' && ! $new->isEmpty()) {
108 189
                $insertData[$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true);
109 189
            }
110 478
        }
111
112
        // add discriminator if the class has one
113 477 View Code Duplication
        if (isset($class->discriminatorField)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
114 32
            $insertData[$class->discriminatorField] = isset($class->discriminatorValue)
115 32
                ? $class->discriminatorValue
116 32
                : $class->name;
117 32
        }
118
119 477
        return $insertData;
120
    }
121
122
    /**
123
     * Prepares the update query to update a given document object in mongodb.
124
     *
125
     * @param object $document
126
     * @return array $updateData
127
     */
128 1
    public function prepareUpdateData($document)
129
    {
130 1
        $class = $this->dm->getClassMetadata(get_class($document));
131 1
        $changeset = $this->uow->getDocumentChangeSet($document);
132
133 1
        $updateData = array();
134 1
        foreach ($changeset as $fieldName => $change) {
135 1
            $mapping = $class->fieldMappings[$fieldName];
136
137
            // skip non embedded document identifiers
138 1
            if ( ! $class->isEmbeddedDocument && ! empty($mapping['id'])) {
139 1
                continue;
140
            }
141
142 1
            list($old, $new) = $change;
143
144
            // @Inc
145 1
            if ($mapping['type'] === 'increment') {
146
                if ($new === null) {
147
                    if ($mapping['nullable'] === true) {
148
                        $updateData['$set'][$mapping['name']] = null;
149
                    } else {
150
                        $updateData['$unset'][$mapping['name']] = true;
151
                    }
152
                } elseif ($new >= $old) {
153
                    $updateData['$inc'][$mapping['name']] = $new - $old;
154
                } else {
155
                    $updateData['$inc'][$mapping['name']] = ($old - $new) * -1;
156
                }
157
158
            // @Field, @String, @Date, etc.
159 1
            } elseif ( ! isset($mapping['association'])) {
160 1
                if (isset($new) || $mapping['nullable'] === true) {
161 1
                    $updateData['$set'][$mapping['name']] = (is_null($new) ? null : Type::getType($mapping['type'])->convertToDatabaseValue($new));
162 1
                } else {
163
                    $updateData['$unset'][$mapping['name']] = true;
164
                }
165
166
            // @EmbedOne
167 1
            } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::EMBED_ONE) {
168
                // If we have a new embedded document then lets set the whole thing
169
                if ($new && $this->uow->isScheduledForInsert($new)) {
170
                    $updateData['$set'][$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new);
171
172
                // If we don't have a new value then lets unset the embedded document
173
                } elseif ( ! $new) {
174
                    $updateData['$unset'][$mapping['name']] = true;
175
176
                // Update existing embedded document
177 View Code Duplication
                } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
178
                    $update = $this->prepareUpdateData($new);
179
                    foreach ($update as $cmd => $values) {
180
                        foreach ($values as $key => $value) {
181
                            $updateData[$cmd][$mapping['name'] . '.' . $key] = $value;
182
                        }
183
                    }
184
                }
185
186
            // @ReferenceMany, @EmbedMany
187
            } elseif (isset($mapping['association']) && $mapping['type'] === 'many' && $new) {
188
                if (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForUpdate($new)) {
189
                    $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true);
190 View Code Duplication
                } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($new)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
                    $updateData['$unset'][$mapping['name']] = true;
192
                    $this->uow->unscheduleCollectionDeletion($new);
193
                } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($old)) {
194
                    $updateData['$unset'][$mapping['name']] = true;
195
                    $this->uow->unscheduleCollectionDeletion($old);
196
                } elseif ($mapping['association'] === ClassMetadata::EMBED_MANY) {
197
                    foreach ($new as $key => $embeddedDoc) {
198
                        if ( ! $this->uow->isScheduledForInsert($embeddedDoc)) {
199
                            $update = $this->prepareUpdateData($embeddedDoc);
200
                            foreach ($update as $cmd => $values) {
201
                                foreach ($values as $name => $value) {
202
                                    $updateData[$cmd][$mapping['name'] . '.' . $key . '.' . $name] = $value;
203
                                }
204
                            }
205
                        }
206
                    }
207
                }
208
209
            // @ReferenceOne
210
            } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE) {
211 View Code Duplication
                if (isset($new) || $mapping['nullable'] === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
212
                    $updateData['$set'][$mapping['name']] = (is_null($new) ? null : $this->prepareReferencedDocumentValue($mapping, $new));
213
                } else {
214
                    $updateData['$unset'][$mapping['name']] = true;
215
                }
216
            }
217 1
        }
218
        // collections that aren't dirty but could be subject to update are
219
        // excluded from change set, let's go through them now
220 1
        foreach ($this->uow->getScheduledCollections($document) as $coll) {
221
            $mapping = $coll->getMapping();
222
            if (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForUpdate($coll)) {
223
                $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($coll, true);
224 View Code Duplication
            } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($coll)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
225
                $updateData['$unset'][$mapping['name']] = true;
226
                $this->uow->unscheduleCollectionDeletion($coll);
227
            }
228
            // @ReferenceMany is handled by CollectionPersister
229 1
        }
230 1
        return $updateData;
231
    }
232
233
    /**
234
     * Prepares the update query to upsert a given document object in mongodb.
235
     *
236
     * @param object $document
237
     * @return array $updateData
238
     */
239 77
    public function prepareUpsertData($document)
240
    {
241 77
        $class = $this->dm->getClassMetadata(get_class($document));
242 77
        $changeset = $this->uow->getDocumentChangeSet($document);
243
244 77
        $updateData = array();
245 77
        foreach ($changeset as $fieldName => $change) {
246 77
            $mapping = $class->fieldMappings[$fieldName];
247
248 77
            list($old, $new) = $change;
249
250
            // @Inc
251 77
            if ($mapping['type'] === 'increment') {
252 4
                if ($new >= $old) {
253 4
                    $updateData['$inc'][$mapping['name']] = $new - $old;
254 4
                } else {
255
                    $updateData['$inc'][$mapping['name']] = ($old - $new) * -1;
256
                }
257
258
            // @Field, @String, @Date, etc.
259 77
            } elseif ( ! isset($mapping['association'])) {
260 77
                if (isset($new) || $mapping['nullable'] === true) {
261 77
                    $updateData['$set'][$mapping['name']] = (is_null($new) ? null : Type::getType($mapping['type'])->convertToDatabaseValue($new));
262 77
                }
263
264
            // @EmbedOne
265 77
            } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::EMBED_ONE) {
266
                // If we have a new embedded document then lets set the whole thing
267 3
                if ($new && $this->uow->isScheduledForInsert($new)) {
268 1
                    $updateData['$set'][$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new);
269
270
                // If we don't have a new value then do nothing on upsert
271 3
                } elseif ( ! $new) {
272
273
                // Update existing embedded document
274 2 View Code Duplication
                } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
275
                    $update = $this->prepareUpsertData($new);
276
                    foreach ($update as $cmd => $values) {
277
                        foreach ($values as $key => $value) {
278
                            $updateData[$cmd][$mapping['name'] . '.' . $key] = $value;
279
                        }
280
                    }
281
                }
282
283
            // @ReferenceOne
284 22 View Code Duplication
            } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
285 12
                if (isset($new) || $mapping['nullable'] === true) {
286 9
                    $updateData['$set'][$mapping['name']] = (is_null($new) ? null : $this->prepareReferencedDocumentValue($mapping, $new));
287 9
                }
288
289
            // @ReferenceMany, @EmbedMany
290 21
            } elseif ($mapping['type'] === ClassMetadata::MANY && ! $mapping['isInverseSide']
291 13
                    && $new instanceof PersistentCollection && $new->isDirty()
292 13
                    && CollectionHelper::isAtomic($mapping['strategy'])) {
293 1
                $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true);
294 1
            }
295
            // @EmbedMany and @ReferenceMany are handled by CollectionPersister
296 77
        }
297
298
        // add discriminator if the class has one
299 77 View Code Duplication
        if (isset($class->discriminatorField)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
300 5
            $updateData['$set'][$class->discriminatorField] = isset($class->discriminatorValue)
301 5
                ? $class->discriminatorValue
302 5
                : $class->name;
303 5
        }
304
305 77
        return $updateData;
306
    }
307
308
    /**
309
     * Returns the reference representation to be stored in MongoDB.
310
     *
311
     * If the document does not have an identifier and the mapping calls for a
312
     * simple reference, null may be returned.
313
     *
314
     * @param array $referenceMapping
315
     * @param object $document
316
     * @return array|null
317
     */
318 171
    public function prepareReferencedDocumentValue(array $referenceMapping, $document)
319
    {
320 171
        return $this->dm->createDBRef($document, $referenceMapping);
321
    }
322
323
    /**
324
     * Returns the embedded document to be stored in MongoDB.
325
     *
326
     * The return value will usually be an associative array with string keys
327
     * corresponding to field names on the embedded document. An object may be
328
     * returned if the document is empty, to ensure that a BSON object will be
329
     * stored in lieu of an array.
330
     *
331
     * If $includeNestedCollections is true, nested collections will be included
332
     * in this prepared value and the option will cascade to all embedded
333
     * associations. If any nested PersistentCollections (embed or reference)
334
     * within this value were previously scheduled for deletion or update, they
335
     * will also be unscheduled.
336
     *
337
     * @param array $embeddedMapping
338
     * @param object $embeddedDocument
339
     * @param boolean $includeNestedCollections
340
     * @return array|object
341
     * @throws \UnexpectedValueException if an unsupported associating mapping is found
342
     */
343 157
    public function prepareEmbeddedDocumentValue(array $embeddedMapping, $embeddedDocument, $includeNestedCollections = false)
344
    {
345 157
        $embeddedDocumentValue = array();
346 157
        $class = $this->dm->getClassMetadata(get_class($embeddedDocument));
347
348 157
        foreach ($class->fieldMappings as $mapping) {
349
            // Skip notSaved fields
350 155
            if ( ! empty($mapping['notSaved'])) {
351 1
                continue;
352
            }
353
354
            // Inline ClassMetadataInfo::getFieldValue()
355 155
            $rawValue = $class->reflFields[$mapping['fieldName']]->getValue($embeddedDocument);
356
357 155
            $value = null;
358
359 155
            if ($rawValue !== null) {
360 152
                switch (isset($mapping['association']) ? $mapping['association'] : null) {
361
                    // @Field, @String, @Date, etc.
362 152
                    case null:
363 149
                        $value = Type::getType($mapping['type'])->convertToDatabaseValue($rawValue);
364 149
                        break;
365
366 59
                    case ClassMetadata::EMBED_ONE:
367 59
                    case ClassMetadata::REFERENCE_ONE:
368
                        // Nested collections should only be included for embedded relationships
369 18
                        $value = $this->prepareAssociatedDocumentValue($mapping, $rawValue, $includeNestedCollections && isset($mapping['embedded']));
370 18
                        break;
371
372 42
                    case ClassMetadata::EMBED_MANY:
373 42
                    case ClassMetadata::REFERENCE_MANY:
374
                        // Skip PersistentCollections already scheduled for deletion
375 42
                        if ( ! $includeNestedCollections && $rawValue instanceof PersistentCollection
376 42
                            && $this->uow->isCollectionScheduledForDeletion($rawValue)) {
377
                            break;
378
                        }
379
380 42
                        $value = $this->prepareAssociatedCollectionValue($rawValue, $includeNestedCollections);
381 42
                        break;
382
383
                    default:
384
                        throw new \UnexpectedValueException('Unsupported mapping association: ' . $mapping['association']);
385 152
                }
386 152
            }
387
388
            // Omit non-nullable fields that would have a null value
389 155
            if ($value === null && $mapping['nullable'] === false) {
390 57
                continue;
391
            }
392
393 152
            $embeddedDocumentValue[$mapping['name']] = $value;
394 157
        }
395
396
        /* Add a discriminator value if the embedded document is not mapped
397
         * explicitly to a targetDocument class.
398
         */
399 157 View Code Duplication
        if ( ! isset($embeddedMapping['targetDocument'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
400 13
            $discriminatorField = $embeddedMapping['discriminatorField'];
401 13
            $discriminatorValue = isset($embeddedMapping['discriminatorMap'])
402 13
                ? array_search($class->name, $embeddedMapping['discriminatorMap'])
403 13
                : $class->name;
404
405
            /* If the discriminator value was not found in the map, use the full
406
             * class name. In the future, it may be preferable to throw an
407
             * exception here (perhaps based on some strictness option).
408
             *
409
             * @see DocumentManager::createDBRef()
410
             */
411 13
            if ($discriminatorValue === false) {
412 2
                $discriminatorValue = $class->name;
413 2
            }
414
415 13
            $embeddedDocumentValue[$discriminatorField] = $discriminatorValue;
416 13
        }
417
418
        /* If the class has a discriminator (field and value), use it. A child
419
         * class that is not defined in the discriminator map may only have a
420
         * discriminator field and no value, so default to the full class name.
421
         */
422 157 View Code Duplication
        if (isset($class->discriminatorField)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
423 8
            $embeddedDocumentValue[$class->discriminatorField] = isset($class->discriminatorValue)
424 8
                ? $class->discriminatorValue
425 8
                : $class->name;
426 8
        }
427
428
        // Ensure empty embedded documents are stored as BSON objects
429 157
        if (empty($embeddedDocumentValue)) {
430 5
            return (object) $embeddedDocumentValue;
431
        }
432
433
        /* @todo Consider always casting the return value to an object, or
434
         * building $embeddedDocumentValue as an object instead of an array, to
435
         * handle the edge case where all database field names are sequential,
436
         * numeric keys.
437
         */
438 153
        return $embeddedDocumentValue;
439
    }
440
441
    /*
442
     * Returns the embedded document or reference representation to be stored.
443
     *
444
     * @param array $mapping
445
     * @param object $document
446
     * @param boolean $includeNestedCollections
447
     * @return array|object|null
448
     * @throws \InvalidArgumentException if the mapping is neither embedded nor reference
449
     */
450 18
    public function prepareAssociatedDocumentValue(array $mapping, $document, $includeNestedCollections = false)
451
    {
452 18
        if (isset($mapping['embedded'])) {
453 10
            return $this->prepareEmbeddedDocumentValue($mapping, $document, $includeNestedCollections);
454
        }
455
456 16
        if (isset($mapping['reference'])) {
457 16
            return $this->prepareReferencedDocumentValue($mapping, $document);
458
        }
459
460
        throw new \InvalidArgumentException('Mapping is neither embedded nor reference.');
461
    }
462
463
    /**
464
     * Returns the collection representation to be stored and unschedules it afterwards.
465
     *
466
     * @param PersistentCollection $coll
467
     * @param bool $includeNestedCollections
468
     * @return array
469
     */
470 199
    public function prepareAssociatedCollectionValue(PersistentCollection $coll, $includeNestedCollections = false)
471
    {
472 199
        $mapping = $coll->getMapping();
473 199
        $pb = $this;
474 199
        $callback = isset($mapping['embedded'])
475
            ? function($v) use ($pb, $mapping, $includeNestedCollections) {
476 111
                return $pb->prepareEmbeddedDocumentValue($mapping, $v, $includeNestedCollections);
477
            }
478
            : function($v) use ($pb, $mapping) { return $pb->prepareReferencedDocumentValue($mapping, $v); };
479
480 199
        $setData = $coll->map($callback)->toArray();
481 199
        if (CollectionHelper::isList($mapping['strategy'])) {
482 180
            $setData = array_values($setData);
483 180
        }
484
485 199
        $this->uow->unscheduleCollectionDeletion($coll);
486 199
        $this->uow->unscheduleCollectionUpdate($coll);
487
488 199
        return $setData;
489
    }
490
}
491