Passed
Pull Request — master (#239)
by
unknown
02:11
created

RootLoader::getColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
cc 1
eloc 1
c 1
b 1
f 1
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * Cycle DataMapper ORM
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\ORM\Select;
13
14
use Cycle\ORM\ORMInterface;
15
use Cycle\ORM\Parser\AbstractNode;
16
use Cycle\ORM\Parser\RootNode;
17
use Cycle\ORM\Parser\Typecast;
18
use Cycle\ORM\Schema;
19
use Cycle\ORM\Select\Traits\ColumnsTrait;
20
use Cycle\ORM\Select\Traits\ScopeTrait;
21
use Spiral\Database\Query\SelectQuery;
22
use Spiral\Database\StatementInterface;
23
24
/**
25
 * Primary ORM loader. Loader wraps at top of select query in order to modify it's conditions, joins
26
 * and etc based on nested loaders.
27
 *
28
 * Root load does not load constrain from ORM by default.
29
 */
30
final class RootLoader extends AbstractLoader
31
{
32
    use ColumnsTrait;
33
    use ScopeTrait;
34
35
    /** @var array */
36
    protected $options = [
37
        'load' => true,
38
        'scope' => true,
39
    ];
40
41
    /** @var SelectQuery */
42
    private $query;
43
44
    /**
45
     * @param ORMInterface $orm
46
     * @param string       $target
47
     */
48
    public function __construct(ORMInterface $orm, string $target)
49
    {
50
        parent::__construct($orm, $target);
51
        $this->query = $this->getSource()->getDatabase()->select()->from(
52
            sprintf('%s AS %s', $this->getSource()->getTable(), $this->getAlias())
53
        );
54
55
        foreach ($this->getEagerRelations() as $relation) {
56
            $this->loadRelation($relation, [], false, true);
57
        }
58
    }
59
60
    /**
61
     * Clone the underlying query.
62
     */
63
    public function __clone()
64
    {
65
        $this->query = clone $this->query;
66
        parent::__clone();
67
    }
68
69
    /**
70
     * @inheritdoc
71
     */
72
    public function getAlias(): string
73
    {
74
        return $this->target;
75
    }
76
77
    /**
78
     * Get primary key column identifier (aliased).
79
     *
80
     * @return string
81
     */
82
    public function getPK(): string
83
    {
84
        return $this->getAlias() . '.' . $this->fieldAlias($this->define(Schema::PRIMARY_KEY));
85
    }
86
87
    /**
88
     * Returns PK or DISTINCT(PK) if query has any join.
89
     *
90
     * @return string
91
     */
92
    public function getCountField(): string
93
    {
94
        if ($this->isDataDuplicationPossible()) {
95
            // @tuneyourserver solves the issue with counting on queries with joins.
96
            return sprintf('DISTINCT(%s)', $this->getPK());
97
        }
98
99
        return $this->getPK();
100
    }
101
102
    /**
103
     * Return base query associated with the loader.
104
     *
105
     * @return SelectQuery
106
     */
107
    public function getQuery(): SelectQuery
108
    {
109
        return $this->query;
110
    }
111
112
    /**
113
     * Compile query with all needed conditions, columns and etc.
114
     *
115
     * @return SelectQuery
116
     */
117
    public function buildQuery(): SelectQuery
118
    {
119
        return $this->configureQuery(clone $this->query);
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    public function loadData(AbstractNode $node): void
126
    {
127
        $statement = $this->buildQuery()->run();
128
129
        foreach ($statement->fetchAll(StatementInterface::FETCH_NUM) as $row) {
130
            $node->parseRow(0, $row);
131
        }
132
133
        $statement->close();
134
135
        // loading child datasets
136
        foreach ($this->load as $relation => $loader) {
137
            $loader->loadData($node->getNode($relation));
138
        }
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144
    public function isLoaded(): bool
145
    {
146
        // root loader is always loaded
147
        return true;
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    protected function configureQuery(SelectQuery $query): SelectQuery
154
    {
155
        return parent::configureQuery(
156
            $this->mountColumns($query, true, '', true)
157
        );
158
    }
159
160
    /**
161
     * @inheritdoc
162
     */
163
    protected function initNode(): AbstractNode
164
    {
165
        $node = new RootNode($this->columnNames(), $this->define(Schema::PRIMARY_KEY));
166
167
        $typecast = $this->define(Schema::TYPECAST);
168
        if ($typecast !== null) {
169
            $node->setTypecast(new Typecast($typecast, $this->getSource()->getDatabase()));
170
        }
171
172
        return $node;
173
    }
174
175
    /**
176
     * Relation columns.
177
     *
178
     * @return array
179
     */
180
    protected function getColumns(): array
181
    {
182
        return $this->define(Schema::COLUMNS);
183
    }
184
}
185