Completed
Push — master ( 5aa43e...28467c )
by Joschi
02:48
created

Service::useAutoConnect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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