Completed
Push — master ( 36152a...1c7656 )
by Beñat
02:48
created

SqlFileRepository::all()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 9
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 9
loc 9
rs 9.6666
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
3
/*
4
 * This file is part of the BenGorFile package.
5
 *
6
 * (c) Beñat Espiña <[email protected]>
7
 * (c) Gorka Laucirica <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace BenGorFile\File\Infrastructure\Persistence\Sql;
14
15
use BenGorFile\File\Domain\Model\File;
16
use BenGorFile\File\Domain\Model\FileId;
17
use BenGorFile\File\Domain\Model\FileMimeType;
18
use BenGorFile\File\Domain\Model\FileName;
19
use BenGorFile\File\Domain\Model\FileRepository;
20
use BenGorFile\File\Infrastructure\Domain\Model\FileEventBus;
21
22
/**
23
 * Sql file repository class.
24
 *
25
 * @author Beñat Espiña <[email protected]>
26
 * @author Gorka Laucirica <[email protected]>
27
 */
28
final class SqlFileRepository implements FileRepository
29
{
30
    const DATE_FORMAT = 'Y-m-d H:i:s';
31
32
    /**
33
     * The pdo instance.
34
     *
35
     * @var \PDO
36
     */
37
    private $pdo;
38
39
    /**
40
     * The file event bus, it can be null.
41
     *
42
     * @var FileEventBus|null
43
     */
44
    private $eventBus;
45
46
    /**
47
     * Constructor.
48
     *
49
     * @param \PDO              $aPdo       The pdo instance
50
     * @param FileEventBus|null $anEventBus The file event bus, it can be null
51
     */
52
    public function __construct(\PDO $aPdo, FileEventBus $anEventBus = null)
53
    {
54
        $this->pdo = $aPdo;
55
        $this->eventBus = $anEventBus;
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61 View Code Duplication
    public function fileOfId(FileId $anId)
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...
62
    {
63
        $statement = $this->execute('SELECT * FROM file WHERE id = :id', ['id' => $anId->id()]);
64
        if ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
65
            return $this->buildFile($row);
66
        }
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72 View Code Duplication
    public function fileOfName(FileName $aName)
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...
73
    {
74
        $statement = $this->execute('SELECT * FROM file WHERE name = :name AND extension = :extension', [
75
            'name'      => $aName->name(),
76
            'extension' => $aName->extension(),
77
        ]);
78
        if ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
79
            return $this->buildFile($row);
80
        }
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86 View Code Duplication
    public function all()
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...
87
    {
88
        $statement = $this->execute('SELECT * FROM file');
0 ignored issues
show
Bug introduced by
The call to execute() misses a required argument $parameters.

This check looks for function calls that miss required arguments.

Loading history...
89
        if ($rows = $statement->fetch(\PDO::FETCH_ASSOC)) {
90
            return array_map(function ($row) {
91
                return $this->buildFile($row);
92
            }, $rows);
93
        }
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    public function persist(File $aFile)
100
    {
101
        ($this->exist($aFile)) ? $this->update($aFile) : $this->insert($aFile);
102
103
        if ($this->eventBus instanceof FileEventBus) {
104
            $this->handle($aFile->events());
105
        }
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function remove(File $aFile)
112
    {
113
        $this->execute('DELETE FROM file WHERE id = :id', ['id' => $aFile->id()->id()]);
114
115
        if ($this->eventBus instanceof FileEventBus) {
116
            $this->handle($aFile->events());
117
        }
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function size()
124
    {
125
        return $this->pdo->query('SELECT COUNT(*) FROM file')->fetchColumn();
126
    }
127
128
    /**
129
     * Loads the file schema into database create the table
130
     * with file attribute properties as columns.
131
     */
132
    public function initSchema()
133
    {
134
        $this->pdo->exec(<<<SQL
135
DROP TABLE IF EXISTS file;
136
CREATE TABLE file (
137
    id CHAR(36) PRIMARY KEY,
138
    name VARCHAR(255) NOT NULL,
139
    extension VARCHAR(100) NOT NULL,
140
    mime_type VARCHAR(255) NOT NULL,
141
    created_on DATETIME NOT NULL,
142
    updated_on DATETIME NOT NULL
143
)
144
SQL
145
        );
146
    }
147
148
    /**
149
     * Checks if the file given exists in the database.
150
     *
151
     * @param File $aFile The file
152
     *
153
     * @return bool
154
     */
155
    private function exist(File $aFile)
156
    {
157
        $count = $this->execute(
158
            'SELECT COUNT(*) FROM file WHERE id = :id', [':id' => $aFile->id()->id()]
159
        )->fetchColumn();
160
161
        return $count === 1;
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $count (string) and 1 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
162
    }
163
164
    /**
165
     * Prepares the insert SQL with the file given.
166
     *
167
     * @param File $aFile The file
168
     */
169
    private function insert(File $aFile)
170
    {
171
        $sql = 'INSERT INTO file (id, name, extension, mime_type, created_on, updated_on) VALUES (:id, :name, :extension, :mimeType, :createdOn, :updatedOn)';
172
        $this->execute($sql, [
173
            'id'        => $aFile->id()->id(),
174
            'name'      => $aFile->name()->name(),
175
            'extension' => $aFile->name()->extension(),
176
            'mimeType'  => $aFile->mimeType(),
177
            'createdOn' => $aFile->createdOn()->format(self::DATE_FORMAT),
178
            'updatedOn' => $aFile->updatedOn()->format(self::DATE_FORMAT),
179
        ]);
180
    }
181
182
    /**
183
     * Prepares the update SQL with the file given.
184
     *
185
     * @param File $aFile The file
186
     */
187
    private function update(File $aFile)
188
    {
189
        $this->execute('UPDATE file SET name = :name, extension = :extension, mime_type = :mimeType, updated_on = :updatedOn WHERE id = :id', [
190
            'name'      => $aFile->name()->name(),
191
            'extension' => $aFile->name()->extension(),
192
            'mimeType'  => $aFile->mimeType(),
193
            'updatedOn' => $aFile->updatedOn(),
194
            'id'        => $aFile->id()->id(),
195
        ]);
196
    }
197
198
    /**
199
     * Wrapper that encapsulates the same logic about execute the query in PDO.
200
     *
201
     * @param string $aSql       The SQL
202
     * @param array  $parameters Array which contains the parameters of SQL
203
     *
204
     * @return \PDOStatement
205
     */
206
    private function execute($aSql, array $parameters)
207
    {
208
        $statement = $this->pdo->prepare($aSql);
209
        $statement->execute($parameters);
210
211
        return $statement;
212
    }
213
214
    /**
215
     * Builds the file with the given sql row attributes.
216
     *
217
     * @param array $row Array which contains attributes of file
218
     *
219
     * @return File
220
     */
221
    private function buildFile($row)
222
    {
223
        $file = new File(
224
            new FileId($row['id']),
225
            new FileName($row['name'] . '.' . $row['extension']),
226
            new FileMimeType($row['mime_type'])
227
        );
228
229
        $createdOn = new \DateTimeImmutable($row['created_on']);
230
        $updatedOn = new \DateTimeImmutable($row['updated_on']);
231
232
        $file = $this->set($file, 'createdOn', $createdOn);
233
        $file = $this->set($file, 'updatedOn', $updatedOn);
234
235
        return $file;
236
    }
237
238
    /**
239
     * Populates by Reflection the domain object with the given SQL plain values.
240
     *
241
     * @param File   $file          The file domain object
242
     * @param string $propertyName  The property name
243
     * @param mixed  $propertyValue The property value
244
     *
245
     * @return File
246
     */
247
    private function set(File $file, $propertyName, $propertyValue)
248
    {
249
        $reflectionFile = new \ReflectionClass($file);
250
        $reflectionCreatedOn = $reflectionFile->getProperty($propertyName);
251
        $reflectionCreatedOn->setAccessible(true);
252
        $reflectionCreatedOn->setValue($file, $propertyValue);
253
254
        return $file;
255
    }
256
257
    /**
258
     * Handles the given events with event bus.
259
     *
260
     * @param array $events A collection of file domain events
261
     */
262
    private function handle($events)
263
    {
264
        foreach ($events as $event) {
265
            $this->eventBus->handle($event);
266
        }
267
    }
268
}
269