Completed
Push — master ( 3d5802...f04b72 )
by Anton
09:30
created

RootLoader::withColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 10
rs 9.4285
c 0
b 0
f 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
     *
124
     * @return SelectQuery
125
     */
126
    protected function configureQuery(SelectQuery $query): SelectQuery
127
    {
128
        //Clarifying table name
129
        $query->from("{$this->getTable()} AS {$this->getAlias()}");
130
131
        //Columns to be loaded for primary model
132
        $this->mountColumns($query, true, '', true);
133
134
        return parent::configureQuery($query);
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function loadData(AbstractNode $node)
141
    {
142
        //Fetching results from database
143
        $statement = $this->configureQuery(clone $this->query)->run();
144
        $statement->setFetchMode(\PDO::FETCH_NUM);
145
146
        foreach ($statement as $row) {
147
            $node->parseRow(0, $row);
148
        }
149
150
        //Destroying statement
151
        $statement->close();
152
153
        //Executing child loaders
154
        foreach ($this->loaders as $relation => $loader) {
155
            $loader->loadData($node->fetchNode($relation));
156
        }
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function initNode(): AbstractNode
163
    {
164
        return new RootNode(
165
            $this->getColumns(),
166
            $this->schema[Record::SH_PRIMARY_KEY]
167
        );
168
    }
169
170
    /**
171
     * Clone with initial query.
172
     */
173
    public function __clone()
174
    {
175
        $this->query = clone $this->query;
176
        parent::__clone();
177
    }
178
179
    /**
180
     * Relation columns.
181
     *
182
     * @return array
183
     */
184
    protected function getColumns(): array
185
    {
186
        return $this->columns ?? $this->schema[Record::RELATION_COLUMNS];
187
    }
188
}