RootLoader::getColumns()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Spiral, Core Components
4
 *
5
 * @author Wolfy-J
6
 */
7
8
namespace Spiral\ORM\Entities\Loaders;
9
10
use Spiral\Database\Builders\SelectQuery;
11
use Spiral\ORM\Entities\Loaders\Traits\ColumnsTrait;
12
use Spiral\ORM\Entities\Nodes\AbstractNode;
13
use Spiral\ORM\Entities\Nodes\RootNode;
14
use Spiral\ORM\ORMInterface;
15
use Spiral\ORM\Record;
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
 * Note, in RootLoader schema represent record schema since there is no self to self relation.
22
 */
23
class RootLoader extends AbstractLoader
24
{
25
    use ColumnsTrait;
26
27
    /**
28
     * Root loader always define primary SelectQuery.
29
     *
30
     * @var SelectQuery
31
     */
32
    private $query;
33
34
    /**
35
     * Only columns to be selected, by default all columns.
36
     *
37
     * @var null|array
38
     */
39
    private $columns = null;
40
41
    /**
42
     * @param string       $class
43
     * @param array        $schema Record schema for root loader.
44
     * @param ORMInterface $orm
45
     */
46
    public function __construct(string $class, array $schema, ORMInterface $orm)
47
    {
48
        //Constructing with truncated schema
49
        parent::__construct(
50
            $class,
51
            [
52
                Record::SH_PRIMARY_KEY   => $schema[Record::SH_PRIMARY_KEY],
53
                Record::RELATION_COLUMNS => array_keys($schema[Record::SH_DEFAULTS])
54
            ],
55
            $orm
56
        );
57
58
        //Getting our initial select query
59
        $this->query = $orm->table($class)->select();
60
    }
61
62
    /**
63
     * Columns to be selected, please note, primary will always be included, DO not include
64
     * column aliases in here, aliases will be added automatically. Creates new loader tree copy.
65
     *
66
     * @param array $columns
67
     *
68
     * @return RootLoader
69
     */
70
    public function withColumns(array $columns): self
71
    {
72
        $loader = clone $this;
73
        $loader->columns = array_merge(
74
            [$loader->schema[Record::SH_PRIMARY_KEY]],
75
            $columns
76
        );
77
78
        return $loader;
79
    }
80
81
    /**
82
     * Return initial loader query (attention, mutable instance).
83
     *
84
     * @return SelectQuery
85
     */
86
    public function initialQuery(): SelectQuery
87
    {
88
        return $this->query;
89
    }
90
91
    /**
92
     * Return build version of query.
93
     *
94
     * @return SelectQuery
95
     */
96
    public function compiledQuery(): SelectQuery
97
    {
98
        return $this->configureQuery(clone $this->query);
99
    }
100
101
    /**
102
     * Get primary key column if possible (aliased). Null when key is missing or non singular.
103
     *
104
     * @return string|null
105
     */
106
    public function primaryKey(): string
107
    {
108
        return $this->getAlias() . '.' . $this->schema[Record::SH_PRIMARY_KEY];
109
    }
110
111
    /**
112
     * We are using model role as alias. Visibility up.
113
     *
114
     * @return string
115
     */
116
    public function getAlias(): string
117
    {
118
        return $this->orm->define($this->class, ORMInterface::R_ROLE_NAME);
119
    }
120
121
    /**
122
     * @param SelectQuery $query
123
     * @param bool $loadColumns
124
     *
125
     * @return SelectQuery
126
     */
127
    protected function configureQuery(SelectQuery $query, bool $loadColumns = true): SelectQuery
128
    {
129
        //Clarifying table name
130
        $query->from("{$this->getTable()} AS {$this->getAlias()}");
131
132
        //Columns to be loaded for primary model
133
        if ($loadColumns) {
134
            $this->mountColumns($query, true, '', true);
135
        }
136
137
        return parent::configureQuery($query, $loadColumns);
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function loadData(AbstractNode $node)
144
    {
145
        //Fetching results from database
146
        $statement = $this->configureQuery(clone $this->query)->run();
147
        $statement->setFetchMode(\PDO::FETCH_NUM);
148
149
        foreach ($statement as $row) {
150
            $node->parseRow(0, $row);
151
        }
152
153
        //Destroying statement
154
        $statement->close();
155
156
        //Executing child loaders
157
        foreach ($this->loaders as $relation => $loader) {
158
            $loader->loadData($node->fetchNode($relation));
159
        }
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165
    public function initNode(): AbstractNode
166
    {
167
        return new RootNode(
168
            $this->getColumns(),
169
            $this->schema[Record::SH_PRIMARY_KEY]
170
        );
171
    }
172
173
    /**
174
     * Clone with initial query.
175
     */
176
    public function __clone()
177
    {
178
        $this->query = clone $this->query;
179
        parent::__clone();
180
    }
181
182
    /**
183
     * Relation columns.
184
     *
185
     * @return array
186
     */
187
    protected function getColumns(): array
188
    {
189
        return $this->columns ?? $this->schema[Record::RELATION_COLUMNS];
190
    }
191
}