Completed
Push — master ( 055045...9a4ba5 )
by Dominik
02:13
created

AbstractDoctrineRepository::findOneBy()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 8
Ratio 34.78 %

Importance

Changes 0
Metric Value
dl 8
loc 23
rs 9.0856
c 0
b 0
f 0
cc 2
eloc 13
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Model;
6
7
use Chubbyphp\Model\Cache\ModelCacheInterface;
8
use Chubbyphp\Model\Cache\NullModelCache;
9
use Doctrine\DBAL\Connection;
10
use Doctrine\DBAL\Query\QueryBuilder;
11
use Psr\Log\LoggerInterface;
12
use Psr\Log\NullLogger;
13
14
abstract class AbstractDoctrineRepository implements RepositoryInterface
15
{
16
    /**
17
     * @var Connection
18
     */
19
    private $connection;
20
21
    /**
22
     * @var ModelCacheInterface
23
     */
24
    private $cache;
25
26
    /**
27
     * @var LoggerInterface
28
     */
29
    private $logger;
30
31
    /**
32
     * @param Connection               $connection
33
     * @param ModelCacheInterface|null $cache
34
     * @param LoggerInterface|null     $logger
35
     */
36
    public function __construct(
37
        Connection $connection,
38
        ModelCacheInterface $cache = null,
39
        LoggerInterface $logger = null
40
    ) {
41
        $this->connection = $connection;
42
        $this->cache = $cache ?? new NullModelCache();
43
        $this->logger = $logger ?? new NullLogger();
44
    }
45
46
    /**
47
     * @param string $id
48
     *
49
     * @return ModelInterface|null
50
     */
51
    public function find(string $id)
52
    {
53
        $modelClass = $this->getModelClass();
54
55
        $this->logger->info('model: find model {model} with id {id}', ['model' => $modelClass, 'id' => $id]);
56
57
        if ($this->cache->has($id)) {
58
            return $this->cache->get($id);
59
        }
60
61
        $qb = $this->connection->createQueryBuilder();
62
        $qb->select('*')->from($this->getTable())->where($qb->expr()->eq('id', ':id'))->setParameter('id', $id);
63
64
        $row = $qb->execute()->fetch(\PDO::FETCH_ASSOC);
65 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...
66
            $this->logger->warning(
67
                'model: model {model} with id {id} not found',
68
                ['model' => $modelClass, 'id' => $id]
69
            );
70
71
            return null;
72
        }
73
74
        $model = $this->fromRow($row);
75
76
        $this->cache->set($model);
77
78
        return $model;
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
        return $this->fromRow($row);
108
    }
109
110
    /**
111
     * @param array $criteria
112
     *
113
     * @return ModelInterface[]|array
114
     */
115
    public function findBy(array $criteria = []): array
116
    {
117
        $modelClass = $this->getModelClass();
118
119
        $this->logger->info(
120
            'model: find model {model} with criteria {criteria}',
121
            ['model' => $modelClass, 'criteria' => $criteria]
122
        );
123
124
        $rows = $this->getFindByQueryBuilder($criteria)->execute()->fetchAll(\PDO::FETCH_ASSOC);
125
126
        if ([] === $rows) {
127
            return [];
128
        }
129
130
        $models = [];
131
        foreach ($rows as $row) {
132
            $models[] = $this->fromRow($row);
133
        }
134
135
        return $models;
136
    }
137
138
    /**
139
     * @param array $criteria
140
     *
141
     * @return QueryBuilder
142
     */
143
    private function getFindByQueryBuilder(array $criteria = []): QueryBuilder
144
    {
145
        $qb = $this->connection->createQueryBuilder();
146
        $qb->select('*')->from($this->getTable());
147
148
        foreach ($criteria as $field => $value) {
149
            $qb->andWhere($qb->expr()->eq($field, ':'.$field));
150
            $qb->setParameter($field, $value);
151
        }
152
153
        return $qb;
154
    }
155
156
    /**
157
     * @param ModelInterface $model
158
     */
159 View Code Duplication
    public function insert(ModelInterface $model)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
160
    {
161
        $this->logger->info(
162
            'model: insert model {model} with id {id}',
163
            ['model' => get_class($model), 'id' => $model->getId()]
164
        );
165
166
        $this->connection->insert($this->getTable(), $model->toRow());
167
168
        $this->cache->set($model);
169
    }
170
171
    /**
172
     * @param ModelInterface $model
173
     */
174 View Code Duplication
    public function update(ModelInterface $model)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
175
    {
176
        $this->logger->info(
177
            'model: update model {model} with id {id}',
178
            ['model' => get_class($model), 'id' => $model->getId()]
179
        );
180
181
        $this->connection->update($this->getTable(), $model->toRow(), ['id' => $model->getId()]);
182
183
        $this->cache->set($model);
184
    }
185
186
    /**
187
     * @param ModelInterface $model
188
     */
189 View Code Duplication
    public function delete(ModelInterface $model)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
190
    {
191
        $this->logger->info(
192
            'model: delete model {model} with id {id}',
193
            ['model' => get_class($model), 'id' => $model->getId()]
194
        );
195
196
        $this->connection->delete($this->getTable(), ['id' => $model->getId()]);
197
198
        $this->cache->remove($model->getId());
199
    }
200
201
    /**
202
     * @param array $row
203
     * @return ModelInterface
204
     */
205
    protected function fromRow(array $row): ModelInterface
206
    {
207
        /** @var ModelInterface $modelClass */
208
        $modelClass = $this->getModelClass();
209
210
        return $modelClass::fromRow($row);
211
    }
212
213
    /**
214
     * @return string
215
     */
216
    abstract protected function getTable(): string;
217
}
218