Completed
Push — master ( abc7fc...ef6c42 )
by Anton
02:25
created

HasManyLoader::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 4
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\Database\Injections\Parameter;
12
use Spiral\ORM\Entities\Loaders\Traits\ConstrainTrait;
13
use Spiral\ORM\Entities\Loaders\Traits\WhereTrait;
14
use Spiral\ORM\Entities\Nodes\AbstractNode;
15
use Spiral\ORM\Entities\Nodes\ArrayNode;
16
use Spiral\ORM\ORMInterface;
17
use Spiral\ORM\Record;
18
use Spiral\ORM\RecordEntity;
19
20
/**
21
 * Dedicated to load HAS_MANY relation data, POSTLOAD is preferred loading method. Additional where
22
 * conditions and morph keys are supported.
23
 *
24
 * Please note that OUTER and INNER keys defined from perspective of parent (reversed for our
25
 * purposes).
26
 */
27
class HasManyLoader extends RelationLoader
28
{
29
    use WhereTrait, ConstrainTrait;
30
31
    /**
32
     * Default set of relation options. Child implementation might defined their of default options.
33
     *
34
     * @var array
35
     */
36
    protected $options = [
37
        'method'  => self::POSTLOAD,
38
        'minify'  => true,
39
        'alias'   => null,
40
        'using'   => null,
41
        'where'   => null,
42
        'orderBy' => [],
43
        'limit'   => 0
44
    ];
45
46
    /**
47
     * @param string                   $class
48
     * @param string                   $relation
49
     * @param array                    $schema
50
     * @param \Spiral\ORM\ORMInterface $orm
51
     */
52
    public function __construct($class, $relation, array $schema, ORMInterface $orm)
53
    {
54
        parent::__construct($class, $relation, $schema, $orm);
55
56
        if (!empty($schema[RecordEntity::ORDER_BY])) {
57
            //Default sorting direction
58
            $this->options['orderBy'] = $schema[RecordEntity::ORDER_BY];
59
        }
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    protected function configureQuery(SelectQuery $query, array $outerKeys = []): SelectQuery
66
    {
67
        if (!empty($this->options['using'])) {
68
            //Use pre-defined query
69
            return parent::configureQuery($query, $outerKeys);
70
        }
71
72
        if ($this->isJoined()) {
73
            $query->join(
74
                $this->getMethod() == self::JOIN ? 'INNER' : 'LEFT',
75
                "{$this->getTable()} AS {$this->getAlias()}")
76
                ->on(
77
                    $this->localKey(Record::OUTER_KEY),
78
                    $this->parentKey(Record::INNER_KEY)
79
                );
80
        } else {
81
            //This relation is loaded using external query
82
            $query->where(
83
                $this->localKey(Record::OUTER_KEY),
84
                'IN',
85
                new Parameter($outerKeys)
86
            );
87
88
            $this->configureWindow($query, $this->options['orderBy'], $this->options['limit']);
89
        }
90
91
        //When relation is joined we will use ON statements, when not - normal WHERE
92
        $whereTarget = $this->isJoined() ? 'onWhere' : 'where';
93
94
        //Where conditions specified in relation definition
95
        $this->setWhere($query, $this->getAlias(), $whereTarget, $this->schema[Record::WHERE]);
96
97
        //User specified WHERE conditions
98
        $this->setWhere($query, $this->getAlias(), $whereTarget, $this->options['where']);
99
100
        //Morphed records
101
        if (!empty($this->schema[Record::MORPH_KEY])) {
102
            $this->setWhere(
103
                $query,
104
                $this->getAlias(),
105
                $whereTarget,
106
                [
107
                    $this->localKey(Record::MORPH_KEY) => $this->orm->define(
108
                        $this->parent->getClass(),
109
                        ORMInterface::R_ROLE_NAME
110
                    )
111
                ]
112
            );
113
        }
114
115
        return parent::configureQuery($query);
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    protected function initNode(): AbstractNode
122
    {
123
        $node = new ArrayNode(
124
            $this->schema[Record::RELATION_COLUMNS],
125
            $this->schema[Record::OUTER_KEY],
126
            $this->schema[Record::INNER_KEY],
127
            $this->schema[Record::SH_PRIMARY_KEY]
128
        );
129
130
        return $node->asJoined($this->isJoined());
131
    }
132
}