Completed
Push — master ( 4d6323...61e01b )
by Maxim
02:33
created

AbstractEntityRepositoryDb::rowToEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace WebComplete\core\entity;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Query\QueryBuilder;
7
use WebComplete\core\condition\ConditionDbParser;
8
use WebComplete\core\factory\ObjectFactory;
9
use WebComplete\core\utils\hydrator\HydratorInterface;
10
use WebComplete\core\condition\Condition;
11
12
abstract class AbstractEntityRepositoryDb extends AbstractEntityRepository
13
{
14
    const SERIALIZE_STRATEGY_JSON = 1;
15
    const SERIALIZE_STRATEGY_PHP  = 2;
16
17
    protected $table;
18
    /**
19
     * map: fieldName: propertyName
20
     * @var array|null
21
     */
22
    protected $map;
23
    protected $serializeFields = [];
24
    protected $serializeStrategy = self::SERIALIZE_STRATEGY_JSON;
25
26
    /** @var Connection */
27
    protected $db;
28
29
    /**
30
     * @var ConditionDbParser
31
     */
32
    protected $conditionParser;
33
34
    /**
35
     * @param ObjectFactory $factory
36
     * @param HydratorInterface $hydrator
37
     * @param ConditionDbParser $conditionParser
38
     * @param Connection $db
39
     */
40
    public function __construct(
41
        ObjectFactory $factory,
42
        HydratorInterface $hydrator,
43
        ConditionDbParser $conditionParser,
44
        Connection $db
45
    ) {
46
        parent::__construct($factory, $hydrator);
47
        $this->db = $db;
48
        $this->conditionParser = $conditionParser;
49
    }
50
51
    /**
52
     * @return string
53
     */
54
    public function getTable(): string
55
    {
56
        return $this->table;
57
    }
58
59
    /**
60
     * @param \Closure $closure
61
     * @throws \Exception
62
     */
63
    public function transaction(\Closure $closure)
64
    {
65
        $this->db->transactional($closure);
66
    }
67
68
    /**
69
     * @param $id
70
     * @return AbstractEntity|null
71
     */
72
    public function findById($id)
73
    {
74
        return $this->findOne(new Condition(['t1.id' => $id]));
75
    }
76
77
    /**
78
     * @param Condition $condition
79
     * @return AbstractEntity|null
80
     */
81
    public function findOne(Condition $condition)
82
    {
83
        $result = null;
84
        $select = $this->selectQuery($condition);
85
        if ($row = $select->execute()->fetch()) {
86
            $result = $this->rowToEntity($row);
87
        }
88
89
        return $result;
90
    }
91
92
    /**
93
     * @param Condition $condition
94
     * @return AbstractEntity[]
95
     */
96
    public function findAll(Condition $condition = null): array
97
    {
98
        $result = [];
99
        $select = $this->selectQuery($condition);
100 View Code Duplication
        if ($rows = $select->execute()->fetchAll(\PDO::FETCH_ASSOC)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
101
            foreach ($rows as $row) {
102
                $entity = $this->rowToEntity($row);
103
                $result[$entity->getId()] = $entity;
104
            }
105
        }
106
107
        return $result;
108
    }
109
110
    /**
111
     * @param Condition|null $condition
112
     * @return int
113
     */
114
    public function count(Condition $condition = null): int
115
    {
116
        $select = $this->selectQuery($condition);
117
        return $select->select(['t1.id'])->execute()->rowCount();
118
    }
119
120
    /**
121
     * @param AbstractEntity $item
122
     */
123
    public function save(AbstractEntity $item)
124
    {
125
        $data = $this->hydrator->extract($item, $this->map);
126
        $this->beforeDataSave($data);
127
        $this->serializeFields($data);
128
        if ($id = $item->getId()) {
129
            $this->db->update($this->table, $data, ['t1.id' => $id]);
130
        } else {
131
            unset($data['id']);
132
            $this->db->insert($this->table, $data);
133
            $item->setId((int)$this->db->lastInsertId());
134
        }
135
    }
136
137
    /**
138
     * @param $id
139
     *
140
     * @throws \Doctrine\DBAL\Exception\InvalidArgumentException
141
     */
142
    public function delete($id)
143
    {
144
        $this->db->delete($this->table, ['t1.id' => $id]);
145
    }
146
147
    /**
148
     * @param Condition|null $condition
149
     */
150
    public function deleteAll(Condition $condition = null)
151
    {
152
        $query = $this->selectQuery($condition);
153
        $query->delete($this->table, 't1');
154
        $query->execute();
155
    }
156
157
    /**
158
     * @param string $field
159
     * @param string $key
160
     * @param Condition|null $condition
161
     *
162
     * @return array
163
     * @throws \Exception
164
     */
165
    public function getMap(string $field, string $key = 'id', Condition $condition = null): array
166
    {
167
        $result = [];
168
        $select = $this->selectQuery($condition);
169
        $select->select(['t1.' . $field, 't1.' . $key]);
170 View Code Duplication
        if ($rows = $select->execute()->fetchAll(\PDO::FETCH_ASSOC)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
            foreach ($rows as $row) {
172
                $this->unserializeFields($row);
173
                $result[$row[$key]] = $row[$field];
174
            }
175
        }
176
177
        return $result;
178
    }
179
180
    /**
181
     * @param Condition|null $condition
182
     * @return QueryBuilder
183
     */
184
    protected function selectQuery(Condition $condition = null): QueryBuilder
185
    {
186
        $queryBuilder = $this->db->createQueryBuilder();
187
        $queryBuilder->select(['t1.*'])->from($this->table, 't1');
188
        $this->conditionParser->parse($queryBuilder, $condition, $this->map);
189
        return $queryBuilder;
190
    }
191
192
    /**
193
     * Adjust data before save
194
     * @param $data
195
     */
196
    protected function beforeDataSave(&$data)
197
    {
198
    }
199
200
    /**
201
     * @param $data
202
     *
203
     * @return AbstractEntity
204
     */
205
    private function rowToEntity($data)
206
    {
207
        $this->unserializeFields($data);
208
        $entity = $this->factory->createFromData($data, $this->map);
209
        /** @var AbstractEntity $entity */
210
        return $entity;
211
    }
212
213
    /**
214
     * @param $data
215
     */
216
    private function serializeFields(&$data)
217
    {
218
        foreach ($this->serializeFields as $field) {
219
            if (isset($data[$field])) {
220
                $data[$field] = $this->serializeStrategy === self::SERIALIZE_STRATEGY_JSON
221
                    ? \json_encode($data[$field])
222
                    : \serialize($data[$field]);
223
            }
224
        }
225
    }
226
227
    /**
228
     * @param $row
229
     */
230
    private function unserializeFields(&$row)
231
    {
232
        foreach ($this->serializeFields as $field) {
233
            if (isset($row[$field])) {
234
                $row[$field] = $this->serializeStrategy === self::SERIALIZE_STRATEGY_JSON
235
                    ? \json_decode($row[$field], true)
236
                    : \unserialize($row[$field], ['allowed_classes' => true]);
237
            }
238
        }
239
    }
240
}
241