Store::update()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 14
rs 9.4285
cc 2
eloc 7
nc 2
nop 0
1
<?php
2
3
namespace Analogue\ORM\Commands;
4
5
use Analogue\ORM\Mappable;
6
use Analogue\ORM\EntityCollection;
7
use Analogue\ORM\System\Aggregate;
8
use Analogue\ORM\System\Proxies\EntityProxy;
9
use Analogue\ORM\System\Proxies\CollectionProxy;
10
11
/**
12
 * Persist entities & relationships to the
13
 * database.
14
 */
15
class Store extends Command
16
{
17
    /**
18
     * Persist the entity in the database
19
     *
20
     * @throws \InvalidArgumentException
21
     * @return false|mixed
22
     */
23
    public function execute()
24
    {
25
        $entity = $this->aggregate->getEntityObject();
26
27
        $mapper = $this->aggregate->getMapper();
28
29
        if ($mapper->fireEvent('storing', $entity) === false) {
30
            return false;
31
        }
32
33
        $this->preStoreProcess();
34
35
        /**
36
         * We will test the entity for existence
37
         * and run a creation if it doesn't exists
38
         */
39
        if (!$this->aggregate->exists()) {
40
            if ($mapper->fireEvent('creating', $entity) === false) {
41
                return false;
42
            }
43
44
            $this->insert();
45
46
            $mapper->fireEvent('created', $entity, false);
47
        }
48
        else if ($this->aggregate->isDirty()) {
49
            if ($mapper->fireEvent('updating', $entity) === false) {
50
                return false;
51
            }
52
            $this->update();
53
54
            $mapper->fireEvent('updated', $entity, false);
55
        }
56
57
        $this->postStoreProcess();
58
59
        $mapper->fireEvent('stored', $entity, false);
60
61
        return $entity;
62
    }
63
64
    /**
65
     * Run all operations that have to occur before actually
66
     * storing the entity
67
     *
68
     * @throws \InvalidArgumentException
69
     * @return void
70
     */
71
    protected function preStoreProcess()
72
    {
73
        // Create any related object that doesn't exist in the database.
74
        $localRelationships = $this->aggregate->getEntityMap()->getLocalRelationships();
75
76
        $this->createRelatedEntities($localRelationships);
77
78
        // Now we can sync the related collections
79
        $this->aggregate->syncRelationships($localRelationships);
80
    }
81
82
    /**
83
     * Check for existence and create non-existing related entities
84
     *
85
     * @param  array
86
     * @throws \InvalidArgumentException
87
     * @return void
88
     */
89
    protected function createRelatedEntities($relations)
90
    {
91
        $entitiesToCreate = $this->aggregate->getNonExistingRelated($relations);
92
93
        foreach ($entitiesToCreate as $aggregate) {
94
            $this->createStoreCommand($aggregate)->execute();
95
        }
96
    }
97
98
    /**
99
     * Create a new store command
100
     *
101
     * @param  Aggregate $aggregate
102
     * @return Store
103
     */
104
    protected function createStoreCommand(Aggregate $aggregate)
105
    {
106
        // We gotta retrieve the corresponding query adapter to use.
107
        $mapper = $aggregate->getMapper();
108
109
        return new Store($aggregate, $mapper->newQueryBuilder());
110
    }
111
112
    /**
113
     * Run all operations that have to occur after the entity
114
     * is stored.
115
     *
116
     * @throws \InvalidArgumentException
117
     * @return void
118
     */
119
    protected function postStoreProcess()
120
    {
121
        $aggregate = $this->aggregate;
122
123
        // Create any related object that doesn't exist in the database.
124
        $foreignRelationships = $aggregate->getEntityMap()->getForeignRelationships();
125
        $this->createRelatedEntities($foreignRelationships);
126
127
        // Update any pivot tables that has been modified.
128
        $aggregate->updatePivotRecords();
129
130
        // Update any dirty relationship. This include relationships that already exists, have
131
        // dirty attributes / newly created related entities / dirty related entities.
132
        $dirtyRelatedAggregates = $aggregate->getDirtyRelationships();
133
134
        foreach ($dirtyRelatedAggregates as $related) {
135
            $this->createStoreCommand($related)->execute();
136
        }
137
138
        // Now we can sync the related collections
139
        if ($this->aggregate->exists()) {
140
            $this->aggregate->syncRelationships($foreignRelationships);
141
        }
142
        
143
        // TODO be move it to the wrapper class
144
        // so it's the same code for the entity builder
145
        $aggregate->setProxies();
146
147
        // Update Entity Cache
148
        $aggregate->getMapper()->getEntityCache()->refresh($aggregate);
149
    }
150
151
    /**
152
     * Update Related Entities which attributes have
153
     * been modified.
154
     *
155
     * @return void
156
     */
157
    protected function updateDirtyRelated()
158
    {
159
        $relations = $this->entityMap->getRelationships();
0 ignored issues
show
Bug introduced by
The property entityMap does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
160
        $attributes = $this->getAttributes();
0 ignored issues
show
Bug introduced by
The method getAttributes() does not seem to exist on object<Analogue\ORM\Commands\Store>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
162
        foreach ($relations as $relation) {
163
            if (!array_key_exists($relation, $attributes)) {
164
                continue;
165
            }
166
167
            $value = $attributes[$relation];
168
169
            if ($value == null) {
170
                continue;
171
            }
172
173
            if ($value instanceof EntityProxy) {
174
                continue;
175
            }
176
177
            if ($value instanceof CollectionProxy && $value->isLoaded()) {
178
                $value = $value->getUnderlyingCollection();
179
            }
180
            if ($value instanceof CollectionProxy && !$value->isLoaded()) {
181
                foreach ($value->getAddedItems() as $entity) {
182
                    $this->updateEntityIfDirty($entity);
0 ignored issues
show
Bug introduced by
The method updateEntityIfDirty() does not exist on Analogue\ORM\Commands\Store. Did you maybe mean update()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
183
                }
184
                continue;
185
            }
186
187
            if ($value instanceof EntityCollection) {
188
                foreach ($value as $entity) {
189
                    if (!$this->createEntityIfNotExists($entity)) {
0 ignored issues
show
Bug introduced by
The method createEntityIfNotExists() does not seem to exist on object<Analogue\ORM\Commands\Store>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
190
                        $this->updateEntityIfDirty($entity);
0 ignored issues
show
Bug introduced by
The method updateEntityIfDirty() does not exist on Analogue\ORM\Commands\Store. Did you maybe mean update()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
191
                    }
192
                }
193
                continue;
194
            }
195
            if ($value instanceof Mappable) {
196
                $this->updateEntityIfDirty($value);
0 ignored issues
show
Bug introduced by
The method updateEntityIfDirty() does not exist on Analogue\ORM\Commands\Store. Did you maybe mean update()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
197
                continue;
198
            }
199
        }
200
    }
201
202
    /**
203
     * Execute an insert statement on the database
204
     *
205
     * @return void
206
     */
207
    protected function insert()
208
    {
209
        $aggregate = $this->aggregate;
210
211
        $attributes = $aggregate->getRawAttributes();
212
        
213
        $keyName = $aggregate->getEntityMap()->getKeyName();
214
215
        // Check if the primary key is defined in the attributes
216
        if (array_key_exists($keyName, $attributes) && $attributes[$keyName] != null) {
217
            $this->query->insert($attributes);
218
        } else {
219
            $sequence = $aggregate->getEntityMap()->getSequence();
220
221
            $id = $this->query->insertGetId($attributes, $sequence);
222
223
            $aggregate->setEntityAttribute($keyName, $id);
224
        }
225
    }
226
227
    /**
228
     * Run an update statement on the entity
229
     *
230
     * @throws \InvalidArgumentException
231
     *
232
     * @return void
233
     */
234
    protected function update()
235
    {
236
        $query = $this->query;
237
238
        $keyName = $this->aggregate->getEntityKey();
239
240
        $query = $query->where($keyName, '=', $this->aggregate->getEntityId());
241
242
        $dirtyAttributes = $this->aggregate->getDirtyRawAttributes();
243
244
        if (count($dirtyAttributes) > 0) {
245
            $query->update($dirtyAttributes);
246
        }
247
    }
248
}
249