Completed
Push — master ( e2e6d9...5aa43e )
by Joschi
02:56
created

Service::normalizeRepositoryUrl()   C

Complexity

Conditions 7
Paths 16

Size

Total Lines 36
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7.0119

Importance

Changes 6
Bugs 0 Features 1
Metric Value
c 6
b 0
f 1
dl 0
loc 36
ccs 15
cts 16
cp 0.9375
rs 6.7272
cc 7
eloc 16
nc 16
nop 1
crap 7.0119
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)
0 ignored issues
show
Coding Style introduced by
Spaces must be used for alignment; tabs are not allowed
Loading history...
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\Path\ApparatUrl;
41
use Apparat\Object\Domain\Model\Path\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 $adapterStrategyFactory = 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 $adapterStrategyFactory Adapter strategy factory
92
     * @param ManagerInterface $objectManager Object manager
93
     */
94
    public function __construct(
95
        AutoConnectorInterface $autoConnector,
96
        AdapterStrategyFactoryInterface $adapterStrategyFactory,
97
        ManagerInterface $objectManager
98
    )
0 ignored issues
show
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found newline
Loading history...
99
    {
100
        $this->autoConnector = $autoConnector;
101
        $this->adapterStrategyFactory = $adapterStrategyFactory;
102
        $this->objectManager = $objectManager;
103
    }
104
105
    /**
106
     * Pre-register a repository
107
     *
108
     * The purpose of repository pre-registration is to provide custom arguments (like a base
109
     * directory or basic authentication credentials.
110
     * The repository URL may be local or remote, relative or absolute, with Apparat or HTTP scheme.
111
     *
112
     * @param string|ObjectUrl $url Repository URL
113
     * @param RepositoryInterface $repository Repository
114
     */
115 6
    public function register($url, RepositoryInterface $repository)
116
    {
117
        // Repository registration
118 6
        $repositoryUrl = ltrim(self::normalizeRepositoryUrl($url), '/');
119 6
        $this->registry[$repositoryUrl] = $repository;
120 6
    }
121
122
    /**
123
     * Normalize a repository URL
124
     *
125
     * @param string|ObjectUrl $url Repository URL
126
     * @return string Normalized repository URL
127
     * @throws InvalidArgumentException If the repository URL is invalid
128
     */
129 22
    public static function normalizeRepositoryUrl($url)
130
    {
131
        // If it's an apparat URL
132 22
        if ($url instanceof ApparatUrl) {
133 2
            $url = $url->getNormalizedRepositoryUrl();
134
135
            // Else: If it's an object URL
136
        } elseif ($url instanceof ObjectUrl) {
137 1
            $url = $url->getRepositoryUrl();
138
139
            // Else: If it's an empty URL
140 20
        } elseif ($url === null) {
141 1
            return '';
142
        }
143
144
        // If the URL is a string
145 21
        if (is_string($url)) {
146
147
            // Strip the leading apparat base URL
148 20
            $apparatBaseUrl = getenv('APPARAT_BASE_URL');
149 20
            if (strpos($url, $apparatBaseUrl) === 0) {
150 1
                $url = strval(substr($url, strlen($apparatBaseUrl)));
151
            }
152
153
            // Ensure this is a bare URL (without query and fragment)
154 20
            if (Module::isAbsoluteBareUrl($apparatBaseUrl . $url)) {
155 19
                return $url;
156
            }
157
        }
158
159
        // The URL is invalid, throw an error
160 1
        throw new InvalidArgumentException(
161 1
            sprintf('Invalid repository URL "%s"', $url),
162 1
            InvalidArgumentException::INVALID_REPOSITORY_URL
163
        );
164
    }
165
166
    /**
167
     * Return an object repository by URL
168
     *
169
     * If a repository URL hasn't been pre-registered, the method tries to perform an adhoc registration
170
     * based on the URL given.
171
     * The repository URL may be local or remote, relative or absolute, with Apparat or HTTP scheme.
172
     *
173
     * @param string|ObjectUrl $url Repository URL
174
     * @return \Apparat\Object\Domain\Repository\Repository Object repository
175
     * @throws InvalidArgumentException If the repository URL is invalid
176
     * @throws InvalidArgumentException If the repository URL is unknown
177
     */
178 9
    public function get($url)
179
    {
180 9
        $url = ltrim(self::normalizeRepositoryUrl($url), '/');
181
182
        // If the repository URL is unknown
183 8
        if (!self::connected($url)) {
184 2
            throw new InvalidArgumentException(
185 2
                sprintf('Unknown repository URL "%s"', $url),
186 2
                InvalidArgumentException::UNKNOWN_REPOSITORY_URL
187
            );
188
        }
189
190
        // Return the repository instance
191 6
        return $this->registry[$url];
192
    }
193
194
    /**
195
     * Test whether a repository URL registered or can be auto-connected
196
     *
197
     * @param string $url Repository URL
198
     * @return bool Repository is connected
199
     */
200 9
    protected function connected($url)
201
    {
202
        // If the given repository URL is already registered: Success
203 9
        if (!empty($this->registry[$url])) {
204 6
            return true;
205
        }
206
207
        // If auto-connect is enabled and the service is properly configured: Try to auto-connect the repository
208 3
        return $this->autoConnectEnabled && $this->autoConnector->connect($url);
209
    }
210
211
    /**
212
     * Test whether a repository URL is registered
213
     *
214
     * @param string|ObjectUrl $url Repository URL
215
     * @return bool Repository URL is registered
216
     */
217 4
    public function isRegistered($url)
218
    {
219 4
        $url = ltrim(self::normalizeRepositoryUrl($url), '/');
220 4
        return array_key_exists($url, $this->registry) || self::connected($url);
221
    }
222
223
    /**
224
     * Return the adapter strategy factory
225
     *
226
     * @return AdapterStrategyFactoryInterface Adapter strategy factory
227
     */
228 10
    public function getAdapterStrategyFactory()
229
    {
230 10
        return $this->adapterStrategyFactory;
231
    }
232
233
    /**
234
     * Return the object manager
235
     *
236
     * @return ManagerInterface Object manager
237
     */
238 3
    public function getObjectManager()
239
    {
240 3
        return $this->objectManager;
241
    }
242
243
    /*******************************************************************************
244
     * PRIVATE METHODS
245
     *******************************************************************************/
246
247
    /**
248
     * Enable repository auto-connections
249
     *
250
     * If the method is called without any arguments it will just return the current auto-connection state.
251
     *
252
     * @param null|boolean $autoConnect Enable / disable auto-connections
253
     * @return bool Status of repository auto-connection
254
     */
255 7
    public function useAutoConnect($autoConnect = null)
256
    {
257 7
        if ($autoConnect !== null) {
258 7
            $this->autoConnectEnabled = (boolean)$autoConnect;
259
        }
260 7
        return $this->autoConnectEnabled;
261
    }
262
}
263