Passed
Pull Request — master (#239)
by
unknown
03:30
created

RootLoader::initNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 10
rs 10
c 0
b 0
f 0
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
            return sprintf('DISTINCT(%s)', $this->getPK());
96
        }
97
98
        return '*';
99
    }
100
101
    /**
102
     * Return base query associated with the loader.
103
     *
104
     * @return SelectQuery
105
     */
106
    public function getQuery(): SelectQuery
107
    {
108
        return $this->query;
109
    }
110
111
    /**
112
     * Compile query with all needed conditions, columns and etc.
113
     *
114
     * @return SelectQuery
115
     */
116
    public function buildQuery(): SelectQuery
117
    {
118
        return $this->configureQuery(clone $this->query);
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function loadData(AbstractNode $node): void
125
    {
126
        $statement = $this->buildQuery()->run();
127
128
        foreach ($statement->fetchAll(StatementInterface::FETCH_NUM) as $row) {
129
            $node->parseRow(0, $row);
130
        }
131
132
        $statement->close();
133
134
        // loading child datasets
135
        foreach ($this->load as $relation => $loader) {
136
            $loader->loadData($node->getNode($relation));
137
        }
138
    }
139
140
    /**
141
     * @inheritdoc
142
     */
143
    public function isLoaded(): bool
144
    {
145
        // root loader is always loaded
146
        return true;
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    protected function configureQuery(SelectQuery $query): SelectQuery
153
    {
154
        return parent::configureQuery(
155
            $this->mountColumns($query, true, '', true)
156
        );
157
    }
158
159
    /**
160
     * @inheritdoc
161
     */
162
    protected function initNode(): AbstractNode
163
    {
164
        $node = new RootNode($this->columnNames(), $this->define(Schema::PRIMARY_KEY));
165
166
        $typecast = $this->define(Schema::TYPECAST);
167
        if ($typecast !== null) {
168
            $node->setTypecast(new Typecast($typecast, $this->getSource()->getDatabase()));
169
        }
170
171
        return $node;
172
    }
173
174
    /**
175
     * Relation columns.
176
     *
177
     * @return array
178
     */
179
    protected function getColumns(): array
180
    {
181
        return $this->define(Schema::COLUMNS);
182
    }
183
}
184