Passed
Push — master ( c5cb83...e03db5 )
by Anton
02:08
created

RootLoader   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
eloc 33
dl 0
loc 138
rs 10
c 2
b 1
f 1
wmc 15

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getAlias() 0 3 1
A __clone() 0 4 1
A buildQuery() 0 3 1
A getQuery() 0 3 1
A getPK() 0 3 1
A loadData() 0 13 3
A __construct() 0 9 2
A isLoaded() 0 4 1
A configureQuery() 0 4 1
A getColumns() 0 3 1
A initNode() 0 10 2
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\ConstrainTrait;
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 ConstrainTrait;
34
35
    /** @var array */
36
    protected $options = [
37
        'load'      => true,
38
        'constrain' => 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
     * Return base query associated with the loader.
89
     *
90
     * @return SelectQuery
91
     */
92
    public function getQuery(): SelectQuery
93
    {
94
        return $this->query;
95
    }
96
97
    /**
98
     * Compile query with all needed conditions, columns and etc.
99
     *
100
     * @return SelectQuery
101
     */
102
    public function buildQuery(): SelectQuery
103
    {
104
        return $this->configureQuery(clone $this->query);
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function loadData(AbstractNode $node): void
111
    {
112
        $statement = $this->buildQuery()->run();
113
114
        foreach ($statement->fetchAll(StatementInterface::FETCH_NUM) as $row) {
115
            $node->parseRow(0, $row);
116
        }
117
118
        $statement->close();
119
120
        // loading child datasets
121
        foreach ($this->load as $relation => $loader) {
122
            $loader->loadData($node->getNode($relation));
123
        }
124
    }
125
126
    /**
127
     * @inheritdoc
128
     */
129
    public function isLoaded(): bool
130
    {
131
        // root loader is always loaded
132
        return true;
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    protected function configureQuery(SelectQuery $query): SelectQuery
139
    {
140
        return parent::configureQuery(
141
            $this->mountColumns($query, true, '', true)
142
        );
143
    }
144
145
    /**
146
     * @inheritdoc
147
     */
148
    protected function initNode(): AbstractNode
149
    {
150
        $node = new RootNode($this->columnNames(), $this->define(Schema::PRIMARY_KEY));
151
152
        $typecast = $this->define(Schema::TYPECAST);
153
        if ($typecast !== null) {
154
            $node->setTypecast(new Typecast($typecast, $this->getSource()->getDatabase()));
155
        }
156
157
        return $node;
158
    }
159
160
    /**
161
     * Relation columns.
162
     *
163
     * @return array
164
     */
165
    protected function getColumns(): array
166
    {
167
        return $this->define(Schema::COLUMNS);
168
    }
169
}
170