Passed
Pull Request — 2.x (#528)
by Aleksei
17:59
created

RootLoader::forceGroupBy()   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 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\ORM\Select;
6
7
use Cycle\Database\Query\SelectQuery;
8
use Cycle\Database\StatementInterface;
9
use Cycle\ORM\FactoryInterface;
10
use Cycle\ORM\Parser\AbstractNode;
11
use Cycle\ORM\Parser\RootNode;
12
use Cycle\ORM\Service\SourceProviderInterface;
13
use Cycle\ORM\SchemaInterface;
14
use Cycle\ORM\Select\Traits\ColumnsTrait;
15
use Cycle\ORM\Select\Traits\ScopeTrait;
16
17
/**
18
 * Primary ORM loader. Loader wraps at top of select query in order to modify it's conditions, joins
19
 * and etc based on nested loaders.
20
 *
21
 * Root load does not load constrain from ORM by default.
22
 *
23
 * @method RootNode createNode()
24
 *
25
 * @internal
26
 */
27
final class RootLoader extends AbstractLoader
28
{
29
    use ColumnsTrait;
30
    use ScopeTrait;
31
32
    protected array $options = [
33
        'load' => true,
34
        'scope' => true,
35
    ];
36
    private SelectQuery $query;
37
    private bool $forceGroupBy = false;
38
39
    /**
40 6834
     * @param bool $loadRelations Define loading eager relations and JTI hierarchy.
41
     */
42
    public function __construct(
43
        SchemaInterface $ormSchema,
44
        SourceProviderInterface $sourceProvider,
45
        FactoryInterface $factory,
46 6834
        string $target,
47 6834
        bool $loadRelations = true,
48 6834
    ) {
49
        parent::__construct($ormSchema, $sourceProvider, $factory, $target);
50 6834
        $this->query = $this->source->getDatabase()->select()->from(
51
            \sprintf('%s AS %s', $this->source->getTable(), $this->getAlias()),
52 6834
        );
53 1288
        $this->columns = $this->normalizeColumns($this->define(SchemaInterface::COLUMNS));
54
55
        if ($loadRelations) {
56
            foreach ($this->getEagerLoaders() as $relation) {
57
                $this->loadRelation($relation, [], false, true);
58
            }
59
        }
60 3232
    }
61
62 3232
    public function getAlias(): string
63 3232
    {
64
        return $this->target;
65
    }
66 6834
67
    /**
68 6834
     * Primary column name list with table name like `table.column`.
69
     *
70
     * @return string|string[]
71
     */
72
    public function getPK(): array|string
73
    {
74
        $pk = $this->define(SchemaInterface::PRIMARY_KEY);
75
        if (\is_array($pk)) {
76 2152
            $result = [];
77
            foreach ($pk as $key) {
78 2152
                $result[] = $this->getAlias() . '.' . $this->fieldAlias($key);
79 2152
            }
80 400
            return $result;
81 400
        }
82 400
83
        return $this->getAlias() . '.' . $this->fieldAlias($pk);
84 400
    }
85
86
    /**
87 1752
     * Get list of primary fields.
88
     *
89
     * @return list<non-empty-string>
0 ignored issues
show
Bug introduced by
The type Cycle\ORM\Select\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
90
     */
91
    public function getPrimaryFields(): array
92
    {
93 6834
        return (array) $this->define(SchemaInterface::PRIMARY_KEY);
0 ignored issues
show
Bug Best Practice introduced by
The expression return (array)$this->def...Interface::PRIMARY_KEY) returns the type array which is incompatible with the documented return type Cycle\ORM\Select\list.
Loading history...
94
    }
95 6834
96
    /**
97
     * Return base query associated with the loader.
98
     */
99
    public function getQuery(): SelectQuery
100
    {
101 6494
        return $this->query;
102
    }
103 6494
104
    /**
105
     * Compile query with all needed conditions, columns and etc.
106 6382
     */
107
    public function buildQuery(): SelectQuery
108 6382
    {
109
        return $this->configureQuery(clone $this->query);
110 6334
    }
111 6286
112
    public function loadData(AbstractNode $node, bool $includeRole = false): void
113
    {
114 6334
        $statement = $this->buildQuery()->run();
115
116
        foreach ($statement->fetchAll(StatementInterface::FETCH_NUM) as $row) {
117 6334
            $node->parseRow(0, $row);
118 3154
        }
119
120
        $statement->close();
121 6334
122
        // loading child datasets
123
        foreach ($this->load as $relation => $loader) {
124 232
            $loader->loadData($node->getNode($relation), $includeRole);
125
        }
126
127 232
        $this->loadHierarchy($node, $includeRole);
128
    }
129
130 6494
    public function isLoaded(): bool
131
    {
132 6494
        // root loader is always loaded
133 6494
        return true;
134
    }
135
136
    /**
137 6382
     * Add selected columns to GROUP BY clause.
138
     *
139 6382
     * Might be useful when deduplication is required because of JOINs or other conditions.
140
     *
141
     * @param bool $force When set to true, GROUP BY will be forced.
142
     */
143
    public function forceGroupBy(bool $force = true): void
144
    {
145
        $this->forceGroupBy = $force;
146
    }
147
148
    /**
149
     * Clone the underlying query.
150
     */
151
    public function __clone()
152
    {
153
        $this->query = clone $this->query;
154
        parent::__clone();
155
    }
156
157
    protected function configureQuery(SelectQuery $query): SelectQuery
158
    {
159
        return parent::configureQuery(
160
            $this->mountColumns($query, true, '', true, $this->forceGroupBy),
161
        );
162
    }
163
164
    protected function initNode(): RootNode
165
    {
166
        return new RootNode($this->columnNames(), (array) $this->define(SchemaInterface::PRIMARY_KEY));
167
    }
168
}
169