Completed
Pull Request — master (#1518)
by Maciej
10:55
created

Builder::returnNew()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
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 require indexes.
78
     *
79
     * @var bool
80
     */
81
    private $requireIndexes;
82
83
    /**
84
     * Whether or not to register documents in UnitOfWork.
85
     *
86
     * @var bool
87
     */
88
    private $readOnly;
89
90
    /**
91
     * Construct a Builder
92
     *
93
     * @param DocumentManager $dm
94
     * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none
95
     */
96 223
    public function __construct(DocumentManager $dm, $documentName = null)
97
    {
98 223
        $this->dm = $dm;
99 223
        $this->expr = new Expr($dm);
100 223
        if ($documentName !== null) {
101 215
            $this->setDocumentName($documentName);
102
        }
103 222
    }
104
105
    /**
106
     * Set whether or not to require indexes.
107
     *
108
     * @param bool $requireIndexes
109
     * @return $this
110
     *
111
     * @deprecated method was deprecated in 1.2 and will be removed in 2.0
112
     */
113 2
    public function requireIndexes($requireIndexes = true)
114
    {
115 2
        $this->requireIndexes = $requireIndexes;
116 2
        return $this;
117
    }
118
119
    /**
120
     * Set the current field to operate on.
121
     *
122
     * @param string $field
123
     * @return $this
124
     */
125 143
    public function field($field)
126
    {
127 143
        $this->currentField = $field;
128 143
        parent::field($field);
129
130 143
        return $this;
131
    }
132
133
    /**
134
     * Use a primer to eagerly load all references in the current field.
135
     *
136
     * If $primer is true or a callable is provided, referenced documents for
137
     * this field will loaded into UnitOfWork immediately after the query is
138
     * executed. This will avoid multiple queries due to lazy initialization of
139
     * Proxy objects.
140
     *
141
     * If $primer is false, no priming will take place. That is also the default
142
     * behavior.
143
     *
144
     * If a custom callable is used, its signature should conform to the default
145
     * Closure defined in {@link ReferencePrimer::__construct()}.
146
     *
147
     * @param boolean|callable $primer
148
     * @return $this
149
     * @throws \InvalidArgumentException If $primer is not boolean or callable
150
     */
151 23
    public function prime($primer = true)
152
    {
153 23
        if ( ! is_bool($primer) && ! is_callable($primer)) {
154 1
            throw new \InvalidArgumentException('$primer is not a boolean or callable');
155
        }
156
157 22
        if ($primer === false) {
158 1
            unset($this->primers[$this->currentField]);
159
160 1
            return $this;
161
        }
162
163 22
        if (array_key_exists('eagerCursor', $this->query) && !$this->query['eagerCursor']) {
164 1
            throw new \BadMethodCallException("Can't call prime() when setting eagerCursor to false");
165
        }
166
167 21
        $this->primers[$this->currentField] = $primer;
168 21
        return $this;
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174 5
    public function eagerCursor($bool = true)
175
    {
176 5
        if ( ! $bool && ! empty($this->primers)) {
177 1
            throw new \BadMethodCallException("Can't set eagerCursor to false when using reference primers");
178
        }
179
180 4
        return parent::eagerCursor($bool);
181
    }
182
183
184
    /**
185
     * @param bool $bool
186
     * @return $this
187
     */
188 16
    public function hydrate($bool = true)
189
    {
190 16
        $this->hydrate = $bool;
191 16
        return $this;
192
    }
193
194
    /**
195
     * @param bool $bool
196
     * @return $this
197
     */
198 2
    public function readOnly($bool = true)
199
    {
200 2
        $this->readOnly = $bool;
201 2
        return $this;
202
    }
203
204
    /**
205
     * @param bool $bool
206
     * @return $this
207
     */
208 5
    public function refresh($bool = true)
209
    {
210 5
        $this->refresh = $bool;
211 5
        return $this;
212
    }
213
214
    /**
215
     * Change the query type to find and optionally set and change the class being queried.
216
     *
217
     * @param string $documentName
218
     * @return $this
219
     */
220 12
    public function find($documentName = null)
221
    {
222 12
        $this->setDocumentName($documentName);
223 12
        parent::find();
224
225 12
        return $this;
226
    }
227
228
    /**
229
     * @param string $documentName
230
     * @return $this
231
     */
232 7
    public function findAndUpdate($documentName = null)
233
    {
234 7
        $this->setDocumentName($documentName);
235 7
        parent::findAndUpdate();
236
237 7
        return $this;
238
    }
239
240
    /**
241
     * @param bool $bool
242
     * @return $this
243
     */
244 4
    public function returnNew($bool = true)
245
    {
246 4
        $this->refresh(true);
247 4
        parent::returnNew($bool);
248
249 4
        return $this;
250
    }
251
252
    /**
253
     * @param string $documentName
254
     * @return $this
255
     */
256 1
    public function findAndRemove($documentName = null)
257
    {
258 1
        $this->setDocumentName($documentName);
259 1
        parent::findAndRemove();
260
261 1
        return $this;
262
    }
263
264
    /**
265
     * @param string $documentName
266
     * @return $this
267
     *
268
     * @deprecated Deprecated in version 1.2 - use updateOne or updateMany instead
269
     */
270 12
    public function update($documentName = null)
271
    {
272 12
        $this->setDocumentName($documentName);
273 12
        parent::update();
274
275 12
        return $this;
276
    }
277
278
    /**
279
     * @param string $documentName
280
     * @return $this
281
     */
282
    public function updateOne($documentName = null)
283
    {
284
        $this->setDocumentName($documentName);
285
        // @todo use parent::updateOne when we update doctrine/mongodb
286
        parent::update();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (update() instead of updateOne()). Are you sure this is correct? If so, you might want to change this to $this->update().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
287
        parent::multiple(false);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (multiple() instead of updateOne()). Are you sure this is correct? If so, you might want to change this to $this->multiple().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
288
289
        return $this;
290
    }
291
292
    /**
293
     * @param string $documentName
294
     * @return $this
295
     */
296
    public function updateMany($documentName = null)
297
    {
298
        $this->setDocumentName($documentName);
299
        // @todo use parent::updateMany when we update doctrine/mongodb
300
        parent::update();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (update() instead of updateMany()). Are you sure this is correct? If so, you might want to change this to $this->update().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
301
        parent::multiple(true);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (multiple() instead of updateMany()). Are you sure this is correct? If so, you might want to change this to $this->multiple().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
302
303
        return $this;
304
    }
305
306
    /**
307
     * @param string $documentName
308
     * @return $this
309
     */
310 1
    public function insert($documentName = null)
311
    {
312 1
        $this->setDocumentName($documentName);
313 1
        parent::insert();
314
315 1
        return $this;
316
    }
317
318
    /**
319
     * @param string $documentName
320
     * @return $this
321
     */
322 1
    public function remove($documentName = null)
323
    {
324 1
        $this->setDocumentName($documentName);
325 1
        parent::remove();
326
327 1
        return $this;
328
    }
329
330
    /**
331
     * @param object $document
332
     * @return $this
333
     */
334 10
    public function references($document)
335
    {
336 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...
337 8
        return $this;
338
    }
339
340
    /**
341
     * @param object $document
342
     * @return $this
343
     */
344 7
    public function includesReferenceTo($document)
345
    {
346 7
        $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...
347 5
        return $this;
348
    }
349
350
    /**
351
     * Gets the Query executable.
352
     *
353
     * @param array $options
354
     * @return Query $query
355
     */
356 192
    public function getQuery(array $options = array())
357
    {
358 192
        if ($this->query['type'] === Query::TYPE_MAP_REDUCE) {
359 3
            $this->hydrate = false;
360
        }
361
362 192
        $documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name);
363
364 192
        $query = $this->query;
365
366 192
        $query['query'] = $this->expr->getQuery();
367 192
        $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...
368 192
        $query['query'] = $documentPersister->addFilterToPreparedQuery($query['query']);
369
370 192
        $query['newObj'] = $this->expr->getNewObj();
371
372 192
        if (isset($query['distinct'])) {
373 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...
374
        }
375
376 192
        if ($this->class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION && ! empty($query['upsert']) &&
377 192
            (empty($query['query'][$this->class->discriminatorField]) || is_array($query['query'][$this->class->discriminatorField]))) {
378 1
            throw new \InvalidArgumentException('Upsert query that is to be performed on discriminated document does not have single ' .
379 1
                'discriminator. Either not use base class or set \'' . $this->class->discriminatorField . '\' field manually.');
380
        }
381
382 191
        if ( ! empty($query['select'])) {
383 14
            $query['select'] = $documentPersister->prepareSortOrProjection($query['select']);
384 14
            if ($this->hydrate && $this->class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION
385 14
                && ! isset($query['select'][$this->class->discriminatorField])) {
386
                $includeMode = 0 < count(array_filter($query['select'], function($mode) { return $mode == 1; }));
387 2
                if ($includeMode && ! isset($query['select'][$this->class->discriminatorField])) {
388 1
                    $query['select'][$this->class->discriminatorField] = 1;
389
                }
390
            }
391
        }
392
393 191
        if (isset($query['sort'])) {
394 26
            $query['sort'] = $documentPersister->prepareSortOrProjection($query['sort']);
395
        }
396
397 191
        if ($this->class->slaveOkay) {
398 1
            $query['slaveOkay'] = $this->class->slaveOkay;
399
        }
400
401 191
        return new Query(
402 191
            $this->dm,
403 191
            $this->class,
404 191
            $this->collection,
405
            $query,
406
            $options,
407 191
            $this->hydrate,
408 191
            $this->refresh,
409 191
            $this->primers,
410 191
            $this->requireIndexes,
411 191
            $this->readOnly
412
        );
413
    }
414
415
    /**
416
     * Create a new Expr instance that can be used as an expression with the Builder
417
     *
418
     * @return Expr $expr
419
     */
420 25
    public function expr()
421
    {
422 25
        $expr = new Expr($this->dm);
423 25
        $expr->setClassMetadata($this->class);
424
425 25
        return $expr;
426
    }
427
428
    /**
429
     * @param string[]|string $documentName an array of document names or just one.
430
     */
431 222
    private function setDocumentName($documentName)
432
    {
433 222
        if (is_array($documentName)) {
434 2
            $documentNames = $documentName;
435 2
            $documentName = $documentNames[0];
436
437 2
            $metadata = $this->dm->getClassMetadata($documentName);
438 2
            $discriminatorField = $metadata->discriminatorField;
439 2
            $discriminatorValues = $this->getDiscriminatorValues($documentNames);
440
441
            // If a defaultDiscriminatorValue is set and it is among the discriminators being queries, add NULL to the list
442 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...
443 1
                $discriminatorValues[] = null;
444
            }
445
446 1
            $this->field($discriminatorField)->in($discriminatorValues);
447
        }
448
449 221
        if ($documentName !== null) {
450 221
            $this->collection = $this->dm->getDocumentCollection($documentName);
451 221
            $this->class = $this->dm->getClassMetadata($documentName);
452
453
            // Expr also needs to know
454 221
            $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...
455
        }
456 221
    }
457
458
    /**
459
     * Get Discriminator Values
460
     *
461
     * @param \Iterator|array $classNames
462
     * @return array an array of discriminatorValues (mixed type)
463
     * @throws \InvalidArgumentException if the number of found collections > 1
464
     */
465 2
    private function getDiscriminatorValues($classNames)
466
    {
467 2
        $discriminatorValues = array();
468 2
        $collections = array();
469 2
        foreach ($classNames as $className) {
470 2
            $class = $this->dm->getClassMetadata($className);
471 2
            $discriminatorValues[] = $class->discriminatorValue;
472 2
            $key = $this->dm->getDocumentDatabase($className)->getName() . '.' . $class->getCollection();
473 2
            $collections[$key] = $key;
474
        }
475 2
        if (count($collections) > 1) {
476 1
            throw new \InvalidArgumentException('Documents involved are not all mapped to the same database collection.');
477
        }
478 1
        return $discriminatorValues;
479
    }
480
}
481