Completed
Pull Request — master (#1668)
by Andreas
04:58
created

Builder::update()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 1
crap 1
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
20
namespace Doctrine\ODM\MongoDB\Query;
21
22
use Doctrine\ODM\MongoDB\DocumentManager;
23
use Doctrine\ODM\MongoDB\Hydrator;
24
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
25
26
/**
27
 * Query builder for ODM.
28
 *
29
 * @since       1.0
30
 */
31
class Builder extends \Doctrine\MongoDB\Query\Builder
32
{
33
    /**
34
     * The DocumentManager instance for this query
35
     *
36
     * @var DocumentManager
37
     */
38
    private $dm;
39
40
    /**
41
     * The ClassMetadata instance.
42
     *
43
     * @var \Doctrine\ODM\MongoDB\Mapping\ClassMetadata
44
     */
45
    private $class;
46
47
    /**
48
     * The current field we are operating on.
49
     *
50
     * @todo Change this to private once ODM requires doctrine/mongodb 1.1+
51
     * @var string
52
     */
53
    protected $currentField;
54
55
    /**
56
     * Whether or not to hydrate the data to documents.
57
     *
58
     * @var boolean
59
     */
60
    private $hydrate = true;
61
62
    /**
63
     * Whether or not to refresh the data for documents that are already in the identity map.
64
     *
65
     * @var boolean
66
     */
67
    private $refresh = false;
68
69
    /**
70
     * Array of primer Closure instances.
71
     *
72
     * @var array
73
     */
74
    private $primers = array();
75
76
    /**
77
     * Whether or not to register documents in UnitOfWork.
78
     *
79
     * @var bool
80
     */
81
    private $readOnly;
82
83
    /**
84
     * Construct a Builder
85
     *
86
     * @param DocumentManager $dm
87
     * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none
88
     */
89 210
    public function __construct(DocumentManager $dm, $documentName = null)
90
    {
91 210
        $this->dm = $dm;
92 210
        $this->expr = new Expr($dm);
93 210
        if ($documentName !== null) {
94 202
            $this->setDocumentName($documentName);
95
        }
96 209
    }
97
98
    /**
99
     * Set the current field to operate on.
100
     *
101
     * @param string $field
102
     * @return $this
103
     */
104 134
    public function field($field)
105
    {
106 134
        $this->currentField = $field;
107 134
        parent::field($field);
108
109 134
        return $this;
110
    }
111
112
    /**
113
     * Use a primer to eagerly load all references in the current field.
114
     *
115
     * If $primer is true or a callable is provided, referenced documents for
116
     * this field will loaded into UnitOfWork immediately after the query is
117
     * executed. This will avoid multiple queries due to lazy initialization of
118
     * Proxy objects.
119
     *
120
     * If $primer is false, no priming will take place. That is also the default
121
     * behavior.
122
     *
123
     * If a custom callable is used, its signature should conform to the default
124
     * Closure defined in {@link ReferencePrimer::__construct()}.
125
     *
126
     * @param boolean|callable $primer
127
     * @return $this
128
     * @throws \InvalidArgumentException If $primer is not boolean or callable
129
     */
130 27
    public function prime($primer = true)
131
    {
132 27
        if ( ! is_bool($primer) && ! is_callable($primer)) {
133 1
            throw new \InvalidArgumentException('$primer is not a boolean or callable');
134
        }
135
136 26
        if ($primer === false) {
137 1
            unset($this->primers[$this->currentField]);
138
139 1
            return $this;
140
        }
141
142 26
        if (array_key_exists('eagerCursor', $this->query) && !$this->query['eagerCursor']) {
143 1
            throw new \BadMethodCallException("Can't call prime() when setting eagerCursor to false");
144
        }
145
146 25
        $this->primers[$this->currentField] = $primer;
147 25
        return $this;
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 6
    public function eagerCursor($bool = true)
154
    {
155 6
        if ( ! $bool && ! empty($this->primers)) {
156 1
            throw new \BadMethodCallException("Can't set eagerCursor to false when using reference primers");
157
        }
158
159 5
        return parent::eagerCursor($bool);
160
    }
161
162
163
    /**
164
     * @param bool $bool
165
     * @return $this
166
     */
167 16
    public function hydrate($bool = true)
168
    {
169 16
        $this->hydrate = $bool;
170 16
        return $this;
171
    }
172
173
    /**
174
     * @param bool $bool
175
     * @return $this
176
     */
177 2
    public function readOnly($bool = true)
178
    {
179 2
        $this->readOnly = $bool;
180 2
        return $this;
181
    }
182
183
    /**
184
     * @param bool $bool
185
     * @return $this
186
     */
187 5
    public function refresh($bool = true)
188
    {
189 5
        $this->refresh = $bool;
190 5
        return $this;
191
    }
192
193
    /**
194
     * Change the query type to find and optionally set and change the class being queried.
195
     *
196
     * @param string $documentName
197
     * @return $this
198
     */
199 12
    public function find($documentName = null)
200
    {
201 12
        $this->setDocumentName($documentName);
202 12
        parent::find();
203
204 12
        return $this;
205
    }
206
207
    /**
208
     * @param string $documentName
209
     * @return $this
210
     */
211 13
    public function findAndUpdate($documentName = null)
212
    {
213 13
        $this->setDocumentName($documentName);
214 13
        parent::findAndUpdate();
215
216 13
        return $this;
217
    }
218
219
    /**
220
     * @param bool $bool
221
     * @return $this
222
     */
223 4
    public function returnNew($bool = true)
224
    {
225 4
        $this->refresh(true);
226 4
        parent::returnNew($bool);
227
228 4
        return $this;
229
    }
230
231
    /**
232
     * @param string $documentName
233
     * @return $this
234
     */
235 1
    public function findAndRemove($documentName = null)
236
    {
237 1
        $this->setDocumentName($documentName);
238 1
        parent::findAndRemove();
239
240 1
        return $this;
241
    }
242
243
    /**
244
     * @param string $documentName
245
     * @return $this
246
     *
247
     * @deprecated Deprecated in version 1.2 - use updateOne or updateMany instead
248
     */
249 12
    public function update($documentName = null)
250
    {
251 12
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
252 12
            sprintf('%s was deprecated in version 1.2 - use updateOne or updateMany instead.', __METHOD__),
253 12
            E_USER_DEPRECATED
254
        );
255 12
        $this->setDocumentName($documentName);
256 12
        parent::update();
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\MongoDB\Query\Builder::update() has been deprecated with message: Deprecated in version 1.4 - use updateOne or updateMany instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
257
258 12
        return $this;
259
    }
260
261
    /**
262
     * @param string $documentName
263
     * @return $this
264
     */
265
    public function updateOne($documentName = null)
266
    {
267
        $this->setDocumentName($documentName);
268
        parent::updateOne();
269
270
        return $this;
271
    }
272
273
    /**
274
     * @param string $documentName
275
     * @return $this
276
     */
277
    public function updateMany($documentName = null)
278
    {
279
        $this->setDocumentName($documentName);
280
        parent::updateMany();
281
282
        return $this;
283
    }
284
285
    /**
286
     * @param string $documentName
287
     * @return $this
288
     */
289 1
    public function insert($documentName = null)
290
    {
291 1
        $this->setDocumentName($documentName);
292 1
        parent::insert();
293
294 1
        return $this;
295
    }
296
297
    /**
298
     * @param string $documentName
299
     * @return $this
300
     */
301 1
    public function remove($documentName = null)
302
    {
303 1
        $this->setDocumentName($documentName);
304 1
        parent::remove();
305
306 1
        return $this;
307
    }
308
309
    /**
310
     * @param object $document
311
     * @return $this
312
     */
313 10
    public function references($document)
314
    {
315 10
        $this->expr->references($document);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Doctrine\MongoDB\Query\Expr as the method references() does only exist in the following sub-classes of Doctrine\MongoDB\Query\Expr: Doctrine\ODM\MongoDB\Query\Expr. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
316 8
        return $this;
317
    }
318
319
    /**
320
     * @param object $document
321
     * @return $this
322
     */
323 6
    public function includesReferenceTo($document)
324
    {
325 6
        $this->expr->includesReferenceTo($document);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Doctrine\MongoDB\Query\Expr as the method includesReferenceTo() does only exist in the following sub-classes of Doctrine\MongoDB\Query\Expr: Doctrine\ODM\MongoDB\Query\Expr. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
326 4
        return $this;
327
    }
328
329
    /**
330
     * @inheritdoc
331
     * @deprecated Deprecated in version 1.2 - use Aggregation Builder's group stage instead.
332
     */
333 1
    public function group($keys, array $initial, $reduce = null, array $options = [])
334
    {
335 1
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
336 1
            sprintf('%s was deprecated in version 1.2 - use Aggregation Builder\'s group stage instead.', __METHOD__),
337 1
            E_USER_DEPRECATED
338
        );
339 1
        return parent::group($keys, $initial, $reduce, $options);
340
    }
341
342
    /**
343
     * {@inheritdoc}
344
     *
345
     * @deprecated in version 1.2 - use setReadPreference instead.
346
     */
347 3
    public function slaveOkay($bool = true)
348
    {
349 3
        if ($bool) {
350 2
            @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
351 2
                sprintf('%s was deprecated in version 1.2 - use setReadPreference instead.', __METHOD__),
352 2
                E_USER_DEPRECATED
353
            );
354
        }
355
356 3
        return parent::slaveOkay($bool);
357
    }
358
359
    /**
360
     * Gets the Query executable.
361
     *
362
     * @param array $options
363
     * @return Query $query
364
     */
365 179
    public function getQuery(array $options = array())
366
    {
367 179
        if ($this->query['type'] === Query::TYPE_MAP_REDUCE) {
368 3
            $this->hydrate = false;
369
        }
370
371 179
        $documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name);
372
373 179
        $query = $this->query;
374
375 179
        $query['query'] = $this->expr->getQuery();
376 179
        $query['query'] = $documentPersister->addDiscriminatorToPreparedQuery($query['query']);
0 ignored issues
show
Documentation introduced by
$query['query'] is of type string, but the function expects a array.

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...
377 179
        $query['query'] = $documentPersister->addFilterToPreparedQuery($query['query']);
378
379 179
        $query['newObj'] = $this->expr->getNewObj();
380
381 179
        if (isset($query['distinct'])) {
382 2
            $query['distinct'] = $documentPersister->prepareFieldName($query['distinct']);
0 ignored issues
show
Bug introduced by
It seems like $query['distinct'] can also be of type array; however, Doctrine\ODM\MongoDB\Per...ter::prepareFieldName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
383
        }
384
385 179
        if ($this->class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION && ! empty($query['upsert']) &&
386 179
            (empty($query['query'][$this->class->discriminatorField]) || is_array($query['query'][$this->class->discriminatorField]))) {
387 1
            throw new \InvalidArgumentException('Upsert query that is to be performed on discriminated document does not have single ' .
388 1
                'discriminator. Either not use base class or set \'' . $this->class->discriminatorField . '\' field manually.');
389
        }
390
391 178
        if ( ! empty($query['select'])) {
392 14
            $query['select'] = $documentPersister->prepareSortOrProjection($query['select']);
393 14
            if ($this->hydrate && $this->class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION
394 14
                && ! isset($query['select'][$this->class->discriminatorField])) {
395
                $includeMode = 0 < count(array_filter($query['select'], function($mode) { return $mode == 1; }));
396 2
                if ($includeMode && ! isset($query['select'][$this->class->discriminatorField])) {
397 1
                    $query['select'][$this->class->discriminatorField] = 1;
398
                }
399
            }
400
        }
401
402 178
        if (isset($query['sort'])) {
403 23
            $query['sort'] = $documentPersister->prepareSortOrProjection($query['sort']);
404
        }
405
406 178
        if ($this->class->slaveOkay) {
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...etadataInfo::$slaveOkay has been deprecated with message: in version 1.2 and will be removed in 2.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
407 1
            $query['slaveOkay'] = $this->class->slaveOkay;
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...etadataInfo::$slaveOkay has been deprecated with message: in version 1.2 and will be removed in 2.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
408
        }
409
410 178
        if ($this->class->readPreference && ! array_key_exists('readPreference', $query)) {
411 1
            $query['readPreference'] = $this->class->readPreference;
412 1
            $query['readPreferenceTags'] = $this->class->readPreferenceTags;
413
        }
414
415 178
        return new Query(
416 178
            $this->dm,
417 178
            $this->class,
418 178
            $this->collection,
419 178
            $query,
420 178
            $options,
421 178
            $this->hydrate,
422 178
            $this->refresh,
423 178
            $this->primers,
424 178
            $this->readOnly
425
        );
426
    }
427
428
    /**
429
     * Create a new Expr instance that can be used as an expression with the Builder
430
     *
431
     * @return Expr $expr
432
     */
433 20
    public function expr()
434
    {
435 20
        $expr = new Expr($this->dm);
436 20
        $expr->setClassMetadata($this->class);
437
438 20
        return $expr;
439
    }
440
441
    /**
442
     * @param string[]|string $documentName an array of document names or just one.
443
     */
444 209
    private function setDocumentName($documentName)
445
    {
446 209
        if (is_array($documentName)) {
447 2
            $documentNames = $documentName;
448 2
            $documentName = $documentNames[0];
449
450 2
            $metadata = $this->dm->getClassMetadata($documentName);
451 2
            $discriminatorField = $metadata->discriminatorField;
452 2
            $discriminatorValues = $this->getDiscriminatorValues($documentNames);
453
454
            // If a defaultDiscriminatorValue is set and it is among the discriminators being queries, add NULL to the list
455 1 View Code Duplication
            if ($metadata->defaultDiscriminatorValue && array_search($metadata->defaultDiscriminatorValue, $discriminatorValues) !== false) {
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...
456 1
                $discriminatorValues[] = null;
457
            }
458
459 1
            $this->field($discriminatorField)->in($discriminatorValues);
460
        }
461
462 208
        if ($documentName !== null) {
463 208
            $this->collection = $this->dm->getDocumentCollection($documentName);
464 208
            $this->class = $this->dm->getClassMetadata($documentName);
465
466
            // Expr also needs to know
467 208
            $this->expr->setClassMetadata($this->class);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Doctrine\MongoDB\Query\Expr as the method setClassMetadata() does only exist in the following sub-classes of Doctrine\MongoDB\Query\Expr: Doctrine\ODM\MongoDB\Query\Expr. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
468
        }
469 208
    }
470
471
    /**
472
     * Get Discriminator Values
473
     *
474
     * @param \Iterator|array $classNames
475
     * @return array an array of discriminatorValues (mixed type)
476
     * @throws \InvalidArgumentException if the number of found collections > 1
477
     */
478 2
    private function getDiscriminatorValues($classNames)
479
    {
480 2
        $discriminatorValues = array();
481 2
        $collections = array();
482 2
        foreach ($classNames as $className) {
483 2
            $class = $this->dm->getClassMetadata($className);
484 2
            $discriminatorValues[] = $class->discriminatorValue;
485 2
            $key = $this->dm->getDocumentDatabase($className)->getName() . '.' . $class->getCollection();
486 2
            $collections[$key] = $key;
487
        }
488 2
        if (count($collections) > 1) {
489 1
            throw new \InvalidArgumentException('Documents involved are not all mapped to the same database collection.');
490
        }
491 1
        return $discriminatorValues;
492
    }
493
}
494