Completed
Push — master ( ff0a6e...e40fc7 )
by Joschi
02:55
created

Manager::objectResourceExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 9.4285
1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Application
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\Application\Model\Object;
38
39
use Apparat\Kernel\Ports\Kernel;
40
use Apparat\Object\Application\Factory\ObjectFactory;
41
use Apparat\Object\Domain\Model\Object\Id;
42
use Apparat\Object\Domain\Model\Object\ManagerInterface;
43
use Apparat\Object\Domain\Model\Object\ObjectInterface;
44
use Apparat\Object\Domain\Model\Object\ResourceInterface;
45
use Apparat\Object\Domain\Model\Object\Revision;
46
use Apparat\Object\Domain\Model\Object\Type;
47
use Apparat\Object\Domain\Model\Path\RepositoryPath;
48
use Apparat\Object\Domain\Model\Path\RepositoryPathInterface;
49
use Apparat\Object\Domain\Repository\InvalidArgumentException;
50
use Apparat\Object\Domain\Repository\RepositoryInterface;
51
use Apparat\Object\Domain\Repository\Selector;
52
use Apparat\Object\Domain\Repository\SelectorInterface;
53
use Apparat\Resource\Ports\InvalidReaderArgumentException;
54
55
/**
56
 * Object manager
57
 *
58
 * @package Apparat\Object
59
 * @subpackage Apparat\Object\Infrastructure
60
 */
61
class Manager implements ManagerInterface
62
{
63
    /**
64
     * Create and return a new object
65
     *
66
     * @param RepositoryInterface $repository Repository to create the object in
67
     * @param Type $type Object type
68
     * @param string $payload Object payload
69
     * @param array $propertyData Object property data
70
     * @return ObjectInterface Object
71
     */
72
    public function createObject(RepositoryInterface $repository, Type $type, $payload = '', array $propertyData = [])
73
    {
74
        // Construct a creation closure
75 5
        $creationClosure = function (Id $uid) use ($repository, $type, $payload, $propertyData) {
76
            /** @var Revision $revision */
77 4
            $revision = Kernel::create(Revision::class, [1, true]);
78
79
            /** @var RepositoryPath $repositoryPath */
80 4
            $repositoryPath = Kernel::create(RepositoryPath::class, [$repository]);
81 4
            $repositoryPath = $repositoryPath->setId($uid);
82 4
            $repositoryPath = $repositoryPath->setRevision($revision);
83 4
            $repositoryPath = $repositoryPath->setType($type);
84 4
            $repositoryPath = $repositoryPath->setCreationDate(new \DateTimeImmutable());
85
86 4
            return ObjectFactory::createFromParams($repositoryPath, $payload, $propertyData);
87 5
        };
88
89
        // Wrap the object creation in an ID allocation transaction
90 5
        return $repository->getAdapterStrategy()->createObjectResource($creationClosure);
91
    }
92
93
    /**
94
     * Load an object from a repository
95
     *
96
     * @param RepositoryPathInterface $path Repository object path
97
     * @param int $visibility Object visibility
98
     * @return ObjectInterface Object
99
     * @throws InvalidArgumentException If the visibility requirement is invalid
100
     */
101 26
    public function loadObject(RepositoryPathInterface $path, $visibility = SelectorInterface::ALL)
102
    {
103
        // Create the current revision path
104
        /** @var RepositoryPathInterface $currentPath */
105 26
        $currentPath = $path->setRevision(Revision::current());
106
107
        // Load the object resource respecting visibility constraints
108 26
        $objectResource = $this->loadObjectResource($currentPath, $visibility);
109
110
        // Instantiate the object
111 24
        $object = ObjectFactory::createFromResource($currentPath, $objectResource);
0 ignored issues
show
Bug introduced by
It seems like $objectResource defined by $this->loadObjectResourc...rrentPath, $visibility) on line 108 can be null; however, Apparat\Object\Applicati...y::createFromResource() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
112
113
        // Use and return the requested object revision
114 24
        return $object->useRevision($path->getRevision());
115
    }
116
117
    /**
118
     * Load and return an object resource respecting visibility constraints
119
     *
120
     * @param RepositoryPathInterface $currentPath
121
     * @param int $visibility Object visibility
122
     * @return ResourceInterface Object resource
123
     */
124 27
    public function loadObjectResource(RepositoryPathInterface &$currentPath, $visibility = SelectorInterface::ALL)
125
    {
126
        // Validate the object visibility
127 27
        $this->validateVisibility($visibility);
128
129 26
        $objectResource = null;
130
131
        // Create the current revision paths (visible and hidden)
132
        /** @var RepositoryPathInterface[] $currentPaths */
133 26
        $currentPaths = array_filter([
134 26
            ($visibility & SelectorInterface::VISIBLE) ? $currentPath->setHidden(false) : null,
135 26
            ($visibility & SelectorInterface::HIDDEN) ? $currentPath->setHidden(true) : null,
136 26
        ]);
137
138
        // Run through the possible revision paths
139 26
        foreach ($currentPaths as $currentPathIndex => $currentPath) {
140
            try {
141
                // Load the current object resource
142 26
                $objectResource = $this->getObjectResource($currentPath);
143 25
                break;
144
145
                // In case of an error
146 3
            } catch (InvalidReaderArgumentException $e) {
147
                // If it's not an error about the resource not existing or if it's the last possible option
148 3
                if (($e->getCode() != InvalidReaderArgumentException::RESOURCE_DOES_NOT_EXIST)
149 3
                    || ($currentPathIndex >= (count($currentPaths) - 1))
150 3
                ) {
151 1
                    throw $e;
152
                }
153
            }
154 26
        }
155
156 25
        return $objectResource;
157
    }
158
159
    /**
160
     * Validate a given object visibility
161
     *
162
     * @param int $visibility Object visibility
163
     * @throw InvalidArgumentException If the visibility requirement is invalid
164
     */
165 27
    protected function validateVisibility($visibility) {
166
        // If the visibility requirement is invalid
167 27
        if (!Selector::isValidVisibility($visibility)) {
168 1
            throw new InvalidArgumentException(
169 1
                sprintf(
170 1
                    'Invalid repository selector visibility "%s"',
171
                    $visibility
172 1
                ),
173 1
                InvalidArgumentException::INVALID_REPOSITORY_SELECTOR_COMPONENT,
174 1
                null,
175
                'visibility'
176 1
            );
177
        }
178 26
    }
179
180
    /**
181
     * Instantiate object resource
182
     *
183
     * @param RepositoryPathInterface $path
184
     * @return ResourceInterface Object resource
185
     */
186 26
    public function getObjectResource(RepositoryPathInterface $path)
187
    {
188 26
        return $path->getRepository()->getAdapterStrategy()->getObjectResource(
189 26
            $path->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
190 26
        );
191
    }
192
193
    /**
194
     * Test whether an object resource exists
195
     *
196
     * @param RepositoryPathInterface $path
197
     * @return boolean Object resource exists
198
     */
199 28
    public function objectResourceExists(RepositoryPathInterface $path)
200
    {
201 28
        return $path->getRepository()->getAdapterStrategy()->hasResource(
202 28
            $path->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
203 28
        );
204
    }
205
}
206