Completed
Push — master ( 957f41...1cd7c2 )
by Maciej
17s
created

PersistenceBuilder   D

Complexity

Total Complexity 118

Size/Duplication

Total Lines 446
Duplicated Lines 18.83 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 96.15%

Importance

Changes 0
Metric Value
wmc 118
lcom 1
cbo 7
dl 84
loc 446
ccs 175
cts 182
cp 0.9615
rs 4.8717
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
C prepareInsertData() 5 51 17
A prepareReferencedDocumentValue() 0 4 1
F prepareEmbeddedDocumentValue() 23 97 22
A prepareAssociatedDocumentValue() 0 12 3
D prepareUpdateData() 28 98 42
C prepareUpsertData() 28 65 29
A prepareAssociatedCollectionValue() 0 20 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PersistenceBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PersistenceBuilder, and based on these observations, apply Extract Interface, too.

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