Completed
Push — ezp25946-migrate_files_to_othe... ( 7b23be...d05e09 )
by
unknown
29:04 queued 15:33
created

LegacyDFSCluster::removePrefix()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
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\Base\Exceptions\BadStateException;
13
use eZ\Publish\Core\IO\IOMetadataHandler;
14
use Doctrine\DBAL\Connection;
15
use Doctrine\DBAL\DBALException;
16
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
17
use eZ\Publish\Core\IO\Exception\BinaryFileNotFoundException;
18
use eZ\Publish\Core\IO\Exception\InvalidBinaryFileIdException;
19
use eZ\Publish\Core\IO\UrlDecorator;
20
use eZ\Publish\SPI\IO\BinaryFileCreateStruct as SPIBinaryFileCreateStruct;
21
use eZ\Publish\SPI\IO\BinaryFile as SPIBinaryFile;
22
use RuntimeException;
23
24
/**
25
 * Manages IO metadata in a mysql table, ezdfsfile.
26
 *
27
 * It will prevent simultaneous writes to the same file.
28
 */
29
class LegacyDFSCluster implements IOMetadataHandler
30
{
31
    /** @var Connection */
32
    private $db;
33
34
    /** @var UrlDecorator */
35
    private $urlDecorator;
36
37
    /**
38
     * @param Connection $connection Doctrine DBAL connection
39
     * @param UrlDecorator $urlDecorator The URL decorator used to add a prefix to files path
40
     */
41
    public function __construct(Connection $connection, UrlDecorator $urlDecorator = null)
42
    {
43
        $this->db = $connection;
44
        $this->urlDecorator = $urlDecorator;
45
    }
46
47
    /**
48
     * Inserts a new reference to file $spiBinaryFileId.
49
     *
50
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If a file $spiBinaryFileId already exists
51
     *
52
     * @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...
53
     *
54
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException if an error occurs creating the record
55
     * @throws RuntimeException if a DBAL error occurs
56
     *
57
     * @return \eZ\Publish\SPI\IO\BinaryFile
58
     */
59
    public function create(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
60
    {
61
        $path = $this->addPrefix($binaryFileCreateStruct->id);
62
63
        try {
64
            /*
65
             * @todo what might go wrong here ? Can another process be trying to insert the same image ?
66
             *       what happens if somebody did ?
67
             **/
68
            $stmt = $this->db->prepare(<<<SQL
69
INSERT INTO ezdfsfile
70
  (name, name_hash, name_trunk, mtime, size, scope, datatype)
71
  VALUES (:name, :name_hash, :name_trunk, :mtime, :size, :scope, :datatype)
72
ON DUPLICATE KEY UPDATE
73
  datatype=VALUES(datatype), scope=VALUES(scope), size=VALUES(size),
74
  mtime=VALUES(mtime), expired=VALUES(expired)
75
SQL
76
            );
77
            $stmt->bindValue('name', $path);
78
            $stmt->bindValue('name_hash', md5($path));
79
            $stmt->bindValue('name_trunk', $this->getNameTrunk($binaryFileCreateStruct));
80
            $stmt->bindValue('mtime', $binaryFileCreateStruct->mtime);
81
            $stmt->bindValue('size', $binaryFileCreateStruct->size);
82
            $stmt->bindValue('scope', $this->getScope($binaryFileCreateStruct));
83
            $stmt->bindValue('datatype', $binaryFileCreateStruct->mimeType);
84
            $stmt->execute();
85
        } catch (DBALException $e) {
86
            throw new RuntimeException("A DBAL error occured while writing $path", 0, $e);
87
        }
88
89
        if ($stmt->rowCount() == 0) {
90
            throw new BadStateException('LegacyDFSCluster', 'Unexpected rowCount after creating');
91
        }
92
93
        return $this->mapSPIBinaryFileCreateStructToSPIBinaryFile($binaryFileCreateStruct);
94
    }
95
96
    /**
97
     * Deletes file $spiBinaryFileId.
98
     *
99
     * @throws BinaryFileNotFoundException If $spiBinaryFileId is not found
100
     *
101
     * @param string $spiBinaryFileId
102
     */
103 View Code Duplication
    public function delete($spiBinaryFileId)
104
    {
105
        $path = $this->addPrefix($spiBinaryFileId);
106
107
        // Unlike the legacy cluster, the file is directly deleted. It was inherited from the DB cluster anyway
108
        $stmt = $this->db->prepare('DELETE FROM ezdfsfile WHERE name_hash LIKE :name_hash');
109
        $stmt->bindValue('name_hash', md5($path));
110
        $stmt->execute();
111
112
        if ($stmt->rowCount() != 1) {
113
            // Is this really necessary ?
114
            throw new BinaryFileNotFoundException($path);
115
        }
116
    }
117
118
    /**
119
     * Loads and returns metadata for $spiBinaryFileId.
120
     *
121
     * @param string $spiBinaryFileId
122
     *
123
     * @return SPIBinaryFile
124
     *
125
     * @throws BinaryFileNotFoundException if no row is found for $spiBinaryFileId
126
     * @throws DBALException Any unhandled DBAL exception
127
     */
128
    public function load($spiBinaryFileId)
129
    {
130
        $path = $this->addPrefix($spiBinaryFileId);
131
132
        $stmt = $this->db->prepare('SELECT * FROM ezdfsfile WHERE name_hash LIKE ? AND expired != 1 AND mtime > 0');
133
        $stmt->bindValue(1, md5($path));
134
        $stmt->execute();
135
136
        if ($stmt->rowCount() == 0) {
137
            throw new BinaryFileNotFoundException($path);
138
        }
139
140
        $row = $stmt->fetch(\PDO::FETCH_ASSOC) + array('id' => $spiBinaryFileId);
141
142
        return $this->mapArrayToSPIBinaryFile($row);
143
    }
144
145
    /**
146
     * Checks if a file $spiBinaryFileId exists.
147
     *
148
     * @param string $spiBinaryFileId
149
     *
150
     * @throws NotFoundException
151
     * @throws DBALException Any unhandled DBAL exception
152
     *
153
     * @return bool
154
     */
155 View Code Duplication
    public function exists($spiBinaryFileId)
156
    {
157
        $path = $this->addPrefix($spiBinaryFileId);
158
159
        $stmt = $this->db->prepare('SELECT name FROM ezdfsfile WHERE name_hash LIKE ? and mtime > 0 and expired != 1');
160
        $stmt->bindValue(1, md5($path));
161
        $stmt->execute();
162
163
        return ($stmt->rowCount() == 1);
164
    }
165
166
    /**
167
     * @param SPIBinaryFileCreateStruct $binaryFileCreateStruct
168
     *
169
     * @return mixed
170
     */
171
    protected function getNameTrunk(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
172
    {
173
        return $this->addPrefix($binaryFileCreateStruct->id);
174
    }
175
176
    /**
177
     * Returns the value for the scope meta field, based on the created file's path.
178
     *
179
     * Note that this is slightly incorrect, as it will return binaryfile for media files as well. It is a bit
180
     * of an issue, but shouldn't be a blocker given that this meta field isn't used that much.
181
     *
182
     * @param SPIBinaryFileCreateStruct $binaryFileCreateStruct
183
     *
184
     * @return string
185
     */
186
    protected function getScope(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
187
    {
188
        list($filePrefix) = explode('/', $binaryFileCreateStruct->id);
189
190
        switch ($filePrefix) {
191
            case 'images':
192
                return 'image';
193
194
            case 'original':
195
                return 'binaryfile';
196
        }
197
198
        return 'UNKNOWN_SCOPE';
199
    }
200
201
    /**
202
     * Adds the internal prefix string to $id.
203
     *
204
     * @param string $id
205
     *
206
     * @return string prefixed id
207
     */
208
    protected function addPrefix($id)
209
    {
210
        return isset($this->urlDecorator) ? $this->urlDecorator->decorate($id) : $id;
211
    }
212
213
    /**
214
     * Removes the internal prefix string from $prefixedId.
215
     *
216
     * @param string $prefixedId
217
     *
218
     * @return string the id without the prefix
219
     *
220
     * @throws InvalidBinaryFileIdException if the prefix isn't found in $prefixedId
221
     */
222
    protected function removePrefix($prefixedId)
223
    {
224
        return isset($this->urlDecorator) ? $this->urlDecorator->undecorate($prefixedId) : $prefixedId;
225
    }
226
227 View Code Duplication
    public function getMimeType($spiBinaryFileId)
228
    {
229
        $stmt = $this->db->prepare('SELECT * FROM ezdfsfile WHERE name_hash LIKE ? AND expired != 1 AND mtime > 0');
230
        $stmt->bindValue(1, md5($this->addPrefix($spiBinaryFileId)));
231
        $stmt->execute();
232
233
        if ($stmt->rowCount() == 0) {
234
            throw new BinaryFileNotFoundException($spiBinaryFileId);
235
        }
236
237
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
238
239
        return $row['datatype'];
240
    }
241
242
    public function deleteDirectory($spiPath)
243
    {
244
        $stmt = $this->db->prepare('DELETE FROM ezdfsfile WHERE name LIKE ?');
245
        $stmt->bindValue(1, rtrim($spiPath, '/') . '/%');
246
        $stmt->execute();
247
    }
248
249
    /**
250
     * Maps an array of data base properties (id, size, mtime, datatype, md5_path, path...) to an SPIBinaryFile object.
251
     *
252
     * @param array $properties database properties array
253
     *
254
     * @return SPIBinaryFile
255
     */
256
    protected function mapArrayToSPIBinaryFile(array $properties)
257
    {
258
        $spiBinaryFile = new SPIBinaryFile();
259
        $spiBinaryFile->id = $properties['id'];
260
        $spiBinaryFile->size = $properties['size'];
261
        $spiBinaryFile->mtime = new DateTime('@' . $properties['mtime']);
262
        $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...
263
264
        return $spiBinaryFile;
265
    }
266
267
    /**
268
     * @param SPIBinaryFileCreateStruct $binaryFileCreateStruct
269
     *
270
     * @return SPIBinaryFile
271
     */
272
    protected function mapSPIBinaryFileCreateStructToSPIBinaryFile(SPIBinaryFileCreateStruct $binaryFileCreateStruct)
273
    {
274
        $spiBinaryFile = new SPIBinaryFile();
275
        $spiBinaryFile->id = $binaryFileCreateStruct->id;
276
        $spiBinaryFile->mtime = $binaryFileCreateStruct->mtime;
277
        $spiBinaryFile->size = $binaryFileCreateStruct->size;
278
        $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...
279
280
        return $spiBinaryFile;
281
    }
282
283
    /**
284
     * Count all available files in $scope.
285
     *
286
     * @param string $scope The file scope, one of 'binaryfile', 'image', 'mediafile'
287
     * @return int
288
     */
289 View Code Duplication
    public function count($scope)
290
    {
291
        $stmt = $this->db->prepare('SELECT count(name_hash) as count FROM ezdfsfile WHERE scope LIKE ? AND expired != 1 AND mtime > 0');
292
        $stmt->bindValue(1, $scope);
293
        $stmt->execute();
294
295
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
296
297
        return (int)$row['count'];
298
    }
299
}
300