Completed
Push — master ( ae9dae...0072ad )
by Joschi
02:44
created

Service   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 87.23%

Importance

Changes 9
Bugs 1 Features 2
Metric Value
wmc 20
c 9
b 1
f 2
lcom 1
cbo 5
dl 0
loc 211
ccs 41
cts 47
cp 0.8723
rs 10

9 Methods

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