Completed
Push — master ( 8fa92c...8ed056 )
by Joschi
07:11
created

Manager::validateVisibility()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 9
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 14
ccs 4
cts 4
cp 1
crap 2
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 4
        $creationClosure = function (Id $uid) use ($repository, $type, $payload, $propertyData) {
76
            /** @var Revision $revision */
77 3
            $revision = Kernel::create(Revision::class, [1, true]);
78
79
            /** @var RepositoryPath $repositoryPath */
80 3
            $repositoryPath = Kernel::create(RepositoryPath::class, [$repository]);
81 3
            $repositoryPath = $repositoryPath->setId($uid);
82 3
            $repositoryPath = $repositoryPath->setRevision($revision);
83 3
            $repositoryPath = $repositoryPath->setType($type);
84 3
            $repositoryPath = $repositoryPath->setCreationDate(new \DateTimeImmutable());
85
86 3
            return ObjectFactory::createFromParams($repositoryPath, $payload, $propertyData);
87 4
        };
88
89
        // Wrap the object creation in an ID allocation transaction
90 4
        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 1
129 1
        $objectResource = null;
130 1
131
        // Create the current revision paths (visible and hidden)
132 1
        /** @var RepositoryPathInterface[] $currentPaths */
133 1
        $currentPaths = array_filter([
134 1
            ($visibility & SelectorInterface::VISIBLE) ? $currentPath->setHidden(false) : null,
135
            ($visibility & SelectorInterface::HIDDEN) ? $currentPath->setHidden(true) : null,
136 1
        ]);
137
138
        // Run through the possible revision paths
139 26
        foreach ($currentPaths as $currentPathIndex => $currentPath) {
140
            try {
141
                // Load the current object resource
142
                $objectResource = $this->getObjectResource($currentPath);
143 26
                break;
144 26
145 26
                // In case of an error
146 26
            } catch (InvalidReaderArgumentException $e) {
0 ignored issues
show
Bug introduced by
The class Apparat\Resource\Ports\I...ReaderArgumentException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
147
                // If it's not an error about the resource not existing or if it's the last possible option
148
                if (($e->getCode() != InvalidReaderArgumentException::RESOURCE_DOES_NOT_EXIST)
149 26
                    || ($currentPathIndex >= (count($currentPaths) - 1))
150
                ) {
151
                    throw $e;
152 26
                }
153 25
            }
154
        }
155
156 3
        return $objectResource;
157
    }
158 3
159 3
    /**
160 3
     * Validate a given object visibility
161 1
     *
162
     * @param int $visibility Object visibility
163
     * @throw InvalidArgumentException If the visibility requirement is invalid
164 26
     */
165
    protected function validateVisibility($visibility) {
166 25
        // If the visibility requirement is invalid
167
        if (!Selector::isValidVisibility($visibility)) {
168
            throw new InvalidArgumentException(
169
                sprintf(
170
                    'Invalid repository selector visibility "%s"',
171
                    $visibility
172
                ),
173
                InvalidArgumentException::INVALID_REPOSITORY_SELECTOR_COMPONENT,
174
                null,
175 26
                'visibility'
176
            );
177 26
        }
178 26
    }
179 26
180
    /**
181
     * Instantiate object resource
182
     *
183
     * @param RepositoryPathInterface $path
184
     * @return ResourceInterface Object resource
185
     */
186
    public function getObjectResource(RepositoryPathInterface $path)
187
    {
188 27
        return $path->getRepository()->getAdapterStrategy()->getObjectResource(
189
            $path->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
190 27
        );
191 27
    }
192 27
193
    /**
194
     * Test whether an object resource exists
195
     *
196
     * @param RepositoryPathInterface $path
197
     * @return boolean Object resource exists
198
     */
199
    public function objectResourceExists(RepositoryPathInterface $path)
200
    {
201
        return $path->getRepository()->getAdapterStrategy()->hasObjectResource(
202
            $path->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
203
        );
204
    }
205
}
206