Completed
Push — master ( 108e84...f077fb )
by Joschi
08:25
created

Service::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
ccs 0
cts 5
cp 0
rs 9.6666
cc 1
eloc 7
nc 1
nop 3
crap 2
1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Domain
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\Domain\Repository;
38
39
use Apparat\Object\Domain\Model\Object\ManagerInterface;
40
use Apparat\Object\Domain\Model\Uri\ApparatUrl;
41
use Apparat\Object\Domain\Model\Uri\ObjectUrl;
42
use Apparat\Object\Module;
43
44
/**
45
 * Repository register
46
 *
47
 * @package Apparat\Object
48
 * @subpackage Apparat\Object\Domain
49
 */
50
class Service
51
{
52
    /**
53
     * Registered repositories
54
     *
55
     * @var array
56
     */
57
    protected $registry = [];
58
    /**
59
     * Repository auto-connector service
60
     *
61
     * @var AutoConnectorInterface
62
     */
63
    protected $autoConnector = null;
64
    /**
65
     * Adapter strategy factory
66
     *
67
     * @var AdapterStrategyFactoryInterface
68
     */
69
    protected $adptStrategyFactory = null;
70
    /**
71
     * Object manager
72
     *
73
     * @var ManagerInterface
74
     */
75
    protected $objectManager = null;
76
    /**
77
     * Auto-connect to repositories
78
     *
79
     * @var bool
80
     */
81
    protected $autoConnectEnabled = true;
82
83
    /*******************************************************************************
84
     * PUBLIC METHODS
85
     *******************************************************************************/
86
87
    /**
88
     * Repository service constructor
89
     *
90
     * @param AutoConnectorInterface $autoConnector Auto-connector
91
     * @param AdapterStrategyFactoryInterface $adptStrategyFactory Adapter strategy factory
92
     * @param ManagerInterface $objectManager Object manager
93
     */
94
    public function __construct(
95
        AutoConnectorInterface $autoConnector,
96
        AdapterStrategyFactoryInterface $adptStrategyFactory,
97
        ManagerInterface $objectManager
98
    ) {
99
        $this->autoConnector = $autoConnector;
100
        $this->adptStrategyFactory = $adptStrategyFactory;
101
        $this->objectManager = $objectManager;
102
    }
103
104
    /**
105
     * Reset the repository service
106
     *
107
     * @return Service Self reference
108
     */
109 3
    public function reset()
110
    {
111 3
        $this->registry = [];
112 3
        return $this;
113
    }
114
115
    /**
116
     * Pre-register a repository
117
     *
118
     * The purpose of repository pre-registration is to provide custom arguments (like a base
119
     * directory or basic authentication credentials.
120
     * The repository URL may be local or remote, relative or absolute, with Apparat or HTTP scheme.
121
     *
122
     * @param string|ObjectUrl $url Repository URL
123
     * @param RepositoryInterface $repository Repository
124
     */
125 18
    public function register($url, RepositoryInterface $repository)
126
    {
127
        // Repository registration
128 18
        $repositoryUrl = ltrim(self::normalizeRepositoryUrl($url), '/');
129 18
        $this->registry[$repositoryUrl] = $repository;
130 18
    }
131
132
    /**
133
     * Normalize a repository URL
134
     *
135
     * @param string|ObjectUrl $url Repository URL
136
     * @return string Normalized repository URL
137
     * @throws InvalidArgumentException If the repository URL is invalid
138
     */
139 69
    public static function normalizeRepositoryUrl($url)
140
    {
141
        // If it's an apparat URL
142 69
        if ($url instanceof ApparatUrl) {
143 3
            $url = $url->getNormalizedRepositoryUrl();
144
145
            // Else: If it's an object URL
146
        } elseif ($url instanceof ObjectUrl) {
147 1
            $url = $url->getRepositoryUrl();
148
149
            // Else: If it's an empty URL
150 67
        } elseif ($url === null) {
151 3
            return '';
152
        }
153
154
        // If the URL is a string
155 68
        if (is_string($url)) {
156
            // Strip the leading apparat base URL
157 67
            $apparatBaseUrl = getenv('APPARAT_BASE_URL');
158 67
            if (strpos($url, $apparatBaseUrl) === 0) {
159 1
                $url = strval(substr($url, strlen($apparatBaseUrl)));
160
            }
161
162
            // Ensure this is a bare URL (without query and fragment)
163 67
            if (Module::isAbsoluteBareUrl($apparatBaseUrl.$url)) {
164 66
                return $url;
165
            }
166
        }
167
168
        // The URL is invalid, throw an error
169 1
        throw new InvalidArgumentException(
170 1
            sprintf('Invalid repository URL "%s"', $url),
171 1
            InvalidArgumentException::INVALID_REPOSITORY_URL
172
        );
173
    }
174
175
    /**
176
     * Return an object repository by URL
177
     *
178
     * If a repository URL has not been pre-registered, the method tries to perform an ad-hoc registration
179
     * based on the URL given.
180
     * The repository URL may be local or remote, relative or absolute, with Apparat or HTTP scheme.
181
     *
182
     * @param string|ObjectUrl $url Repository URL
183
     * @return \Apparat\Object\Domain\Repository\Repository Object repository
184
     * @throws InvalidArgumentException If the repository URL is invalid
185
     * @throws InvalidArgumentException If the repository URL is unknown
186
     */
187 36
    public function get($url)
188
    {
189 36
        $url = ltrim(self::normalizeRepositoryUrl($url), '/');
190
191
        // If the repository URL is unknown
192 35
        if (!self::connected($url)) {
193 2
            throw new InvalidArgumentException(
194 2
                sprintf('Unknown repository URL "%s"', $url),
195 2
                InvalidArgumentException::UNKNOWN_REPOSITORY_URL
196
            );
197
        }
198
199
        // Return the repository instance
200 33
        return $this->registry[$url];
201
    }
202
203
    /**
204
     * Test whether a repository URL registered or can be auto-connected
205
     *
206
     * @param string $url Repository URL
207
     * @return bool Repository is connected
208
     */
209 36
    protected function connected($url)
210
    {
211
        // If the given repository URL is already registered: Success
212 36
        if (!empty($this->registry[$url])) {
213 31
            return true;
214
        }
215
216
        // If auto-connect is enabled: Try to auto-connect the requested repository
217 5
        return $this->autoConnectEnabled && $this->autoConnector->connect($url);
218
    }
219
220
    /**
221
     * Test whether a repository URL is registered
222
     *
223
     * @param string|ObjectUrl $url Repository URL
224
     * @return bool Repository URL is registered
225
     */
226 37
    public function isRegistered($url)
227
    {
228 37
        $url = ltrim(self::normalizeRepositoryUrl($url), '/');
229 37
        return array_key_exists($url, $this->registry) || self::connected($url);
230
    }
231
232
    /**
233
     * Return the adapter strategy factory
234
     *
235
     * @return AdapterStrategyFactoryInterface Adapter strategy factory
236
     */
237 24
    public function getAdapterStrategyFactory()
238
    {
239 24
        return $this->adptStrategyFactory;
240
    }
241
242
    /**
243
     * Return the object manager
244
     *
245
     * @return ManagerInterface Object manager
246
     */
247 49
    public function getObjectManager()
248
    {
249 49
        return $this->objectManager;
250
    }
251
252
    /*******************************************************************************
253
     * PRIVATE METHODS
254
     *******************************************************************************/
255
256
    /**
257
     * Enable repository auto-connections
258
     *
259
     * If the method is called without any arguments it will just return the current auto-connection state.
260
     *
261
     * @param null|boolean $autoConnect Enable / disable auto-connections
262
     * @return bool Status of repository auto-connection
263
     */
264 23
    public function useAutoConnect($autoConnect = null)
265
    {
266 23
        if ($autoConnect !== null) {
267 23
            $this->autoConnectEnabled = (boolean)$autoConnect;
268
        }
269 23
        return $this->autoConnectEnabled;
270
    }
271
}
272