Manager::getObjectResource()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
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\Uri\RepositoryLocator;
48
use Apparat\Object\Domain\Model\Uri\RepositoryLocatorInterface;
49
use Apparat\Object\Domain\Repository\InvalidArgumentException as RepositoryInvalidArgumentException;
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\Application
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 8
    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 8
        if ($creationDate === null) {
82 5
            $creationDate = new \DateTimeImmutable('now');
83
        }
84
85
        // Construct a creation closure
86 8
        $creationClosure = function (Id $uid) use ($repository, $type, $payload, $propertyData, $creationDate) {
87
            /** @var Revision $revision */
88 7
            $revision = Kernel::create(Revision::class, [1, true]);
89
90
            /** @var RepositoryLocator $repositoryLocator */
91 7
            $repositoryLocator = Kernel::create(RepositoryLocator::class, [$repository]);
92 7
            $repositoryLocator = $repositoryLocator->setId($uid);
93 7
            $repositoryLocator = $repositoryLocator->setRevision($revision);
94 7
            $repositoryLocator = $repositoryLocator->setObjectType($type);
95 7
            $repositoryLocator = $repositoryLocator->setCreationDate($creationDate);
96
97 7
            return ObjectFactory::createFromParams($repositoryLocator, $payload, $propertyData);
0 ignored issues
show
Compatibility introduced by
$repositoryLocator 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...
98 8
        };
99
100
        // Wrap the object creation in an ID allocation transaction
101 8
        return $repository->getAdapterStrategy()->createObjectResource($creationClosure);
102
    }
103
104
    /**
105
     * Load an object from a repository
106
     *
107
     * @param RepositoryLocatorInterface $locator Repository object locator
108
     * @param int $visibility Object visibility
109
     * @return ObjectInterface Object
110
     */
111 42
    public function loadObject(RepositoryLocatorInterface $locator, $visibility = SelectorInterface::ALL)
112
    {
113 42
        $revision = $locator->getRevision();
114 42
        return (($revision->getRevision() == 1) && $revision->isDraft()) ?
115 42
            $this->loadInitialObjectDraft($locator, $visibility) : $this->loadObjectRevision($locator, $visibility);
116
    }
117
118
    /**
119
     * Load a particular object revision from a repository
120
     *
121
     * @param RepositoryLocatorInterface $locator Repository object locator
122
     * @param int $visibility Object visibility
123
     * @return ObjectInterface Object
124
     */
125 1
    protected function loadInitialObjectDraft(RepositoryLocatorInterface $locator, $visibility = SelectorInterface::ALL)
126
    {
127
        // Load the object resource respecting visibility constraints
128 1
        $objectResource = $this->loadObjectResource($locator, $visibility);
129
130
        // Instantiate and return the object
131 1
        return ObjectFactory::createFromResource($locator, $objectResource);
132
    }
133
134
    /**
135
     * Load a particular object revision from a repository
136
     *
137
     * @param RepositoryLocatorInterface $locator Repository object locator
138
     * @param int $visibility Object visibility
139
     * @return ObjectInterface Object
140
     */
141 41
    protected function loadObjectRevision(RepositoryLocatorInterface $locator, $visibility = SelectorInterface::ALL)
142
    {
143
        // Create the current revision locator
144
        /** @var RepositoryLocatorInterface $currentLocator */
145 41
        $currentLocator = $locator->setRevision(Revision::current());
146
147
        // Load the object resource respecting visibility constraints
148 41
        $objectResource = $this->loadObjectResource($currentLocator, $visibility);
149
150
        // Instantiate the object
151 38
        $object = ObjectFactory::createFromResource($currentLocator, $objectResource);
152
153
        // Use and return the requested object revision
154 38
        return $object->useRevision($locator->getRevision());
155
    }
156
157
    /**
158
     * Load and return an object resource respecting visibility constraints
159
     *
160
     * @param RepositoryLocatorInterface $currentLocator
161
     * @param int $visibility Object visibility
162
     * @return ResourceInterface Object resource
163
     * @throws InvalidArgumentException If the resource could not be loaded
164
     */
165 43
    public function loadObjectResource(
166
        RepositoryLocatorInterface &$currentLocator,
167
        $visibility = SelectorInterface::ALL
168
    ) {
169
        // Validate the object visibility
170 43
        $this->validateVisibility($visibility);
171
172 42
        $objectResource = null;
173
174
        // Create the current revision locators (visible and hidden)
175
        /** @var RepositoryLocatorInterface[] $currentLocators */
176 42
        $currentLocators = array_filter([
177 42
            ($visibility & SelectorInterface::VISIBLE) ? $currentLocator->setHidden(false) : null,
178 42
            ($visibility & SelectorInterface::HIDDEN) ? $currentLocator->setHidden(true) : null,
179
        ]);
180
181
        // Run through the possible revision locators
182 42
        foreach ($currentLocators as $currentLocatorIndex => $currentLocator) {
183
            try {
184
                // Load the current object resource
185 42
                $objectResource = $this->getObjectResource($currentLocator);
186 41
                break;
187
188
                // In case of an error
189 3
            } catch (InvalidReaderArgumentException $e) {
190
                // If it's not an error about the resource not existing or if it's the last possible option
191 3
                if (($e->getCode() != InvalidReaderArgumentException::RESOURCE_DOES_NOT_EXIST)
192 3
                    || ($currentLocatorIndex >= (count($currentLocators) - 1))
193
                ) {
194 3
                    throw $e;
195
                }
196
            }
197
        }
198
199
        // If the resource could not be loaded
200 41
        if (!($objectResource instanceof ResourceInterface)) {
201 1
            throw new InvalidArgumentException(
202 1
                'Resource could not be loaded',
203 1
                InvalidArgumentException::RESOURCE_NOT_LOADED
204
            );
205
        }
206
207 40
        return $objectResource;
208
    }
209
210
    /**
211
     * Validate a given object visibility
212
     *
213
     * @param int $visibility Object visibility
214
     * @throw RepositoryInvalidArgumentException If the visibility requirement is invalid
215
     */
216 43
    protected function validateVisibility($visibility)
217
    {
218
        // If the visibility requirement is invalid
219 43
        if (!Selector::isValidVisibility($visibility)) {
220 1
            throw new RepositoryInvalidArgumentException(
221
                sprintf(
222 1
                    'Invalid repository selector visibility "%s"',
223
                    $visibility
224
                ),
225 1
                RepositoryInvalidArgumentException::INVALID_REPOSITORY_SELECTOR_COMPONENT,
226 1
                null,
227 1
                'visibility'
228
            );
229
        }
230 42
    }
231
232
    /**
233
     * Instantiate object resource
234
     *
235
     * @param RepositoryLocatorInterface $locator
236
     * @return ResourceInterface Object resource
237
     */
238 42
    public function getObjectResource(RepositoryLocatorInterface $locator)
239
    {
240 42
        return $locator->getRepository()->getAdapterStrategy()->getObjectResource(
241 42
            $locator->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
242
        );
243
    }
244
245
    /**
246
     * Test whether an object resource exists
247
     *
248
     * @param RepositoryLocatorInterface $locator
249
     * @return boolean Object resource exists
250
     */
251 45
    public function objectResourceExists(RepositoryLocatorInterface $locator)
252
    {
253 45
        return $locator->getRepository()->getAdapterStrategy()->hasResource(
254 45
            $locator->withExtension(getenv('OBJECT_RESOURCE_EXTENSION'))
255
        );
256
    }
257
}
258