Completed
Push — master ( 25953d...e2e6d9 )
by Joschi
02:32
created

Service   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 84%

Importance

Changes 6
Bugs 1 Features 0
Metric Value
wmc 20
c 6
b 1
f 0
lcom 1
cbo 5
dl 0
loc 213
ccs 42
cts 50
cp 0.84
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A register() 0 6 1
A get() 0 15 2
A isRegistered() 0 5 2
A getAdapterStrategyFactory() 0 4 1
A getObjectManager() 0 4 1
C normalizeRepositoryUrl() 0 37 7
A useAutoConnect() 0 7 2
A connected() 0 10 3
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 $registry = [];
59
    /**
60
     * Repository auto-connector service
61
     *
62
     * @var AutoConnectorInterface
63
     */
64
    protected $autoConnector = null;
65
    /**
66
     * Adapter strategy factory
67
     *
68
     * @var AdapterStrategyFactoryInterface
69
     */
70
    protected $adapterStrategyFactory = null;
71
    /**
72
     * Object manager
73
     *
74
     * @var ManagerInterface
75
     */
76
    protected $objectManager = null;
77
    /**
78
     * Auto-connect to repositories
79
     *
80
     * @var bool
81
     */
82
    protected $autoConnectEnabled = true;
83
84
    /*******************************************************************************
85
     * PUBLIC METHODS
86
     *******************************************************************************/
87
88
    /**
89
     * Repository service constructor
90
     *
91
     * @param AutoConnectorInterface $autoConnector Auto-connector
92
     * @param AdapterStrategyFactoryInterface $adapterStrategyFactory Adapter strategy factory
93
     * @param ManagerInterface $objectManager Object manager
94
     */
95
    public function __construct(
96
        AutoConnectorInterface $autoConnector,
97
        AdapterStrategyFactoryInterface $adapterStrategyFactory,
98
        ManagerInterface $objectManager
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|Url $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), '/');
0 ignored issues
show
Bug introduced by
It seems like $url defined by parameter $url on line 115 can also be of type object<Apparat\Object\Domain\Model\Path\Url>; however, Apparat\Object\Domain\Re...ormalizeRepositoryUrl() does only seem to accept string|object<Apparat\Ob...n\Model\Path\ObjectUrl>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
119 6
        $this->registry[$repositoryUrl] = $repository;
120 6
    }
121
122
    /**
123
     * Return an object repository by URL
124
     *
125
     * If a repository URL hasn't been pre-registered, the method tries to perform an adhoc registration
126
     * based on the URL given.
127
     * The repository URL may be local or remote, relative or absolute, with Apparat or HTTP scheme.
128
     *
129
     * @param string|Url $url Repository URL
130
     * @return \Apparat\Object\Domain\Repository\Repository Object repository
131
     * @throws InvalidArgumentException If the repository URL is invalid
132
     * @throws InvalidArgumentException If the repository URL is unknown
133
     */
134 9
    public function get($url)
135
    {
136 9
        $url = ltrim(self::normalizeRepositoryUrl($url), '/');
0 ignored issues
show
Bug introduced by
It seems like $url can also be of type object<Apparat\Object\Domain\Model\Path\Url>; however, Apparat\Object\Domain\Re...ormalizeRepositoryUrl() does only seem to accept string|object<Apparat\Ob...n\Model\Path\ObjectUrl>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

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