Passed
Pull Request — master (#6709)
by Sergey
12:37
created

ResultSetMapping::getEntityResultCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Query;
6
7
use Doctrine\DBAL\Types\Type;
8
use Doctrine\ORM\Mapping\AssociationMetadata;
9
10
/**
11
 * A ResultSetMapping describes how a result set of an SQL query maps to a Doctrine result.
12
 *
13
 * IMPORTANT NOTE:
14
 * The properties of this class are only public for fast internal READ access and to (drastically)
15
 * reduce the size of serialized instances for more effective caching due to better (un-)serialization
16
 * performance.
17
 *
18
 * <b>Users should use the public methods.</b>
19
 *
20
 * @todo Think about whether the number of lookup maps can be reduced.
21
 */
22
class ResultSetMapping
23
{
24
    /**
25
     * Whether the result is mixed (contains scalar values together with field values).
26
     *
27
     * @ignore
28
     * @var bool
29
     */
30
    public $isMixed = false;
31
32
    /**
33
     * Whether the result is a select statement.
34
     *
35
     * @ignore
36
     * @var bool
37
     */
38
    public $isSelect = true;
39
40
    /**
41
     * Maps alias names to class names.
42
     *
43
     * @ignore
44
     * @var string[]
45
     */
46
    public $aliasMap = [];
47
48
    /**
49
     * Maps alias names to related association field names.
50
     *
51
     * @ignore
52
     * @var string[]
53
     */
54
    public $relationMap = [];
55
56
    /**
57
     * Maps alias names to parent alias names.
58
     *
59
     * @ignore
60
     * @var string[]
61
     */
62
    public $parentAliasMap = [];
63
64
    /**
65
     * Maps column names in the result set to field names for each class.
66
     *
67
     * @ignore
68
     * @var string[]
69
     */
70
    public $fieldMappings = [];
71
72
    /**
73
     * Maps column names in the result set to the alias/field name to use in the mapped result.
74
     *
75
     * @ignore
76
     * @var string[]
77
     */
78
    public $scalarMappings = [];
79
80
    /**
81
     * Maps column names in the result set to the alias/field type to use in the mapped result.
82
     *
83
     * @ignore
84
     * @var Type[]
85
     */
86
    public $typeMappings = [];
87
88
    /**
89
     * Maps entities in the result set to the alias name to use in the mapped result.
90
     *
91
     * @ignore
92
     * @var string[]
93
     */
94
    public $entityMappings = [];
95
96
    /**
97
     * Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names.
98
     *
99
     * @ignore
100
     * @var string[]
101
     */
102
    public $metaMappings = [];
103
104
    /**
105
     * Maps column names in the result set to the alias they belong to.
106
     *
107
     * @ignore
108
     * @var string[]
109
     */
110
    public $columnOwnerMap = [];
111
112
    /**
113
     * List of columns in the result set that are used as discriminator columns.
114
     *
115
     * @ignore
116
     * @var string[]
117
     */
118
    public $discriminatorColumns = [];
119
120
    /**
121
     * Maps alias names to field names that should be used for indexing.
122
     *
123
     * @ignore
124
     * @var string[]
125
     */
126
    public $indexByMap = [];
127
128
    /**
129
     * Map from column names to class names that declare the field the column is mapped to.
130
     *
131
     * @ignore
132
     * @var string[]
133
     */
134
    public $declaringClasses = [];
135
136
    /**
137
     * This is necessary to hydrate derivate foreign keys correctly.
138
     *
139
     * @var bool[][]
140
     */
141
    public $isIdentifierColumn = [];
142
143
    /**
144
     * Maps column names in the result set to field names for each new object expression.
145
     *
146
     * @var mixed[][]
147
     */
148
    public $newObjectMappings = [];
149
150
    /**
151
     * Maps last argument for new objects in order to initiate object construction
152
     *
153
     * @var array
154
     */
155
    public $nestedNewObjectArguments = [];
156
157
    /**
158
     * Maps metadata parameter names to the metadata attribute.
159
     *
160
     * @var mixed[]
161
     */
162
    public $metadataParameterMapping = [];
163
164
    /**
165
     * Contains query parameter names to be resolved as discriminator values
166
     *
167
     * @var string[]
168
     */
169
    public $discriminatorParameters = [];
170
171
    /**
172
     * Adds an entity result to this ResultSetMapping.
173
     *
174
     * @param string      $class       The class name of the entity.
175
     * @param string      $alias       The alias for the class. The alias must be unique among all entity
176
     *                                 results or joined entity results within this ResultSetMapping.
177
     * @param string|null $resultAlias The result alias with which the entity result should be
178
     *                                 placed in the result structure.
179
     *
180
     * @return ResultSetMapping This ResultSetMapping instance.
181
     *
182
     * @todo Rename: addRootEntity
183
     */
184 1095
    public function addEntityResult($class, $alias, $resultAlias = null)
185
    {
186 1095
        $this->aliasMap[$alias]       = $class;
187 1095
        $this->entityMappings[$alias] = $resultAlias;
188
189 1095
        if ($resultAlias !== null) {
190 45
            $this->isMixed = true;
191
        }
192
193 1095
        return $this;
194
    }
195
196
    /**
197
     * Sets a discriminator column for an entity result or joined entity result.
198
     * The discriminator column will be used to determine the concrete class name to
199
     * instantiate.
200
     *
201
     * @param string $alias       The alias of the entity result or joined entity result the discriminator
202
     *                            column should be used for.
203
     * @param string $discrColumn The name of the discriminator column in the SQL result set.
204
     *
205
     * @return ResultSetMapping This ResultSetMapping instance.
206
     *
207
     * @todo Rename: addDiscriminatorColumn
208
     */
209 178
    public function setDiscriminatorColumn($alias, $discrColumn)
210
    {
211 178
        $this->discriminatorColumns[$alias] = $discrColumn;
212 178
        $this->columnOwnerMap[$discrColumn] = $alias;
213
214 178
        return $this;
215
    }
216
217
    /**
218
     * Sets a field to use for indexing an entity result or joined entity result.
219
     *
220
     * @param string $alias     The alias of an entity result or joined entity result.
221
     * @param string $fieldName The name of the field to use for indexing.
222
     *
223
     * @return ResultSetMapping This ResultSetMapping instance.
224
     */
225 42
    public function addIndexBy($alias, $fieldName)
226
    {
227 42
        $found = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $found is dead and can be removed.
Loading history...
228
229 42
        foreach (array_merge($this->metaMappings, $this->fieldMappings) as $columnName => $columnFieldName) {
230 42
            if (! ($columnFieldName === $fieldName && $this->columnOwnerMap[$columnName] === $alias)) {
231 32
                continue;
232
            }
233
234 40
            $this->addIndexByColumn($alias, $columnName);
235 40
            $found = true;
236
237 40
            break;
238
        }
239
240
        /* TODO: check if this exception can be put back, for now it's gone because of assumptions made by some ORM internals
241
        if ( ! $found) {
242
            $message = sprintf(
243
                'Cannot add index by for DQL alias %s and field %s without calling addFieldResult() for them before.',
244
                $alias,
245
                $fieldName
246
            );
247
248
            throw new \LogicException($message);
249
        }
250
        */
251
252 42
        return $this;
253
    }
254
255
    /**
256
     * Sets to index by a scalar result column name.
257
     *
258
     * @param string $resultColumnName
259
     *
260
     * @return ResultSetMapping This ResultSetMapping instance.
261
     */
262 3
    public function addIndexByScalar($resultColumnName)
263
    {
264 3
        $this->indexByMap['scalars'] = $resultColumnName;
265
266 3
        return $this;
267
    }
268
269
    /**
270
     * Sets a column to use for indexing an entity or joined entity result by the given alias name.
271
     *
272
     * @param string $alias
273
     * @param string $resultColumnName
274
     *
275
     * @return ResultSetMapping This ResultSetMapping instance.
276
     */
277 41
    public function addIndexByColumn($alias, $resultColumnName)
278
    {
279 41
        $this->indexByMap[$alias] = $resultColumnName;
280
281 41
        return $this;
282
    }
283
284
    /**
285
     * Checks whether an entity result or joined entity result with a given alias has
286
     * a field set for indexing.
287
     *
288
     * @param string $alias
289
     *
290
     * @return bool
291
     *
292
     * @todo Rename: isIndexed($alias)
293
     */
294 2
    public function hasIndexBy($alias)
295
    {
296 2
        return isset($this->indexByMap[$alias]);
297
    }
298
299
    /**
300
     * Checks whether the column with the given name is mapped as a field result
301
     * as part of an entity result or joined entity result.
302
     *
303
     * @param string $columnName The name of the column in the SQL result set.
304
     *
305
     * @return bool
306
     *
307
     * @todo Rename: isField
308
     */
309 1
    public function isFieldResult($columnName)
310
    {
311 1
        return isset($this->fieldMappings[$columnName]);
312
    }
313
314
    /**
315
     * Adds a field to the result that belongs to an entity or joined entity.
316
     *
317
     * @param string      $alias          The alias of the root entity or joined entity to which the field belongs.
318
     * @param string      $columnName     The name of the column in the SQL result set.
319
     * @param string      $fieldName      The name of the field on the declaring class.
320
     * @param string|null $declaringClass The name of the class that declares/owns the specified field.
321
     *                                    When $alias refers to a superclass in a mapped hierarchy but
322
     *                                    the field $fieldName is defined on a subclass, specify that here.
323
     *                                    If not specified, the field is assumed to belong to the class
324
     *                                    designated by $alias.
325
     *
326
     * @return ResultSetMapping This ResultSetMapping instance.
327
     *
328
     * @todo Rename: addField
329
     */
330 1079
    public function addFieldResult($alias, $columnName, $fieldName, $declaringClass = null)
331
    {
332
        // column name (in result set) => field name
333 1079
        $this->fieldMappings[$columnName] = $fieldName;
334
        // column name => alias of owner
335 1079
        $this->columnOwnerMap[$columnName] = $alias;
336
        // field name => class name of declaring class
337 1079
        $this->declaringClasses[$columnName] = $declaringClass ?: $this->aliasMap[$alias];
338
339 1079
        if (! $this->isMixed && $this->scalarMappings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->scalarMappings of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
340 10
            $this->isMixed = true;
341
        }
342
343 1079
        return $this;
344
    }
345
346
    /**
347
     * Adds a joined entity result.
348
     *
349
     * @param string $class       The class name of the joined entity.
350
     * @param string $alias       The unique alias to use for the joined entity.
351
     * @param string $parentAlias The alias of the entity result that is the parent of this joined result.
352
     * @param string $relation    The association field that connects the parent entity result
353
     *                            with the joined entity result.
354
     *
355
     * @return ResultSetMapping This ResultSetMapping instance.
356
     *
357
     * @todo Rename: addJoinedEntity
358
     */
359 370
    public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
360
    {
361 370
        $this->aliasMap[$alias]       = $class;
362 370
        $this->parentAliasMap[$alias] = $parentAlias;
363 370
        $this->relationMap[$alias]    = $relation;
364
365 370
        return $this;
366
    }
367
368
    /**
369
     * Adds a scalar result mapping.
370
     *
371
     * @param string $columnName The name of the column in the SQL result set.
372
     * @param string $alias      The result alias with which the scalar result should be placed in the result structure.
373
     * @param Type   $type       The column type
374
     *
375
     * @return ResultSetMapping This ResultSetMapping instance.
376
     *
377
     * @todo Rename: addScalar
378
     */
379 344
    public function addScalarResult($columnName, $alias, Type $type)
380
    {
381 344
        $this->scalarMappings[$columnName] = $alias;
382 344
        $this->typeMappings[$columnName]   = $type;
383
384 344
        if (! $this->isMixed && $this->fieldMappings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fieldMappings of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
385 120
            $this->isMixed = true;
386
        }
387
388 344
        return $this;
389
    }
390
391
    /**
392
     * Checks whether a column with a given name is mapped as a scalar result.
393
     *
394
     * @param string $columnName The name of the column in the SQL result set.
395
     *
396
     * @return bool
397
     *
398
     * @todo Rename: isScalar
399
     */
400 2
    public function isScalarResult($columnName)
401
    {
402 2
        return isset($this->scalarMappings[$columnName]);
403
    }
404
405
    /**
406
     * Gets the name of the class of an entity result or joined entity result,
407
     * identified by the given unique alias.
408
     *
409
     * @param string $alias
410
     *
411
     * @return string
412
     */
413 7
    public function getClassName($alias)
414
    {
415 7
        return $this->aliasMap[$alias];
416
    }
417
418
    /**
419
     * Gets the field alias for a column that is mapped as a scalar value.
420
     *
421
     * @param string $columnName The name of the column in the SQL result set.
422
     *
423
     * @return string
424
     */
425 2
    public function getScalarAlias($columnName)
426
    {
427 2
        return $this->scalarMappings[$columnName];
428
    }
429
430
    /**
431
     * Gets the name of the class that owns a field mapping for the specified column.
432
     *
433
     * @param string $columnName
434
     *
435
     * @return string
436
     */
437 4
    public function getDeclaringClass($columnName)
438
    {
439 4
        return $this->declaringClasses[$columnName];
440
    }
441
442
    /**
443
     * @param string $alias
444
     *
445
     * @return AssociationMetadata
446
     */
447
    public function getRelation($alias)
448
    {
449
        return $this->relationMap[$alias];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->relationMap[$alias] returns the type string which is incompatible with the documented return type Doctrine\ORM\Mapping\AssociationMetadata.
Loading history...
450
    }
451
452
    /**
453
     * @param string $alias
454
     *
455
     * @return bool
456
     */
457 1
    public function isRelation($alias)
458
    {
459 1
        return isset($this->relationMap[$alias]);
460
    }
461
462
    /**
463
     * Gets the alias of the class that owns a field mapping for the specified column.
464
     *
465
     * @param string $columnName
466
     *
467
     * @return string
468
     */
469 4
    public function getEntityAlias($columnName)
470
    {
471 4
        return $this->columnOwnerMap[$columnName];
472
    }
473
474
    /**
475
     * Gets the parent alias of the given alias.
476
     *
477
     * @param string $alias
478
     *
479
     * @return string
480
     */
481
    public function getParentAlias($alias)
482
    {
483
        return $this->parentAliasMap[$alias];
484
    }
485
486
    /**
487
     * Checks whether the given alias has a parent alias.
488
     *
489
     * @param string $alias
490
     *
491
     * @return bool
492
     */
493 1
    public function hasParentAlias($alias)
494
    {
495 1
        return isset($this->parentAliasMap[$alias]);
496
    }
497
498
    /**
499
     * Gets the field name for a column name.
500
     *
501
     * @param string $columnName
502
     *
503
     * @return string
504
     */
505 1
    public function getFieldName($columnName)
506
    {
507 1
        return $this->fieldMappings[$columnName];
508
    }
509
510
    /**
511
     * @return string[]
512
     */
513
    public function getAliasMap()
514
    {
515
        return $this->aliasMap;
516
    }
517
518
    /**
519
     * Gets the number of different entities that appear in the mapped result.
520
     *
521
     * @return int
522
     */
523
    public function getEntityResultCount()
524
    {
525
        return count($this->aliasMap);
526
    }
527
528
    /**
529
     * Checks whether this ResultSetMapping defines a mixed result.
530
     *
531
     * Mixed results can only occur in object and array (graph) hydration. In such a
532
     * case a mixed result means that scalar values are mixed with objects/array in
533
     * the result.
534
     *
535
     * @return bool
536
     */
537 1
    public function isMixedResult()
538
    {
539 1
        return $this->isMixed;
540
    }
541
542
    /**
543
     * Adds a meta column (foreign key or discriminator column) to the result set.
544
     *
545
     * @param string $alias              The result alias with which the meta result should be placed in the result structure.
546
     * @param string $columnName         The name of the column in the SQL result set.
547
     * @param string $fieldName          The name of the field on the declaring class.
548
     * @param bool   $isIdentifierColumn
549
     * @param Type   $type               The column type
550
     *
551
     * @return ResultSetMapping This ResultSetMapping instance.
552
     */
553 735
    public function addMetaResult($alias, $columnName, $fieldName, $isIdentifierColumn, Type $type)
554
    {
555 735
        $this->metaMappings[$columnName]   = $fieldName;
556 735
        $this->columnOwnerMap[$columnName] = $alias;
557 735
        $this->typeMappings[$columnName]   = $type;
558
559 735
        if ($isIdentifierColumn) {
560 65
            $this->isIdentifierColumn[$alias][$columnName] = true;
561
        }
562
563 735
        return $this;
564
    }
565
566 2
    public function addNewObjectAsArgument($alias, $objOwner, $objOwnerIdx)
567
    {
568
        $owner = [
569 2
            'ownerIndex' => $objOwner,
570 2
            'argIndex' => $objOwnerIdx,
571
        ];
572
573 2
        if (!isset($this->nestedNewObjectArguments[$owner['ownerIndex']])) {
574 2
            $this->nestedNewObjectArguments[$alias] = $owner;
575
576 2
            return;
577
        }
578
579 2
        $this->nestedNewObjectArguments = array_merge(
580 2
            [$alias => $owner],
581 2
            $this->nestedNewObjectArguments
582
        );
583 2
    }
584
}
585