Failed Conditions
CANCELLED  
Pull Request — master (#7095)
by Benjamin
10:13
created

ResultSetMapping::addIndexByScalar()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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