Completed
Push — master ( 4b418f...791c35 )
by Joschi
02:31
created

Service::connected()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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