Completed
Push — ezp25946-migrate_files_to_othe... ( 5c47cf...c757fe )
by
unknown
13:02
created

LegacyDFSCluster::mapArrayToSPIBinaryFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 1
dl 10
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the eZ Publish Legacy package.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributd with this source code.
8
 */
9
namespace eZ\Publish\Core\IO\IOMetadataHandler;
10
11
use DateTime;
12
use eZ\Publish\Core\IO\IOMetadataHandler;
13
use Doctrine\DBAL\Connection;
14
use Doctrine\DBAL\DBALException;
15
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
16
use eZ\Publish\Core\IO\Exception\BinaryFileNotFoundException;
17
use eZ\Publish\Core\IO\Exception\InvalidBinaryFileIdException;
18
use eZ\Publish\Core\IO\UrlDecorator;
19
use eZ\Publish\SPI\IO\BinaryFileCreateStruct as SPIBinaryFileCreateStruct;
20
use eZ\Publish\SPI\IO\BinaryFile as SPIBinaryFile;
21
use RuntimeException;
22
23
/**
24
 * Manages IO metadata in a mysql table, ezdfsfile.
25
 *
26
 * It will prevent simultaneous writes to the same file.
27
 */
28
class LegacyDFSCluster implements IOMetadataHandler
29
{
30
    /** @var Connection */
31
    private $db;
32
33
    /** @var UrlDecorator */
34
    private $urlDecorator;
35
36
    /**
37
     * @param Connection $connection Doctrine DBAL connection
38
     * @param UrlDecorator $urlDecorator The URL decorator used to add a prefix to files path
39
     */
40
    public function __construct(Connection $connection, UrlDecorator $urlDecorator = null)
41
    {
42
        $this->db = $connection;
43
        $this->urlDecorator = $urlDecorator;
44
    }
45
46
    /**
47
     * Inserts a new reference to file $spiBinaryFileId.
48
     *
49
     * @param string  $spiBinaryFileId
0 ignored issues
show
Bug introduced by
There is no parameter named $spiBinaryFileId. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
50
     *
51
     * @throws RuntimeException if a DBAL error occurs
52
     *
53
     * @return \eZ\Publish\SPI\IO\BinaryFile
54
     */
55
    public function create(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
56
    {
57
        $path = $this->addPrefix($binaryFileCreateStruct->id);
58
59
        try {
60
            /*
61
             * @todo what might go wrong here ? Can another process be trying to insert the same image ?
62
             *       what happens if somebody did ?
63
             **/
64
            $stmt = $this->db->prepare(<<<SQL
65
INSERT INTO ezdfsfile
66
  (name, name_hash, name_trunk, mtime, size, scope, datatype)
67
  VALUES (:name, :name_hash, :name_trunk, :mtime, :size, :scope, :datatype)
68
ON DUPLICATE KEY UPDATE
69
  datatype=VALUES(datatype), scope=VALUES(scope), size=VALUES(size),
70
  mtime=VALUES(mtime)
71
SQL
72
            );
73
            $stmt->bindValue('name', $path);
74
            $stmt->bindValue('name_hash', md5($path));
75
            $stmt->bindValue('name_trunk', $this->getNameTrunk($binaryFileCreateStruct));
76
            $stmt->bindValue(
77
                'mtime',
78
                $binaryFileCreateStruct->mtime instanceof DateTime
79
                    ? $binaryFileCreateStruct->mtime->getTimestamp()
80
                    : $binaryFileCreateStruct->mtime
81
            );
82
            $stmt->bindValue('size', $binaryFileCreateStruct->size);
83
            $stmt->bindValue('scope', $this->getScope($binaryFileCreateStruct));
84
            $stmt->bindValue('datatype', $binaryFileCreateStruct->mimeType);
85
            $stmt->execute();
86
        } catch (DBALException $e) {
87
            throw new RuntimeException("A DBAL error occured while writing $path", 0, $e);
88
        }
89
90
        return $this->mapSPIBinaryFileCreateStructToSPIBinaryFile($binaryFileCreateStruct);
91
    }
92
93
    /**
94
     * Deletes file $spiBinaryFileId.
95
     *
96
     * @throws BinaryFileNotFoundException If $spiBinaryFileId is not found
97
     *
98
     * @param string $spiBinaryFileId
99
     */
100 View Code Duplication
    public function delete($spiBinaryFileId)
101
    {
102
        $path = $this->addPrefix($spiBinaryFileId);
103
104
        // Unlike the legacy cluster, the file is directly deleted. It was inherited from the DB cluster anyway
105
        $stmt = $this->db->prepare('DELETE FROM ezdfsfile WHERE name_hash LIKE :name_hash');
106
        $stmt->bindValue('name_hash', md5($path));
107
        $stmt->execute();
108
109
        if ($stmt->rowCount() != 1) {
110
            // Is this really necessary ?
111
            throw new BinaryFileNotFoundException($path);
112
        }
113
    }
114
115
    /**
116
     * Loads and returns metadata for $spiBinaryFileId.
117
     *
118
     * @param string $spiBinaryFileId
119
     *
120
     * @return SPIBinaryFile
121
     *
122
     * @throws BinaryFileNotFoundException if no row is found for $spiBinaryFileId
123
     * @throws DBALException Any unhandled DBAL exception
124
     */
125
    public function load($spiBinaryFileId)
126
    {
127
        $path = $this->addPrefix($spiBinaryFileId);
128
129
        $stmt = $this->db->prepare('SELECT * FROM ezdfsfile WHERE name_hash LIKE ? AND expired != 1 AND mtime > 0');
130
        $stmt->bindValue(1, md5($path));
131
        $stmt->execute();
132
133
        if ($stmt->rowCount() == 0) {
134
            throw new BinaryFileNotFoundException($path);
135
        }
136
137
        $row = $stmt->fetch(\PDO::FETCH_ASSOC) + array('id' => $spiBinaryFileId);
138
139
        return $this->mapArrayToSPIBinaryFile($row);
140
    }
141
142
    /**
143
     * Checks if a file $spiBinaryFileId exists.
144
     *
145
     * @param string $spiBinaryFileId
146
     *
147
     * @throws NotFoundException
148
     * @throws DBALException Any unhandled DBAL exception
149
     *
150
     * @return bool
151
     */
152 View Code Duplication
    public function exists($spiBinaryFileId)
153
    {
154
        $path = $this->addPrefix($spiBinaryFileId);
155
156
        $stmt = $this->db->prepare('SELECT name FROM ezdfsfile WHERE name_hash LIKE ? and mtime > 0 and expired != 1');
157
        $stmt->bindValue(1, md5($path));
158
        $stmt->execute();
159
160
        return ($stmt->rowCount() == 1);
161
    }
162
163
    /**
164
     * @param SPIBinaryFileCreateStruct $binaryFileCreateStruct
165
     *
166
     * @return mixed
167
     */
168
    protected function getNameTrunk(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
169
    {
170
        return $this->addPrefix($binaryFileCreateStruct->id);
171
    }
172
173
    /**
174
     * Returns the value for the scope meta field, based on the created file's path.
175
     *
176
     * Note that this is slightly incorrect, as it will return binaryfile for media files as well. It is a bit
177
     * of an issue, but shouldn't be a blocker given that this meta field isn't used that much.
178
     *
179
     * @param SPIBinaryFileCreateStruct $binaryFileCreateStruct
180
     *
181
     * @return string
182
     */
183
    protected function getScope(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
184
    {
185
        list($filePrefix) = explode('/', $binaryFileCreateStruct->id);
186
187
        switch ($filePrefix) {
188
            case 'images':
189
                return 'image';
190
191
            case 'original':
192
                return 'binaryfile';
193
        }
194
195
        return 'UNKNOWN_SCOPE';
196
    }
197
198
    /**
199
     * Adds the internal prefix string to $id.
200
     *
201
     * @param string $id
202
     *
203
     * @return string prefixed id
204
     */
205
    protected function addPrefix($id)
206
    {
207
        return isset($this->urlDecorator) ? $this->urlDecorator->decorate($id) : $id;
208
    }
209
210
    /**
211
     * Removes the internal prefix string from $prefixedId.
212
     *
213
     * @param string $prefixedId
214
     *
215
     * @return string the id without the prefix
216
     *
217
     * @throws InvalidBinaryFileIdException if the prefix isn't found in $prefixedId
218
     */
219
    protected function removePrefix($prefixedId)
220
    {
221
        return isset($this->urlDecorator) ? $this->urlDecorator->undecorate($prefixedId) : $prefixedId;
222
    }
223
224 View Code Duplication
    public function getMimeType($spiBinaryFileId)
225
    {
226
        $stmt = $this->db->prepare('SELECT * FROM ezdfsfile WHERE name_hash LIKE ? AND expired != 1 AND mtime > 0');
227
        $stmt->bindValue(1, md5($this->addPrefix($spiBinaryFileId)));
228
        $stmt->execute();
229
230
        if ($stmt->rowCount() == 0) {
231
            throw new BinaryFileNotFoundException($spiBinaryFileId);
232
        }
233
234
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
235
236
        return $row['datatype'];
237
    }
238
239
    public function deleteDirectory($spiPath)
240
    {
241
        $stmt = $this->db->prepare('DELETE FROM ezdfsfile WHERE name LIKE ?');
242
        $stmt->bindValue(1, rtrim($spiPath, '/') . '/%');
243
        $stmt->execute();
244
    }
245
246
    /**
247
     * Maps an array of data base properties (id, size, mtime, datatype, md5_path, path...) to an SPIBinaryFile object.
248
     *
249
     * @param array $properties database properties array
250
     *
251
     * @return SPIBinaryFile
252
     */
253 View Code Duplication
    protected function mapArrayToSPIBinaryFile(array $properties)
254
    {
255
        $spiBinaryFile = new SPIBinaryFile();
256
        $spiBinaryFile->id = $properties['id'];
257
        $spiBinaryFile->size = $properties['size'];
258
        $spiBinaryFile->mtime = new DateTime('@' . $properties['mtime']);
259
        $spiBinaryFile->mimeType = $properties['datatype'];
0 ignored issues
show
Deprecated Code introduced by
The property eZ\Publish\SPI\IO\BinaryFile::$mimeType has been deprecated with message: Since 5.3.3, use IO\Handler::getMimeType()

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
260
261
        return $spiBinaryFile;
262
    }
263
264
    /**
265
     * @param SPIBinaryFileCreateStruct $binaryFileCreateStruct
266
     *
267
     * @return SPIBinaryFile
268
     */
269
    protected function mapSPIBinaryFileCreateStructToSPIBinaryFile(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
270
    {
271
        $spiBinaryFile = new SPIBinaryFile();
272
        $spiBinaryFile->id = $binaryFileCreateStruct->id;
273
        $spiBinaryFile->mtime = $binaryFileCreateStruct->mtime;
274
        $spiBinaryFile->size = $binaryFileCreateStruct->size;
275
        $spiBinaryFile->mimeType = $binaryFileCreateStruct->mimeType;
0 ignored issues
show
Deprecated Code introduced by
The property eZ\Publish\SPI\IO\BinaryFile::$mimeType has been deprecated with message: Since 5.3.3, use IO\Handler::getMimeType()

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
276
277
        return $spiBinaryFile;
278
    }
279
280
    public function loadList($limit = null, $offset = null)
281
    {
282
        $stmt = $this->db->prepare(
283
            'SELECT * FROM ezdfsfile WHERE expired != 1 AND mtime > 0' .
284
            ($limit !== null ? ' LIMIT :limit' : '') .
285
            ($offset !== null ? ' OFFSET :offset' : '')
286
        );
287
        if ($limit !== null) {
288
            $stmt->bindValue('limit', $limit, \PDO::PARAM_INT);
289
        }
290
        if ($offset !== null) {
291
            $stmt->bindValue('offset', $offset, \PDO::PARAM_INT);
292
        }
293
        $stmt->execute();
294
295
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
296
297
        $spiBinaryFileList = [];
298
        foreach ($rows as $row) {
299
            $row['id'] = $this->removePrefix($row['name']);
300
            $spiBinaryFileList[] = $this->mapArrayToSPIBinaryFile($row);
301
        }
302
303
        return $spiBinaryFileList;
304
    }
305
306
    public function count()
307
    {
308
        $stmt = $this->db->prepare('SELECT count(name_hash) as count FROM ezdfsfile WHERE expired != 1 AND mtime > 0');
309
        $stmt->execute();
310
311
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
312
313
        return (int)$row['count'];
314
    }
315
}
316