Completed
Push — master ( a7b476...58257b )
by Adrian
01:51
created

OneToMany::joinSubselect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 13
rs 10
1
<?php
2
3
namespace Sirius\Orm\Relation;
4
5
use Sirius\Orm\Action\BaseAction;
6
use Sirius\Orm\Collection\Collection;
7
use Sirius\Orm\Entity\EntityInterface;
8
use Sirius\Orm\Entity\StateEnum;
9
use Sirius\Orm\Entity\Tracker;
10
use Sirius\Orm\Helpers\Inflector;
11
use Sirius\Orm\Query;
12
13
class OneToMany extends Relation
14
{
15
    protected function applyDefaults(): void
16
    {
17
        $nativeKey = $this->nativeMapper->getPrimaryKey();
18
        if (! isset($this->options[RelationConfig::NATIVE_KEY])) {
19
            $this->options[RelationConfig::NATIVE_KEY] = $nativeKey;
20
        }
21
22
        if (! isset($this->options[RelationConfig::FOREIGN_KEY])) {
23
            $prefix                                     = Inflector::singularize($this->nativeMapper->getTable());
24
            $this->options[RelationConfig::FOREIGN_KEY] = $this->getKeyColumn($prefix, $nativeKey);
25
        }
26
27
        parent::applyDefaults();
28
    }
29
30
    public function getQuery(Tracker $tracker)
31
    {
32
        $nativeKey = $this->options[RelationConfig::NATIVE_KEY];
33
        $nativePks = $tracker->pluck($nativeKey);
34
35
        $query = $this->foreignMapper
36
            ->newQuery()
37
            ->where($this->options[RelationConfig::FOREIGN_KEY], $nativePks);
38
39
        $query = $this->applyQueryCallback($query);
40
41
        $query = $this->applyForeignGuards($query);
42
43
        return $query;
44
    }
45
46
    public function joinSubselect(Query $query, string $reference)
47
    {
48
        $tableRef = $this->foreignMapper->getTableAlias(true);
0 ignored issues
show
Unused Code introduced by
The assignment to $tableRef is dead and can be removed.
Loading history...
49
        $subselect = $query->subSelectForJoinWith()
50
                           ->columns($this->foreignMapper->getTable() . '.*')
51
                           ->from($this->foreignMapper->getTable())
52
                           ->as($reference);
53
54
        $subselect = $this->applyQueryCallback($subselect);
55
56
        $subselect = $this->applyForeignGuards($subselect);
57
58
        return $query->join('INNER', $subselect->getStatement(), $this->getJoinOnForSubselect());
59
    }
60
61
    public function attachMatchesToEntity(EntityInterface $nativeEntity, array $result)
62
    {
63
        // no point in linking entities if the native one is deleted
64
        if ($nativeEntity->getPersistenceState() == StateEnum::DELETED) {
65
            return;
66
        }
67
68
        $found = [];
69
        foreach ($result as $foreignEntity) {
70
            if ($this->entitiesBelongTogether($nativeEntity, $foreignEntity)) {
71
                $found[] = $foreignEntity;
72
                $this->attachEntities($nativeEntity, $foreignEntity);
73
            }
74
        }
75
76
        $this->nativeMapper->setEntityAttribute($nativeEntity, $this->name, new Collection($found));
77
    }
78
79
    public function attachEntities(EntityInterface $nativeEntity, EntityInterface $foreignEntity)
80
    {
81
        foreach ($this->keyPairs as $nativeCol => $foreignCol) {
82
            $nativeKeyValue  = $this->nativeMapper->getEntityAttribute($nativeEntity, $nativeCol);
83
            $this->foreignMapper->setEntityAttribute($foreignEntity, $foreignCol, $nativeKeyValue);
84
        }
85
    }
86
87
    public function detachEntities(EntityInterface $nativeEntity, EntityInterface $foreignEntity)
88
    {
89
        $state = $foreignEntity->getPersistenceState();
90
        $foreignEntity->setPersistenceState(StateEnum::SYNCHRONIZED);
91
        foreach ($this->keyPairs as $nativeCol => $foreignCol) {
92
            $this->foreignMapper->setEntityAttribute($foreignEntity, $foreignCol, null);
93
        }
94
        $this->foreignMapper->setEntityAttribute($foreignEntity, $this->name, null);
95
        $foreignEntity->setPersistenceState($state);
96
    }
97
98
    protected function addActionOnDelete(BaseAction $action)
99
    {
100
        $nativeEntity       = $action->getEntity();
101
        $remainingRelations = $this->getRemainingRelations($action->getOption('relations'));
102
103
        // no cascade delete? treat as save so we can process the changes
104
        if (! $this->isCascade()) {
105
            $this->addActionOnSave($action);
106
        } else {
107
            // retrieve them again from the DB since the related collection might not have everything
108
            // for example due to a relation query callback
109
            $foreignEntities = $this->getQuery(new Tracker($this->nativeMapper, [$nativeEntity->getArrayCopy()]))
110
                                    ->get();
111
112
            foreach ($foreignEntities as $foreignEntity) {
113
                $deleteAction = $this->foreignMapper
114
                    ->newDeleteAction($foreignEntity, ['relations' => $remainingRelations]);
115
                $action->append($this->newSyncAction($nativeEntity, $foreignEntity, 'delete'));
116
                $action->append($deleteAction);
117
            }
118
        }
119
    }
120
121
    protected function addActionOnSave(BaseAction $action)
122
    {
123
        if (!$this->relationWasChanged($action->getEntity())) {
124
            return;
125
        }
126
127
        $nativeEntity       = $action->getEntity();
128
        $remainingRelations = $this->getRemainingRelations($action->getOption('relations'));
129
130
        /** @var Collection $foreignEntities */
131
        $foreignEntities = $this->nativeMapper->getEntityAttribute($nativeEntity, $this->name);
132
        $changes         = $foreignEntities->getChanges();
133
134
        // save the entities still in the collection
135
        foreach ($foreignEntities as $foreignEntity) {
136
            if (! empty($foreignEntity->getChanges())) {
137
                $saveAction = $this->foreignMapper
138
                    ->newSaveAction($foreignEntity, ['relations' => $remainingRelations]);
139
                $saveAction->addColumns($this->getExtraColumnsForAction());
0 ignored issues
show
Bug introduced by
The method addColumns() does not exist on Sirius\Orm\Action\BaseAction. It seems like you code against a sub-type of Sirius\Orm\Action\BaseAction such as Sirius\Orm\Action\Update. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

139
                $saveAction->/** @scrutinizer ignore-call */ 
140
                             addColumns($this->getExtraColumnsForAction());
Loading history...
140
                $action->append($this->newSyncAction($nativeEntity, $foreignEntity, 'save'));
141
                $action->append($saveAction);
142
            }
143
        }
144
145
        // save entities that were removed but NOT deleted
146
        foreach ($changes['removed'] as $foreignEntity) {
147
            $saveAction = $this->foreignMapper
148
                ->newSaveAction($foreignEntity, ['relations' => $remainingRelations]);
149
            $saveAction->addColumns($this->getExtraColumnsForAction());
150
            $action->append($this->newSyncAction($nativeEntity, $foreignEntity, 'delete'));
151
            $action->append($saveAction);
152
        }
153
    }
154
}
155