Passed
Pull Request — master (#7244)
by
unknown
09:28
created

ResultSetMapping   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 541
Duplicated Lines 0 %

Test Coverage

Coverage 88.1%

Importance

Changes 0
Metric Value
dl 0
loc 541
rs 9
c 0
b 0
f 0
ccs 74
cts 84
cp 0.881
wmc 35

24 Methods

Rating   Name   Duplication   Size   Complexity  
A isFieldResult() 0 3 1
A getAliasMap() 0 3 1
A isScalarResult() 0 3 1
A hasParentAlias() 0 3 1
A addEntityResult() 0 10 2
A getDeclaringClass() 0 3 1
A getParentAlias() 0 3 1
A addMetaResult() 0 11 2
A getClassName() 0 3 1
A addJoinedEntityResult() 0 7 1
A hasIndexBy() 0 3 1
A addScalarResult() 0 10 3
A getEntityResultCount() 0 3 1
B addIndexBy() 0 28 4
A addIndexByScalar() 0 5 1
A isRelation() 0 3 1
A getEntityAlias() 0 3 1
A isMixedResult() 0 3 1
A getScalarAlias() 0 3 1
A setDiscriminatorColumn() 0 6 1
B addFieldResult() 0 20 5
A getRelation() 0 3 1
A getFieldName() 0 3 1
A addIndexByColumn() 0 5 1
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
use function array_key_exists;
10
use function array_merge;
11
use function count;
12
use function sprintf;
13
14
/**
15
 * A ResultSetMapping describes how a result set of an SQL query maps to a Doctrine result.
16
 *
17
 * IMPORTANT NOTE:
18
 * The properties of this class are only public for fast internal READ access and to (drastically)
19
 * reduce the size of serialized instances for more effective caching due to better (un-)serialization
20
 * performance.
21
 *
22
 * <b>Users should use the public methods.</b>
23
 *
24
 * @todo Think about whether the number of lookup maps can be reduced.
25
 */
26
class ResultSetMapping
27
{
28
    /**
29
     * Whether the result is mixed (contains scalar values together with field values).
30
     *
31
     * @ignore
32
     * @var bool
33
     */
34
    public $isMixed = false;
35
36
    /**
37
     * Whether the result is a select statement.
38
     *
39
     * @ignore
40
     * @var bool
41
     */
42
    public $isSelect = true;
43
44
    /**
45
     * Maps alias names to class names.
46
     *
47
     * @ignore
48
     * @var string[]
49
     */
50
    public $aliasMap = [];
51
52
    /**
53
     * Maps alias names to related association field names.
54
     *
55
     * @ignore
56
     * @var string[]
57
     */
58
    public $relationMap = [];
59
60
    /**
61
     * Maps alias names to parent alias names.
62
     *
63
     * @ignore
64
     * @var string[]
65
     */
66
    public $parentAliasMap = [];
67
68
    /**
69
     * Maps column names in the result set to field names for each class.
70
     *
71
     * @ignore
72
     * @var string[]
73
     */
74
    public $fieldMappings = [];
75
76
    /**
77
     * Maps column names in the result set to the alias/field name to use in the mapped result.
78
     *
79
     * @ignore
80
     * @var string[]
81
     */
82
    public $scalarMappings = [];
83
84
    /**
85
     * Maps column names in the result set to the alias/field type to use in the mapped result.
86
     *
87
     * @ignore
88
     * @var Type[]
89
     */
90
    public $typeMappings = [];
91
92
    /**
93
     * Maps entities in the result set to the alias name to use in the mapped result.
94
     *
95
     * @ignore
96
     * @var string[]
97
     */
98
    public $entityMappings = [];
99
100
    /**
101
     * Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names.
102
     *
103
     * @ignore
104
     * @var string[]
105
     */
106
    public $metaMappings = [];
107
108
    /**
109
     * Maps column names in the result set to the alias they belong to.
110
     *
111
     * @ignore
112
     * @var string[]
113
     */
114
    public $columnOwnerMap = [];
115
116
    /**
117
     * List of columns in the result set that are used as discriminator columns.
118
     *
119
     * @ignore
120
     * @var string[]
121
     */
122
    public $discriminatorColumns = [];
123
124
    /**
125
     * Maps alias names to field names that should be used for indexing.
126
     *
127
     * @ignore
128
     * @var string[]
129
     */
130
    public $indexByMap = [];
131
132
    /**
133
     * Map from column names to class names that declare the field the column is mapped to.
134
     *
135
     * @ignore
136
     * @var string[]
137
     */
138
    public $declaringClasses = [];
139
140
    /**
141
     * This is necessary to hydrate derivate foreign keys correctly.
142
     *
143
     * @var bool[][]
144
     */
145
    public $isIdentifierColumn = [];
146
147
    /**
148
     * Maps column names in the result set to field names for each new object expression.
149
     *
150
     * @var mixed[][]
151
     */
152
    public $newObjectMappings = [];
153
154
    /**
155
     * Maps metadata parameter names to the metadata attribute.
156
     *
157
     * @var mixed[]
158
     */
159
    public $metadataParameterMapping = [];
160
161
    /**
162
     * Contains query parameter names to be resolved as discriminator values
163
     *
164
     * @var string[]
165
     */
166
    public $discriminatorParameters = [];
167
168
    /**
169
     * Adds an entity result to this ResultSetMapping.
170
     *
171
     * @param string      $class       The class name of the entity.
172
     * @param string      $alias       The alias for the class. The alias must be unique among all entity
173
     *                                 results or joined entity results within this ResultSetMapping.
174
     * @param string|null $resultAlias The result alias with which the entity result should be
175
     *                                 placed in the result structure.
176
     *
177
     * @return ResultSetMapping This ResultSetMapping instance.
178
     *
179
     * @todo Rename: addRootEntity
180
     */
181 1084
    public function addEntityResult($class, $alias, $resultAlias = null)
182
    {
183 1084
        $this->aliasMap[$alias]       = $class;
184 1084
        $this->entityMappings[$alias] = $resultAlias;
185
186 1084
        if ($resultAlias !== null) {
187 45
            $this->isMixed = true;
188
        }
189
190 1084
        return $this;
191
    }
192
193
    /**
194
     * Sets a discriminator column for an entity result or joined entity result.
195
     * The discriminator column will be used to determine the concrete class name to
196
     * instantiate.
197
     *
198
     * @param string $alias       The alias of the entity result or joined entity result the discriminator
199
     *                            column should be used for.
200
     * @param string $discrColumn The name of the discriminator column in the SQL result set.
201
     *
202
     * @return ResultSetMapping This ResultSetMapping instance.
203
     *
204
     * @todo Rename: addDiscriminatorColumn
205
     */
206 181
    public function setDiscriminatorColumn($alias, $discrColumn)
207
    {
208 181
        $this->discriminatorColumns[$alias] = $discrColumn;
209 181
        $this->columnOwnerMap[$discrColumn] = $alias;
210
211 181
        return $this;
212
    }
213
214
    /**
215
     * Sets a field to use for indexing an entity result or joined entity result.
216
     *
217
     * @param string $alias     The alias of an entity result or joined entity result.
218
     * @param string $fieldName The name of the field to use for indexing.
219
     *
220
     * @return ResultSetMapping This ResultSetMapping instance.
221
     */
222 42
    public function addIndexBy($alias, $fieldName)
223
    {
224 42
        $found = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $found is dead and can be removed.
Loading history...
225
226 42
        foreach (array_merge($this->metaMappings, $this->fieldMappings) as $columnName => $columnFieldName) {
227 42
            if (! ($columnFieldName === $fieldName && $this->columnOwnerMap[$columnName] === $alias)) {
228 32
                continue;
229
            }
230
231 40
            $this->addIndexByColumn($alias, $columnName);
232 40
            $found = true;
233
234 40
            break;
235
        }
236
237
        /* TODO: check if this exception can be put back, for now it's gone because of assumptions made by some ORM internals
238
        if ( ! $found) {
239
            $message = sprintf(
240
                'Cannot add index by for DQL alias %s and field %s without calling addFieldResult() for them before.',
241
                $alias,
242
                $fieldName
243
            );
244
245
            throw new \LogicException($message);
246
        }
247
        */
248
249 42
        return $this;
250
    }
251
252
    /**
253
     * Sets to index by a scalar result column name.
254
     *
255
     * @param string $resultColumnName
256
     *
257
     * @return ResultSetMapping This ResultSetMapping instance.
258
     */
259 3
    public function addIndexByScalar($resultColumnName)
260
    {
261 3
        $this->indexByMap['scalars'] = $resultColumnName;
262
263 3
        return $this;
264
    }
265
266
    /**
267
     * Sets a column to use for indexing an entity or joined entity result by the given alias name.
268
     *
269
     * @param string $alias
270
     * @param string $resultColumnName
271
     *
272
     * @return ResultSetMapping This ResultSetMapping instance.
273
     */
274 41
    public function addIndexByColumn($alias, $resultColumnName)
275
    {
276 41
        $this->indexByMap[$alias] = $resultColumnName;
277
278 41
        return $this;
279
    }
280
281
    /**
282
     * Checks whether an entity result or joined entity result with a given alias has
283
     * a field set for indexing.
284
     *
285
     * @param string $alias
286
     *
287
     * @return bool
288
     *
289
     * @todo Rename: isIndexed($alias)
290
     */
291 2
    public function hasIndexBy($alias)
292
    {
293 2
        return isset($this->indexByMap[$alias]);
294
    }
295
296
    /**
297
     * Checks whether the column with the given name is mapped as a field result
298
     * as part of an entity result or joined entity result.
299
     *
300
     * @param string $columnName The name of the column in the SQL result set.
301
     *
302
     * @return bool
303
     *
304
     * @todo Rename: isField
305
     */
306 1
    public function isFieldResult($columnName)
307
    {
308 1
        return isset($this->fieldMappings[$columnName]);
309
    }
310
311
    /**
312
     * Adds a field to the result that belongs to an entity or joined entity.
313
     *
314
     * @param string      $alias          The alias of the root entity or joined entity to which the field belongs.
315
     * @param string      $columnName     The name of the column in the SQL result set.
316
     * @param string      $fieldName      The name of the field on the declaring class.
317
     * @param string|null $declaringClass The name of the class that declares/owns the specified field.
318
     *                                    When $alias refers to a superclass in a mapped hierarchy but
319
     *                                    the field $fieldName is defined on a subclass, specify that here.
320
     *                                    If not specified, the field is assumed to belong to the class
321
     *                                    designated by $alias.
322
     *
323
     * @return ResultSetMapping This ResultSetMapping instance.
324
     *
325
     * @todo Rename: addField
326
     */
327 1068
    public function addFieldResult($alias, $columnName, $fieldName, $declaringClass = null)
328
    {
329
        // column name (in result set) => field name
330 1068
        $this->fieldMappings[$columnName] = $fieldName;
331
        // column name => alias of owner
332 1068
        $this->columnOwnerMap[$columnName] = $alias;
333
        // field name => class name of declaring class
334 1068
        if ($declaringClass) {
335 945
            $this->declaringClasses[$columnName] = $declaringClass;
336 140
        } elseif (array_key_exists($alias, $this->aliasMap)) {
337 140
            $this->declaringClasses[$columnName] = $this->aliasMap[$alias];
338
        } else {
339 1
            throw new \LogicException(sprintf('Alias %s does not exist in alias map', $alias));
340
        }
341
342 1068
        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...
343 10
            $this->isMixed = true;
344
        }
345
346 1068
        return $this;
347
    }
348
349
    /**
350
     * Adds a joined entity result.
351
     *
352
     * @param string $class       The class name of the joined entity.
353
     * @param string $alias       The unique alias to use for the joined entity.
354
     * @param string $parentAlias The alias of the entity result that is the parent of this joined result.
355
     * @param string $relation    The association field that connects the parent entity result
356
     *                            with the joined entity result.
357
     *
358
     * @return ResultSetMapping This ResultSetMapping instance.
359
     *
360
     * @todo Rename: addJoinedEntity
361
     */
362 367
    public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
363
    {
364 367
        $this->aliasMap[$alias]       = $class;
365 367
        $this->parentAliasMap[$alias] = $parentAlias;
366 367
        $this->relationMap[$alias]    = $relation;
367
368 367
        return $this;
369
    }
370
371
    /**
372
     * Adds a scalar result mapping.
373
     *
374
     * @param string $columnName The name of the column in the SQL result set.
375
     * @param string $alias      The result alias with which the scalar result should be placed in the result structure.
376
     * @param Type   $type       The column type
377
     *
378
     * @return ResultSetMapping This ResultSetMapping instance.
379
     *
380
     * @todo Rename: addScalar
381
     */
382 341
    public function addScalarResult($columnName, $alias, Type $type)
383
    {
384 341
        $this->scalarMappings[$columnName] = $alias;
385 341
        $this->typeMappings[$columnName]   = $type;
386
387 341
        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...
388 116
            $this->isMixed = true;
389
        }
390
391 341
        return $this;
392
    }
393
394
    /**
395
     * Checks whether a column with a given name is mapped as a scalar result.
396
     *
397
     * @param string $columnName The name of the column in the SQL result set.
398
     *
399
     * @return bool
400
     *
401
     * @todo Rename: isScalar
402
     */
403 2
    public function isScalarResult($columnName)
404
    {
405 2
        return isset($this->scalarMappings[$columnName]);
406
    }
407
408
    /**
409
     * Gets the name of the class of an entity result or joined entity result,
410
     * identified by the given unique alias.
411
     *
412
     * @param string $alias
413
     *
414
     * @return string
415
     */
416 2
    public function getClassName($alias)
417
    {
418 2
        return $this->aliasMap[$alias];
419
    }
420
421
    /**
422
     * Gets the field alias for a column that is mapped as a scalar value.
423
     *
424
     * @param string $columnName The name of the column in the SQL result set.
425
     *
426
     * @return string
427
     */
428
    public function getScalarAlias($columnName)
429
    {
430
        return $this->scalarMappings[$columnName];
431
    }
432
433
    /**
434
     * Gets the name of the class that owns a field mapping for the specified column.
435
     *
436
     * @param string $columnName
437
     *
438
     * @return string
439
     */
440 1
    public function getDeclaringClass($columnName)
441
    {
442 1
        return $this->declaringClasses[$columnName];
443
    }
444
445
    /**
446
     * @param string $alias
447
     *
448
     * @return AssociationMetadata
449
     */
450
    public function getRelation($alias)
451
    {
452
        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...
453
    }
454
455
    /**
456
     * @param string $alias
457
     *
458
     * @return bool
459
     */
460 1
    public function isRelation($alias)
461
    {
462 1
        return isset($this->relationMap[$alias]);
463
    }
464
465
    /**
466
     * Gets the alias of the class that owns a field mapping for the specified column.
467
     *
468
     * @param string $columnName
469
     *
470
     * @return string
471
     */
472 1
    public function getEntityAlias($columnName)
473
    {
474 1
        return $this->columnOwnerMap[$columnName];
475
    }
476
477
    /**
478
     * Gets the parent alias of the given alias.
479
     *
480
     * @param string $alias
481
     *
482
     * @return string
483
     */
484
    public function getParentAlias($alias)
485
    {
486
        return $this->parentAliasMap[$alias];
487
    }
488
489
    /**
490
     * Checks whether the given alias has a parent alias.
491
     *
492
     * @param string $alias
493
     *
494
     * @return bool
495
     */
496 1
    public function hasParentAlias($alias)
497
    {
498 1
        return isset($this->parentAliasMap[$alias]);
499
    }
500
501
    /**
502
     * Gets the field name for a column name.
503
     *
504
     * @param string $columnName
505
     *
506
     * @return string
507
     */
508 1
    public function getFieldName($columnName)
509
    {
510 1
        return $this->fieldMappings[$columnName];
511
    }
512
513
    /**
514
     * @return string[]
515
     */
516
    public function getAliasMap()
517
    {
518
        return $this->aliasMap;
519
    }
520
521
    /**
522
     * Gets the number of different entities that appear in the mapped result.
523
     *
524
     * @return int
525
     */
526
    public function getEntityResultCount()
527
    {
528
        return count($this->aliasMap);
529
    }
530
531
    /**
532
     * Checks whether this ResultSetMapping defines a mixed result.
533
     *
534
     * Mixed results can only occur in object and array (graph) hydration. In such a
535
     * case a mixed result means that scalar values are mixed with objects/array in
536
     * the result.
537
     *
538
     * @return bool
539
     */
540 1
    public function isMixedResult()
541
    {
542 1
        return $this->isMixed;
543
    }
544
545
    /**
546
     * Adds a meta column (foreign key or discriminator column) to the result set.
547
     *
548
     * @param string $alias              The result alias with which the meta result should be placed in the result structure.
549
     * @param string $columnName         The name of the column in the SQL result set.
550
     * @param string $fieldName          The name of the field on the declaring class.
551
     * @param bool   $isIdentifierColumn
552
     * @param Type   $type               The column type
553
     *
554
     * @return ResultSetMapping This ResultSetMapping instance.
555
     */
556 728
    public function addMetaResult($alias, $columnName, $fieldName, $isIdentifierColumn, Type $type)
557
    {
558 728
        $this->metaMappings[$columnName]   = $fieldName;
559 728
        $this->columnOwnerMap[$columnName] = $alias;
560 728
        $this->typeMappings[$columnName]   = $type;
561
562 728
        if ($isIdentifierColumn) {
563 66
            $this->isIdentifierColumn[$alias][$columnName] = true;
564
        }
565
566 728
        return $this;
567
    }
568
}
569