SqlStore   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 6
dl 0
loc 246
ccs 0
cts 124
cp 0
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A create() 0 6 1
A insertEntity() 0 8 1
A read() 0 5 1
A update() 0 6 1
A updateEntity() 0 9 1
A delete() 0 5 1
A deleteEntity() 0 11 1
A collectionIterator() 0 16 3
A relationships() 0 32 3
A deleteRelationship() 0 18 2
A updateRelationship() 0 22 3
1
<?php
2
3
namespace Percy\Store;
4
5
use Aura\Filter\FilterFactory;
6
use Aura\SqlQuery\QueryFactory;
7
use Aura\Sql\ExtendedPdo;
8
use PDO;
9
use PDOException;
10
use Percy\Entity\Collection;
11
use Percy\Entity\EntityInterface;
12
13
class SqlStore extends AbstractStore
14
{
15
    /**
16
     * @var \Aura\Sql\ExtendedPdo
17
     */
18
    protected $dbal;
19
20
    /**
21
     * @var \Aura\SqlQuery\QueryFactory
22
     */
23
    protected $query;
24
25
    /**
26
     * Construct.
27
     *
28
     * @param \Aura\Sql\ExtendedPdo      $dbal
29
     * @param \Aura\Filter\FilterFactory $filter
30
     */
31
    public function __construct(ExtendedPdo $dbal, FilterFactory $filter)
32
    {
33
        $this->dbal  = $dbal;
34
        $this->query = new QueryFactory($dbal->getAttribute(PDO::ATTR_DRIVER_NAME));
35
        parent::__construct($filter);
36
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41
    public function create(Collection $collection, array $scopes = [])
42
    {
43
        $this->decorate($collection, StoreInterface::ON_CREATE);
44
        $this->validate($collection);
45
        return $this->collectionIterator($collection, 'insertEntity', $scopes);
46
    }
47
48
    /**
49
     * Insert an entity to the database.
50
     *
51
     * @param \Percy\Entity\EntityInterface $entity
52
     * @param array                         $scopes
53
     *
54
     * @return void
55
     */
56
    protected function insertEntity(EntityInterface $entity, array $scopes = [])
57
    {
58
        $insert = $this->query->newInsert();
59
        $insert->into($entity->getDataSource());
60
        $insert->cols($entity->getData($scopes, true));
61
62
        $this->dbal->perform($insert->getStatement(), $insert->getBindValues());
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public function read(Collection $collection, array $scopes = [])
69
    {
70
        // mysql need do nothing with the data on a read request
71
        return true;
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function update(Collection $collection, array $scopes = [])
78
    {
79
        $this->decorate($collection, StoreInterface::ON_UPDATE);
80
        $this->validate($collection);
81
        return $this->collectionIterator($collection, 'updateEntity', $scopes);
82
    }
83
84
    /**
85
     * Update an entity in the database.
86
     *
87
     * @param \Percy\Entity\EntityInterface $entity
88
     * @param array                         $scopes
89
     *
90
     * @return void
91
     */
92
    protected function updateEntity(EntityInterface $entity, array $scopes = [])
93
    {
94
        $update = $this->query->newUpdate();
95
        $update->table($entity->getDataSource());
96
        $update->cols($entity->getData($scopes, true));
97
        $update->where(sprintf('%s = ?', $entity->getPrimary()), $entity[$entity->getPrimary()]);
98
99
        $this->dbal->perform($update->getStatement(), $update->getBindValues());
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105
    public function delete(Collection $collection, array $scopes = [])
106
    {
107
        $this->decorate($collection, StoreInterface::ON_DELETE);
108
        return $this->collectionIterator($collection, 'deleteEntity', $scopes);
109
    }
110
111
    /**
112
     * Delete an entity from the database. Be aware, this handles hard deletes.
113
     * To handle soft deletes, extend this class and overload this method.
114
     *
115
     * @param \Percy\Entity\EntityInterface $entity
116
     * @param array                         $scopes
117
     *
118
     * @return void
119
     */
120
    protected function deleteEntity(EntityInterface $entity, array $scopes = [])
121
    {
122
        // ensure write scopes
123
        $entity->getData($scopes, true);
124
125
        $delete = $this->query->newDelete();
126
        $delete->from($entity->getDataSource());
127
        $delete->where(sprintf('%s = ?', $entity->getPrimary()), $entity[$entity->getPrimary()]);
128
129
        $this->dbal->perform($delete->getStatement(), $delete->getBindValues());
130
    }
131
132
    /**
133
     * Iterate a collection with the correct callback.
134
     *
135
     * @param \Percy\Entity\Collection $collection
136
     * @param string                   $callable
137
     *
138
     * @return boolean
139
     */
140
    protected function collectionIterator(Collection $collection, $callable, array $scopes = [])
141
    {
142
        $this->dbal->beginTransaction();
143
144
        try {
145
            foreach ($collection->getIterator() as $entity) {
146
                call_user_func_array([$this, $callable], [$entity, $scopes]);
147
            }
148
        } catch (PDOException $e) {
149
            $this->dbal->rollBack();
150
            return false;
151
        }
152
153
        $this->dbal->commit();
154
        return true;
155
    }
156
157
    /**
158
     * Persist relationships to data store.
159
     *
160
     * @param \Percy\Entity\EntityInterface $entity
161
     * @param array                         $rels
162
     * @param array                         $map
163
     *
164
     * @return void
165
     */
166
    public function relationships(EntityInterface $entity, array $rels, array $map)
167
    {
168
        $this->dbal->beginTransaction();
169
170
        foreach ($rels as $rel) {
171
            $exists = $this->dbal->fetchOne(sprintf(
172
                "select * from %s where %s = '%s' and %s = '%s'",
173
                $map['defined_in']['table'],
174
                $map['defined_in']['primary'],
175
                $entity[$map['defined_in']['entity']],
176
                $map['target']['relationship'],
177
                $rel
178
            ));
179
180
            if ($exists !== false) {
181
                continue;
182
            }
183
184
            $data = [
185
                $map['defined_in']['primary']  => $entity[$map['defined_in']['entity']],
186
                $map['target']['relationship'] => $rel
187
            ];
188
189
            $insert = $this->query->newInsert();
190
            $insert->into($map['defined_in']['table']);
191
            $insert->cols($data);
192
193
            $this->dbal->perform($insert->getStatement(), $insert->getBindValues());
194
        }
195
196
        $this->dbal->commit();
197
    }
198
199
    /**
200
     * Remove relationship.
201
     *
202
     * @param \Percy\Entity\EntityInterface $entity
203
     * @param array                         $rels
204
     * @param array                         $map
205
     *
206
     * @return void
207
     */
208
    public function deleteRelationship(EntityInterface $entity, array $rels, array $map)
209
    {
210
        $this->dbal->beginTransaction();
211
212
        foreach ($rels as $rel) {
213
            $delete = $this->query->newDelete();
214
            $delete->from($map['defined_in']['table']);
215
            $delete->where(sprintf('%s = :%s', $map['defined_in']['primary'], $map['defined_in']['entity']));
216
            $delete->where(sprintf('%s = :%s', $map['target']['relationship'], 'relationship'));
217
            $delete->limit(1);
218
            $delete->bindValue('uuid', $entity[$map['defined_in']['entity']]);
219
            $delete->bindValue('relationship', $rel);
220
221
            $this->dbal->perform($delete->getStatement(), $delete->getBindValues());
222
        }
223
224
        $this->dbal->commit();
225
    }
226
227
    /**
228
     * Update a relationship.
229
     *
230
     * @param \Percy\Entity\EntityInterface $entity
231
     * @param array                         $rels
232
     * @param array                         $map
233
     *
234
     * @return void
235
     */
236
    public function updateRelationship(EntityInterface $entity, array $rels, array $map)
237
    {
238
        $this->dbal->beginTransaction();
239
240
        foreach ($rels as $rel) {
241
            foreach ($rel as $key => $value) {
242
                $update = $this->query->newUpdate();
243
                $update->table($map['defined_in']['table']);
244
                $update->cols([$map['target']['relationship'] => $value]);
245
                $update->where(sprintf('%s = :%s', $map['defined_in']['primary'], $map['defined_in']['entity']));
246
                $update->where(sprintf('%s = :%s', $map['target']['relationship'], 'relationship'));
247
                $update->limit(1);
248
                $update->bindValue('uuid', $entity[$map['defined_in']['entity']]);
249
                $update->bindValue('relationship', $key);
250
                $update->bindValue($map['target']['relationship'], $value);
251
252
                $this->dbal->perform($update->getStatement(), $update->getBindValues());
253
            }
254
        }
255
256
        $this->dbal->commit();
257
    }
258
}
259