Completed
Push — master ( 4f0ac2...beb83a )
by Dominik
01:47
created

AbstractDoctrineRepository::remove()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Model\Doctrine\DBAL;
6
7
use Chubbyphp\Model\Cache\ModelCache;
8
use Chubbyphp\Model\Cache\ModelCacheInterface;
9
use Chubbyphp\Model\ModelInterface;
10
use Chubbyphp\Model\RepositoryInterface;
11
use Doctrine\DBAL\Connection;
12
use Doctrine\DBAL\Query\QueryBuilder;
13
use Psr\Log\LoggerInterface;
14
use Psr\Log\NullLogger;
15
16
abstract class AbstractDoctrineRepository implements RepositoryInterface
17
{
18
    /**
19
     * @var Connection
20
     */
21
    private $connection;
22
23
    /**
24
     * @var ModelCacheInterface
25
     */
26
    private $cache;
27
28
    /**
29
     * @var LoggerInterface
30
     */
31
    private $logger;
32
33
    /**
34
     * @param Connection               $connection
35
     * @param ModelCacheInterface|null $cache
36
     * @param LoggerInterface|null     $logger
37
     */
38
    public function __construct(
39
        Connection $connection,
40
        ModelCacheInterface $cache = null,
41
        LoggerInterface $logger = null
42
    ) {
43
        $this->connection = $connection;
44
        $this->cache = $cache ?? new ModelCache();
45
        $this->logger = $logger ?? new NullLogger();
46
    }
47
48
    /**
49
     * @param string $id
50
     *
51
     * @return ModelInterface|null
52
     */
53
    public function find(string $id)
54
    {
55
        $modelClass = $this->getModelClass();
56
57
        $this->logger->info('model: find model {model} with id {id}', ['model' => $modelClass, 'id' => $id]);
58
59
        if ($this->cache->has($id)) {
60
            return $this->fromRow($this->cache->get($id));
61
        }
62
63
        $qb = $this->connection->createQueryBuilder();
64
        $qb->select('*')->from($this->getTable())->where($qb->expr()->eq('id', ':id'))->setParameter('id', $id);
65
66
        $row = $qb->execute()->fetch(\PDO::FETCH_ASSOC);
67 View Code Duplication
        if (false === $row) {
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...
68
            $this->logger->warning(
69
                'model: model {model} with id {id} not found',
70
                ['model' => $modelClass, 'id' => $id]
71
            );
72
73
            return null;
74
        }
75
76
        $this->cache->set($row['id'], $row);
77
78
        return $this->fromRow($row);
79
    }
80
81
    /**
82
     * @param array $criteria
83
     *
84
     * @return null|ModelInterface
85
     */
86
    public function findOneBy(array $criteria)
87
    {
88
        $modelClass = $this->getModelClass();
89
90
        $this->logger->info(
91
            'model: find model {model} with criteria {criteria}',
92
            ['model' => $modelClass, 'criteria' => $criteria]
93
        );
94
95
        $qb = $this->getFindByQueryBuilder($criteria)->setMaxResults(1);
96
97
        $row = $qb->execute()->fetch(\PDO::FETCH_ASSOC);
98 View Code Duplication
        if (false === $row) {
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...
99
            $this->logger->warning(
100
                'model: model {model} with criteria {criteria} not found',
101
                ['model' => $modelClass, 'criteria' => $criteria]
102
            );
103
104
            return null;
105
        }
106
107
        $this->cache->set($row['id'], $row);
108
109
        return $this->fromRow($row);
110
    }
111
112
    /**
113
     * @param array $criteria
114
     *
115
     * @return ModelInterface[]|array
116
     */
117
    public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array
118
    {
119
        $modelClass = $this->getModelClass();
120
121
        $this->logger->info(
122
            'model: find model {model} with criteria {criteria}',
123
            ['model' => $modelClass, 'criteria' => $criteria]
124
        );
125
126
        $qb = $this
127
            ->getFindByQueryBuilder($criteria)
128
            ->setFirstResult($offset)
129
            ->setMaxResults($limit)
130
        ;
131
132
        if (null !== $orderBy) {
133
            foreach ($orderBy as $field => $direction) {
134
                $qb->addOrderBy($field, $direction);
135
            }
136
        }
137
138
        $rows = $qb->execute()->fetchAll(\PDO::FETCH_ASSOC);
139
140
        if ([] === $rows) {
141
            return [];
142
        }
143
144
        $models = [];
145
        foreach ($rows as $row) {
146
            $this->cache->set($row['id'], $row);
147
            $models[] = $this->fromRow($row);
148
        }
149
150
        return $models;
151
    }
152
153
    /**
154
     * @param array $criteria
155
     *
156
     * @return QueryBuilder
157
     */
158
    private function getFindByQueryBuilder(array $criteria = []): QueryBuilder
159
    {
160
        $qb = $this->connection->createQueryBuilder();
161
        $qb->select('*')->from($this->getTable());
162
163
        foreach ($criteria as $field => $value) {
164
            $qb->andWhere($qb->expr()->eq($field, ':'.$field));
165
            $qb->setParameter($field, $value);
166
        }
167
168
        return $qb;
169
    }
170
171
    /**
172
     * @param ModelInterface $model
173
     */
174
    public function persist(ModelInterface $model)
175
    {
176
        $this->logger->info(
177
            'model: persist model {model} with id {id}',
178
            ['model' => get_class($model), 'id' => $model->getId()]
179
        );
180
181
        if (null === $this->find($model->getId())) {
182
            $this->connection->insert($this->getTable(), $model->toRow());
183
        } else {
184
            $this->connection->update($this->getTable(), $model->toRow(), ['id' => $model->getId()]);
185
        }
186
187
        $this->cache->set($model->getId(), $model->toRow());
188
    }
189
190
    /**
191
     * @param ModelInterface $model
192
     */
193
    public function remove(ModelInterface $model)
194
    {
195
        $this->logger->info(
196
            'model: remove model {model} with id {id}',
197
            ['model' => get_class($model), 'id' => $model->getId()]
198
        );
199
200
        $this->connection->remove($this->getTable(), ['id' => $model->getId()]);
0 ignored issues
show
Bug introduced by
The method remove() does not seem to exist on object<Doctrine\DBAL\Connection>.

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...
201
202
        $this->cache->remove($model->getId());
203
    }
204
205
    /**
206
     * @param array $row
207
     * @return ModelInterface
208
     */
209
    protected function fromRow(array $row): ModelInterface
210
    {
211
        /** @var ModelInterface $modelClass */
212
        $modelClass = $this->getModelClass();
213
214
        return $modelClass::fromRow($row);
215
    }
216
217
    /**
218
     * @return string
219
     */
220
    abstract protected function getTable(): string;
221
}
222