Completed
Push — master ( 151e42...9754e0 )
by Joschi
03:37
created

FileAdapterStrategy   D

Complexity

Total Complexity 60

Size/Duplication

Total Lines 467
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 15

Test Coverage

Coverage 100%

Importance

Changes 34
Bugs 1 Features 8
Metric Value
c 34
b 1
f 8
dl 0
loc 467
ccs 197
cts 197
cp 1
rs 4.2857
wmc 60
lcom 2
cbo 15

15 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 36 7
C initializeRepository() 0 27 7
F findObjectPaths() 0 58 13
A getResourceHash() 0 4 2
A hasResource() 0 4 1
A importResource() 0 4 1
A getObjectResource() 0 4 1
B createObjectResource() 0 51 5
A persistObject() 0 18 4
B deleteObject() 0 25 5
A getAbsoluteResourcePath() 0 8 1
A persistObjectResource() 0 17 1
B undeleteObject() 0 25 5
B publishObject() 0 31 4
A getRepositorySize() 0 9 3

How to fix   Complexity   

Complex Class

Complex classes like FileAdapterStrategy often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FileAdapterStrategy, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Infrastructure
9
 * @author      Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright   Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license     http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Apparat\Object\Infrastructure\Repository;
38
39
use Apparat\Kernel\Ports\Kernel;
40
use Apparat\Object\Application\Repository\AbstractAdapterStrategy;
41
use Apparat\Object\Domain\Model\Object\Id;
42
use Apparat\Object\Domain\Model\Object\ObjectInterface;
43
use Apparat\Object\Domain\Model\Object\ResourceInterface;
44
use Apparat\Object\Domain\Model\Object\Revision;
45
use Apparat\Object\Domain\Model\Uri\LocatorInterface;
46
use Apparat\Object\Domain\Model\Uri\RepositoryLocator;
47
use Apparat\Object\Domain\Model\Uri\RepositoryLocatorInterface;
48
use Apparat\Object\Domain\Repository\AdapterStrategyInterface;
49
use Apparat\Object\Domain\Repository\RepositoryInterface;
50
use Apparat\Object\Domain\Repository\RuntimeException as DomainRepositoryRuntimeException;
51
use Apparat\Object\Domain\Repository\Selector;
52
use Apparat\Object\Domain\Repository\SelectorInterface;
53
use Apparat\Object\Infrastructure\Factory\ResourceFactory;
54
use Apparat\Object\Infrastructure\Utilities\File;
55
use Apparat\Resource\Domain\Model\Resource\AbstractResource;
56
use Apparat\Resource\Infrastructure\Io\File\AbstractFileReaderWriter;
57
use Apparat\Resource\Infrastructure\Io\File\Writer;
58
59
/**
60
 * File adapter strategy
61
 *
62
 * @package Apparat\Object
63
 * @subpackage Apparat\Object\Infrastructure
64
 */
65
class FileAdapterStrategy extends AbstractAdapterStrategy
66
{
67
    /**
68
     * Adapter strategy type
69
     *
70
     * @var string
71
     */
72
    const TYPE = 'file';
73
    /**
74
     * Glob visibilities
75
     *
76
     * @var array
77
     */
78
    protected static $globVisibilities = [
79
        SelectorInterface::VISIBLE => '',
80
        SelectorInterface::HIDDEN => '.',
81
        SelectorInterface::ALL => '{.,}',
82
    ];
83
    /**
84
     * Configuration
85
     *
86
     * @var array
87
     */
88
    protected $config = null;
89
    /**
90
     * Root directory (without trailing directory separator)
91
     *
92
     * @var string
93
     */
94
    protected $root = null;
95
    /**
96
     * Configuration directory (including trailing directory separator)
97
     *
98
     * @var string
99
     */
100
    protected $configDir = null;
101
102
    /**
103
     * Adapter strategy constructor
104
     *
105
     * @param array $config Adapter strategy configuration
106
     * @throws InvalidArgumentException If the root directory configuration is empty
107
     * @throws InvalidArgumentException If the root directory configuration is invalid
108
     */
109 23
    public function __construct(array $config)
110
    {
111 23
        parent::__construct($config, ['root']);
112
113
        // If the root directory configuration is empty
114 22
        if (empty($this->config['root'])) {
115 1
            throw new InvalidArgumentException(
116 1
                'Empty file adapter strategy root',
117
                InvalidArgumentException::EMTPY_FILE_STRATEGY_ROOT
118 1
            );
119
        }
120
121
        // Get the real locator of the root directory
122 21
        $this->root = realpath($this->config['root']);
123
124
        // If the repository should be initialized
125 21
        if (!empty($this->config['init'])
126 21
            && (boolean)$this->config['init']
127 21
            && $this->initializeRepository()
128 19
        ) {
129 8
            $this->root = realpath($this->config['root']);
130 8
        }
131
132
        // If the root directory configuration is still invalid
133 19
        if (empty($this->root) || !@is_dir($this->root)) {
134 1
            throw new InvalidArgumentException(
135 1
                sprintf(
136 1
                    'Invalid file adapter strategy root "%s"',
137 1
                    $this->config['root']
138 1
                ),
139
                InvalidArgumentException::INVALID_FILE_STRATEGY_ROOT
140 1
            );
141
        }
142
143 18
        $this->configDir = $this->root.DIRECTORY_SEPARATOR.'.repo'.DIRECTORY_SEPARATOR;
144 18
    }
145
146
    /**
147
     * Initialize the repository
148
     *
149
     * @return boolean Success
150
     * @throws DomainRepositoryRuntimeException If the repository cannot be initialized
151
     * @throws DomainRepositoryRuntimeException If the repository size descriptor can not be created
152
     */
153 10
    public function initializeRepository()
154
    {
155
        // Successively create the repository directories
156 10
        $repoDirectories = [$this->config['root'], $this->config['root'].DIRECTORY_SEPARATOR.'.repo'];
157 10
        foreach ($repoDirectories as $repoDirectory) {
158
            // If the repository cannot be initialized
159 10
            if (file_exists($repoDirectory) ? !is_dir($repoDirectory) : !mkdir($repoDirectory, 0777, true)) {
160 1
                throw new DomainRepositoryRuntimeException(
161 1
                    'Could not initialize repository',
162
                    DomainRepositoryRuntimeException::REPO_NOT_INITIALIZED
163 1
                );
164
            }
165 9
        }
166
167
        // If the repository size descriptor can not be created
168 9
        $configDir = $this->config['root'].DIRECTORY_SEPARATOR.'.repo'.DIRECTORY_SEPARATOR;
169 9
        if ((file_exists($configDir.'size.txt') && !is_file($configDir.'size.txt'))
170 8
            || !file_put_contents($configDir.'size.txt', '0')
171 9
        ) {
172 1
            throw new DomainRepositoryRuntimeException(
173 1
                'Could not create repository size descriptor',
174
                DomainRepositoryRuntimeException::REPO_SIZE_DESCRIPTOR_NOT_CREATED
175 1
            );
176
        }
177
178 8
        return true;
179
    }
180
181
    /**
182
     * Find objects by selector
183
     *
184
     * @param Selector|SelectorInterface $selector Object selector
185
     * @param RepositoryInterface $repository Object repository
186
     * @return LocatorInterface[] Object locators
187
     */
188 8
    public function findObjectPaths(SelectorInterface $selector, RepositoryInterface $repository)
189
    {
190 8
        chdir($this->root);
191
192
        // Build a glob string from the selector
193 8
        $glob = '';
194 8
        $globFlags = GLOB_ONLYDIR | GLOB_NOSORT;
195
196 8
        $year = $selector->getYear();
197 8
        if ($year !== null) {
198 8
            $glob .= '/'.$year;
199 8
        }
200
201 8
        $month = $selector->getMonth();
202 8
        if ($month !== null) {
203 8
            $glob .= '/'.$month;
204 8
        }
205
206 8
        $day = $selector->getDay();
207 8
        if ($day !== null) {
208 8
            $glob .= '/'.$day;
209 8
        }
210
211 8
        $hour = $selector->getHour();
212 8
        if ($hour !== null) {
213 2
            $glob .= '/'.$hour;
214 2
        }
215
216 8
        $minute = $selector->getMinute();
217 8
        if ($minute !== null) {
218 2
            $glob .= '/'.$minute;
219 2
        }
220
221 8
        $second = $selector->getSecond();
222 8
        if ($second !== null) {
223 2
            $glob .= '/'.$second;
224 2
        }
225
226 8
        $visibility = $selector->getVisibility();
227 8
        $uid = $selector->getId();
228 8
        $type = $selector->getType();
229 8
        if (($uid !== null) || ($type !== null)) {
230 8
            $glob .= '/'.($uid ?: SelectorInterface::WILDCARD).'-'.($type ?: SelectorInterface::WILDCARD);
231
232 8
            $revision = $selector->getRevision();
233 8
            if ($revision !== null) {
234 1
                $glob .= '/'.self::$globVisibilities[$visibility].($uid ?: SelectorInterface::WILDCARD).'-'.$revision;
235 1
                $globFlags &= ~GLOB_ONLYDIR;
236 1
            }
237 8
        }
238
239 8
        return array_map(
240 8
            function ($objectResourcePath) use ($repository) {
241 8
                return Kernel::create(RepositoryLocator::class, [$repository, '/'.$objectResourcePath]);
242 8
            },
243 8
            glob(ltrim($glob, '/'), $globFlags)
244 8
        );
245
    }
246
247
    /**
248
     * Return an individual hash for a resource
249
     *
250
     * @param string $resourcePath Repository relative resource path
251
     * @return string|null Resource hash
252
     */
253 1
    public function getResourceHash($resourcePath)
254
    {
255 1
        return $this->hasResource($this->root.$resourcePath) ? File::hash($this->root.$resourcePath) : null;
256
    }
257
258
    /**
259
     * Test if an object resource exists
260
     *
261
     * @param string $resourcePath Repository relative resource path
262
     * @return boolean Object resource exists
263
     */
264 43
    public function hasResource($resourcePath)
265
    {
266 43
        return is_file($this->root.$resourcePath);
267
    }
268
269
    /**
270
     * Import a resource into this repository
271
     *
272
     * @param string $source Source resource
273
     * @param string $target Repository relative target resource locator
274
     * @return boolean Success
275
     */
276 2
    public function importResource($source, $target)
277
    {
278 2
        return copy($source, $this->root.$target);
279
    }
280
281
    /**
282
     * Find and return an object resource
283
     *
284
     * @param string $resourcePath Repository relative resource locator
285
     * @return ResourceInterface|AbstractResource Object resource
286
     */
287 39
    public function getObjectResource($resourcePath)
288
    {
289 39
        return ResourceFactory::createFromSource(AbstractFileReaderWriter::WRAPPER.$this->root.$resourcePath);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return \Apparat\Object\I...>root . $resourcePath); (Apparat\Resource\Domain\...source\AbstractResource) is incompatible with the return type declared by the interface Apparat\Object\Domain\Re...face::getObjectResource of type Apparat\Object\Domain\Mo...bject\ResourceInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
290
    }
291
292
    /**
293
     * Allocate an object ID and create an object resource
294
     *
295
     * @param \Closure $creator Object creation closure
296
     * @return ObjectInterface Object
297
     * @throws DomainRepositoryRuntimeException If no object could be created
298
     * @throws \Exception If another error occurs
299
     */
300 7
    public function createObjectResource(\Closure $creator)
301
    {
302 7
        $sizeDescriptor = null;
303
304
        try {
305
            // Open the size descriptor
306 7
            $sizeDescriptor = fopen($this->configDir.'size.txt', 'r+');
307
308
            // If a lock of the size descriptor can be acquired
309 7
            if (flock($sizeDescriptor, LOCK_EX)) {
310
                // Determine the current repository size
311 6
                $repositorySize = '';
312 6
                while (!feof($sizeDescriptor)) {
313 6
                    $repositorySize .= fread($sizeDescriptor, 8);
314 6
                }
315 6
                $repositorySize = intval(trim($repositorySize));
316
317
                // Instantiate the next consecutive object ID
318 6
                $nextObjectId = Kernel::create(Id::class, [++$repositorySize]);
319
320
                // Create & persist the object (bypassing the repository)
321 6
                $object = $creator($nextObjectId);
322 5
                $this->persistObject($object);
323
324
                // Dump the new repository size, unlock the size descriptor
325 5
                ftruncate($sizeDescriptor, 0);
326 5
                fwrite($sizeDescriptor, $repositorySize);
327 5
                fflush($sizeDescriptor);
328 5
                flock($sizeDescriptor, LOCK_UN);
329
330
                // Return the newly created object
331 5
                return $object;
332
            }
333
334
            // If no object could be created
335 1
            throw new DomainRepositoryRuntimeException(
336 1
                'The repository size descriptor is unlockable',
337
                DomainRepositoryRuntimeException::REPO_SIZE_DESCRIPTOR_UNLOCKABLE
338 1
            );
339
340
            // If any exception is thrown
341 2
        } catch (\Exception $e) {
342
            // Release the size descriptor lock
343 2
            if (is_resource($sizeDescriptor)) {
344 2
                flock($sizeDescriptor, LOCK_UN);
345 2
            }
346
347
            // Forward the thrown exception
348 2
            throw $e;
349
        }
350
    }
351
352
    /**
353
     * Persist an object in the repository
354
     *
355
     * @param ObjectInterface $object Object
356
     * @return AdapterStrategyInterface Self reference
357
     */
358 5
    public function persistObject(ObjectInterface $object)
359
    {
360
        // If the object has just been deleted
361 5
        if ($object->hasBeenDeleted()) {
362 3
            return $this->deleteObject($object);
363
364
            // Elseif the object has just been undeleted
365 5
        } elseif ($object->hasBeenUndeleted()) {
366 2
            return $this->undeleteObject($object);
367
368
            // If the object has just been published
369 5
        } elseif ($object->hasBeenPublished()) {
370 2
            $this->publishObject($object);
371 2
        }
372
373
        // Persist the object resource
374 5
        return $this->persistObjectResource($object);
375
    }
376
377
    /**
378
     * Delete all revisions of an object
379
     *
380
     * @param ObjectInterface $object Object
381
     * @return ObjectInterface Object
382
     */
383 3
    protected function deleteObject(ObjectInterface $object)
384
    {
385
        // Hide object directory
386 3
        $objContainerDir = dirname(dirname($this->getAbsoluteResourcePath($object->getRepositoryLocator())));
0 ignored issues
show
Compatibility introduced by
$object->getRepositoryLocator() of type object<Apparat\Object\Do...l\Uri\LocatorInterface> is not a sub-type of object<Apparat\Object\Do...sitoryLocatorInterface>. It seems like you assume a child interface of the interface Apparat\Object\Domain\Model\Uri\LocatorInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
387 3
        $objContainerName = $object->getId()->getId().'-'.$object->getType()->getType();
388 3
        $objPublicContainer = $objContainerDir.DIRECTORY_SEPARATOR.$objContainerName;
389 3
        $objHiddenContainer = $objContainerDir.DIRECTORY_SEPARATOR.'.'.$objContainerName;
390 3
        if (file_exists($objPublicContainer)
391 3
            && is_dir($objPublicContainer)
392 3
            && !rename($objPublicContainer, $objHiddenContainer)
393 3
        ) {
394 1
            throw new RuntimeException(
395 1
                sprintf('Cannot hide object container "%s"', $objContainerName),
396
                RuntimeException::CANNOT_HIDE_OBJECT_CONTAINER
397 1
            );
398
        }
399
400
        // Delete all object revisions
401
        /** @var ObjectInterface $objectRevision */
402 2
        foreach ($object as $objectRevision) {
403 2
            $this->persistObjectResource($objectRevision->delete());
404 2
        }
405
406 2
        return $this;
407
    }
408
409
    /**
410
     * Build an absolute repository resource locator
411
     *
412
     * @param RepositoryLocatorInterface $repositoryLocator Repository locator
413
     * @return string Absolute repository resource locator
414
     */
415 5
    public function getAbsoluteResourcePath(RepositoryLocatorInterface $repositoryLocator)
416
    {
417 5
        return $this->root.str_replace(
418 5
            '/',
419 5
            DIRECTORY_SEPARATOR,
420 5
            $repositoryLocator->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
421 5
        );
422
    }
423
424
    /**
425
     * Persist an object resource in the repository
426
     *
427
     * @param ObjectInterface $object Object
428
     * @return AdapterStrategyInterface Self reference
429
     */
430 5
    protected function persistObjectResource(ObjectInterface $object)
431
    {
432
        /** @var \Apparat\Object\Infrastructure\Resource $objectResource */
433 5
        $objectResource = ResourceFactory::createFromObject($object);
434
435
        // Create the absolute object resource path
436 5
        $objectResourcePath = $this->getAbsoluteResourcePath($object->getRepositoryLocator());
0 ignored issues
show
Compatibility introduced by
$object->getRepositoryLocator() of type object<Apparat\Object\Do...l\Uri\LocatorInterface> is not a sub-type of object<Apparat\Object\Do...sitoryLocatorInterface>. It seems like you assume a child interface of the interface Apparat\Object\Domain\Model\Uri\LocatorInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
437
438
        /** @var Writer $fileWriter */
439 5
        $fileWriter = Kernel::create(
440 5
            Writer::class,
441 5
            [$objectResourcePath, Writer::FILE_CREATE | Writer::FILE_CREATE_DIRS | Writer::FILE_OVERWRITE]
442 5
        );
443 5
        $objectResource->dump($fileWriter);
444
445 5
        return $this;
446
    }
447
448
    /**
449
     * Undelete all revisions of an object
450
     *
451
     * @param ObjectInterface $object Object
452
     * @return ObjectInterface Object
453
     */
454 2
    protected function undeleteObject(ObjectInterface $object)
455
    {
456
        // Hide object directory
457 2
        $objContainerDir = dirname(dirname($this->getAbsoluteResourcePath($object->getRepositoryLocator())));
0 ignored issues
show
Compatibility introduced by
$object->getRepositoryLocator() of type object<Apparat\Object\Do...l\Uri\LocatorInterface> is not a sub-type of object<Apparat\Object\Do...sitoryLocatorInterface>. It seems like you assume a child interface of the interface Apparat\Object\Domain\Model\Uri\LocatorInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
458 2
        $objContainerName = $object->getId()->getId().'-'.$object->getType()->getType();
459 2
        $objPublicContainer = $objContainerDir.DIRECTORY_SEPARATOR.$objContainerName;
460 2
        $objHiddenContainer = $objContainerDir.DIRECTORY_SEPARATOR.'.'.$objContainerName;
461 2
        if (file_exists($objHiddenContainer)
462 2
            && is_dir($objHiddenContainer)
463 2
            && !rename($objHiddenContainer, $objPublicContainer)
464 2
        ) {
465 1
            throw new RuntimeException(
466 1
                sprintf('Cannot unhide object container "%s"', $objContainerName),
467
                RuntimeException::CANNOT_UNHIDE_OBJECT_CONTAINER
468 1
            );
469
        }
470
471
        // Undelete all object revisions
472
        /** @var ObjectInterface $objectRevision */
473 1
        foreach ($object as $objectRevision) {
474 1
            $this->persistObjectResource($objectRevision->undelete());
475 1
        }
476
477 1
        return $this;
478
    }
479
480
    /**
481
     * Publish an object in the repository
482
     *
483
     * @param ObjectInterface $object
484
     */
485 2
    protected function publishObject(ObjectInterface $object)
486
    {
487 2
        $objectRepoLocator = $object->getRepositoryLocator();
488
489
        // If the object had been persisted as a draft: Remove the draft resource
490 2
        $objectDraftLocator = $objectRepoLocator->setRevision($object->getRevision()->setDraft(true));
491 2
        $absObjectDraftPath = $this->getAbsoluteResourcePath($objectDraftLocator);
0 ignored issues
show
Compatibility introduced by
$objectDraftLocator of type object<Apparat\Object\Do...l\Uri\LocatorInterface> is not a sub-type of object<Apparat\Object\Do...sitoryLocatorInterface>. It seems like you assume a child interface of the interface Apparat\Object\Domain\Model\Uri\LocatorInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
492 2
        if (@file_exists($absObjectDraftPath)) {
493 2
            unlink($absObjectDraftPath);
494 2
        }
495
496
        // If it's not the first object revision: Rotate the previous revision resource
497 2
        $objectRevisionNumber = $object->getRevision()->getRevision();
498 2
        if ($objectRevisionNumber > 1) {
499
            // Build the "current" object repository locator
500 2
            $currentRevision = Revision::current();
501
            $curObjectResPath =
502 2
                $this->getAbsoluteResourcePath($objectRepoLocator->setRevision($currentRevision));
0 ignored issues
show
Compatibility introduced by
$objectRepoLocator->setRevision($currentRevision) of type object<Apparat\Object\Do...l\Uri\LocatorInterface> is not a sub-type of object<Apparat\Object\Do...sitoryLocatorInterface>. It seems like you assume a child interface of the interface Apparat\Object\Domain\Model\Uri\LocatorInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
503
504
            // Build the previous object repository locator
505
            /** @var Revision $previousRevision */
506 2
            $previousRevision = Kernel::create(Revision::class, [$objectRevisionNumber - 1]);
507
            $prevObjectResPath
508 2
                = $this->getAbsoluteResourcePath($objectRepoLocator->setRevision($previousRevision));
0 ignored issues
show
Compatibility introduced by
$objectRepoLocator->setR...sion($previousRevision) of type object<Apparat\Object\Do...l\Uri\LocatorInterface> is not a sub-type of object<Apparat\Object\Do...sitoryLocatorInterface>. It seems like you assume a child interface of the interface Apparat\Object\Domain\Model\Uri\LocatorInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
509
510
            // Rotate the previous revision's resource path
511 2
            if (file_exists($curObjectResPath)) {
512 2
                rename($curObjectResPath, $prevObjectResPath);
513 2
            }
514 2
        }
515 2
    }
516
517
    /**
518
     * Return the repository size (number of objects in the repository)
519
     *
520
     * @return int Repository size
521
     */
522 7
    public function getRepositorySize()
523
    {
524 7
        $sizeDescriptorFile = $this->configDir.'size.txt';
525 7
        $repositorySize = 0;
526 7
        if (is_file($sizeDescriptorFile) && is_readable($sizeDescriptorFile)) {
527 7
            $repositorySize = intval(file_get_contents($this->configDir.'size.txt'));
528 7
        }
529 7
        return $repositorySize;
530
    }
531
}
532