Completed
Push — master ( 0bd31b...24de6a )
by Joschi
08:36
created

Manager::loadObjectResource()   C

Complexity

Conditions 7
Paths 3

Size

Total Lines 34
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

Changes 4
Bugs 0 Features 1
Metric Value
cc 7
eloc 15
c 4
b 0
f 1
nc 3
nop 2
dl 0
loc 34
ccs 14
cts 14
cp 1
crap 7
rs 6.7272
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
     * @param \DateTimeInterface $creationDate Object creation date
71
     * @return ObjectInterface Object
72
     */
73 5
    public function createObject(
74
        RepositoryInterface $repository,
75
        Type $type,
76
        $payload = '',
77
        array $propertyData = [],
78
        \DateTimeInterface $creationDate = null
79
    ) {
80
        // Set the creation date to now if empty
81 5
        if ($creationDate === null) {
82 3
            $creationDate = new \DateTimeImmutable('now');
83
        }
84
85
        // Construct a creation closure
86 5
        $creationClosure = function (Id $uid) use ($repository, $type, $payload, $propertyData, $creationDate) {
87
            /** @var Revision $revision */
88 4
            $revision = Kernel::create(Revision::class, [1, true]);
89
90
            /** @var RepositoryPath $repositoryPath */
91 4
            $repositoryPath = Kernel::create(RepositoryPath::class, [$repository]);
92 4
            $repositoryPath = $repositoryPath->setId($uid);
93 4
            $repositoryPath = $repositoryPath->setRevision($revision);
94 4
            $repositoryPath = $repositoryPath->setType($type);
95 4
            $repositoryPath = $repositoryPath->setCreationDate($creationDate);
96
97 4
            return ObjectFactory::createFromParams($repositoryPath, $payload, $propertyData);
98 5
        };
99
100
        // Wrap the object creation in an ID allocation transaction
101 5
        return $repository->getAdapterStrategy()->createObjectResource($creationClosure);
102
    }
103
104
    /**
105
     * Load an object from a repository
106
     *
107
     * @param RepositoryPathInterface $path Repository object path
108
     * @param int $visibility Object visibility
109
     * @return ObjectInterface Object
110
     * @throws InvalidArgumentException If the visibility requirement is invalid
111
     */
112 26
    public function loadObject(RepositoryPathInterface $path, $visibility = SelectorInterface::ALL)
113
    {
114
        // Create the current revision path
115
        /** @var RepositoryPathInterface $currentPath */
116 26
        $currentPath = $path->setRevision(Revision::current());
117
118
        // Load the object resource respecting visibility constraints
119 26
        $objectResource = $this->loadObjectResource($currentPath, $visibility);
120
121
        // Instantiate the object
122 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 119 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...
123
124
        // Use and return the requested object revision
125 24
        return $object->useRevision($path->getRevision());
126
    }
127
128
    /**
129
     * Load and return an object resource respecting visibility constraints
130
     *
131
     * @param RepositoryPathInterface $currentPath
132
     * @param int $visibility Object visibility
133
     * @return ResourceInterface Object resource
134
     */
135 27
    public function loadObjectResource(RepositoryPathInterface &$currentPath, $visibility = SelectorInterface::ALL)
136
    {
137
        // Validate the object visibility
138 27
        $this->validateVisibility($visibility);
139
140 26
        $objectResource = null;
141
142
        // Create the current revision paths (visible and hidden)
143
        /** @var RepositoryPathInterface[] $currentPaths */
144 26
        $currentPaths = array_filter([
145 26
            ($visibility & SelectorInterface::VISIBLE) ? $currentPath->setHidden(false) : null,
146 26
            ($visibility & SelectorInterface::HIDDEN) ? $currentPath->setHidden(true) : null,
147
        ]);
148
149
        // Run through the possible revision paths
150 26
        foreach ($currentPaths as $currentPathIndex => $currentPath) {
151
            try {
152
                // Load the current object resource
153 26
                $objectResource = $this->getObjectResource($currentPath);
154 25
                break;
155
156
                // In case of an error
157 3
            } catch (InvalidReaderArgumentException $e) {
158
                // If it's not an error about the resource not existing or if it's the last possible option
159 3
                if (($e->getCode() != InvalidReaderArgumentException::RESOURCE_DOES_NOT_EXIST)
160 3
                    || ($currentPathIndex >= (count($currentPaths) - 1))
161
                ) {
162 3
                    throw $e;
163
                }
164
            }
165
        }
166
167 25
        return $objectResource;
168
    }
169
170
    /**
171
     * Validate a given object visibility
172
     *
173
     * @param int $visibility Object visibility
174
     * @throw InvalidArgumentException If the visibility requirement is invalid
175
     */
176 27
    protected function validateVisibility($visibility)
177
    {
178
        // If the visibility requirement is invalid
179 27
        if (!Selector::isValidVisibility($visibility)) {
180 1
            throw new InvalidArgumentException(
181
                sprintf(
182 1
                    'Invalid repository selector visibility "%s"',
183
                    $visibility
184
                ),
185 1
                InvalidArgumentException::INVALID_REPOSITORY_SELECTOR_COMPONENT,
186 1
                null,
187 1
                'visibility'
188
            );
189
        }
190 26
    }
191
192
    /**
193
     * Instantiate object resource
194
     *
195
     * @param RepositoryPathInterface $path
196
     * @return ResourceInterface Object resource
197
     */
198 26
    public function getObjectResource(RepositoryPathInterface $path)
199
    {
200 26
        return $path->getRepository()->getAdapterStrategy()->getObjectResource(
201 26
            $path->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
202
        );
203
    }
204
205
    /**
206
     * Test whether an object resource exists
207
     *
208
     * @param RepositoryPathInterface $path
209
     * @return boolean Object resource exists
210
     */
211 28
    public function objectResourceExists(RepositoryPathInterface $path)
212
    {
213 28
        return $path->getRepository()->getAdapterStrategy()->hasResource(
214 28
            $path->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
215
        );
216
    }
217
}
218