Completed
Branch feature/pre-split (2ed6c7)
by Anton
04:25
created

RootLoader::compileQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\ORM\Entities\Loaders;
8
9
use Spiral\Database\Builders\SelectQuery;
10
use Spiral\ORM\Entities\Loaders\Traits\ColumnsTrait;
11
use Spiral\ORM\Entities\Nodes\AbstractNode;
12
use Spiral\ORM\Entities\Nodes\RootNode;
13
use Spiral\ORM\ORMInterface;
14
use Spiral\ORM\Record;
15
16
/**
17
 * Primary ORM loader. Loader wraps at top of select query in order to modify it's conditions, joins
18
 * and etc based on nested loaders.
19
 *
20
 * Note, in RootLoader schema represent record schema since there is no self to self relation.
21
 */
22
class RootLoader extends AbstractLoader
23
{
24
    use ColumnsTrait;
25
26
    /**
27
     * Root loader always define primary SelectQuery.
28
     *
29
     * @var SelectQuery
30
     */
31
    private $query;
32
33
    /**
34
     * @param string       $class
35
     * @param array        $schema Record schema for root loader.
36
     * @param ORMInterface $orm
37
     */
38
    public function __construct(string $class, array $schema, ORMInterface $orm)
39
    {
40
        //Constructing with truncated schema
41
        parent::__construct(
42
            $class,
43
            [
44
                Record::SH_PRIMARIES     => $schema[Record::SH_PRIMARIES],
45
                Record::RELATION_COLUMNS => array_keys($schema[Record::SH_DEFAULTS])
46
            ],
47
            $orm
48
        );
49
50
        //Getting our initial select query
51
        $this->query = $orm->table($class)->select();
52
    }
53
54
    /**
55
     * Return initial loader query (attention, mutable instance).
56
     *
57
     * @return SelectQuery
58
     */
59
    public function initialQuery(): SelectQuery
60
    {
61
        return $this->query;
62
    }
63
64
    /**
65
     * Return build version of query.
66
     *
67
     * @return SelectQuery
68
     */
69
    public function compileQuery(): SelectQuery
70
    {
71
        return $this->query;
72
    }
73
74
    /**
75
     * Get primary key column if possible (aliased). Null when key is missing or non singular.
76
     *
77
     * @return string|null
78
     */
79
    public function primaryKey()
80
    {
81
        $primaryKeys = $this->schema[Record::SH_PRIMARIES];
82
        if (count($primaryKeys) != 1) {
83
            return null;
84
        }
85
86
        return $this->getAlias() . '.' . $primaryKeys[0];
87
    }
88
89
    /**
90
     * @param SelectQuery $query
91
     *
92
     * @return SelectQuery
93
     */
94
    protected function configureQuery(SelectQuery $query): SelectQuery
95
    {
96
        //Clarifying table name
97
        $query->from("{$this->getTable()} AS {$this->getAlias()}");
98
99
        //Columns to be loaded for primary model
100
        $this->mountColumns($query, true, '', true);
101
102
        return parent::configureQuery($query);
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    public function loadData(AbstractNode $node)
109
    {
110
        //Fetching results from database
111
        $statement = $this->configureQuery(clone $this->query)->run();
112
        $statement->setFetchMode(\PDO::FETCH_NUM);
113
114
        foreach ($statement as $row) {
115
            $node->parseRow(0, $row);
116
        }
117
118
        //Destroying statement
119
        $statement->close();
120
121
        //Executing child loaders
122
        foreach ($this->loaders as $relation => $loader) {
123
            $loader->loadData($node->fetchNode($relation));
124
        }
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function initNode(): AbstractNode
131
    {
132
        return new RootNode(
133
            $this->schema[Record::RELATION_COLUMNS],
134
            $this->schema[Record::SH_PRIMARIES]
135
        );
136
    }
137
138
    /**
139
     * Clone with initial query.
140
     */
141
    public function __clone()
142
    {
143
        $this->query = clone $this->query;
144
        parent::__clone();
145
    }
146
147
    /**
148
     * We are using model role as alias.
149
     *
150
     * @return string
151
     */
152
    protected function getAlias(): string
153
    {
154
        return $this->orm->define($this->class, ORMInterface::R_ROLE_NAME);
155
    }
156
157
    /**
158
     * Relation columns.
159
     *
160
     * @return array
161
     */
162
    protected function getColumns(): array
163
    {
164
        return $this->schema[Record::RELATION_COLUMNS];
165
    }
166
}