Passed
Push — master ( 8eafb5...9551a9 )
by Thierry
02:09
created

Registry::getClassOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Registry.php - Jaxon callable class registry
5
 *
6
 * This class is the entry point for class, directory and namespace registration.
7
 *
8
 * @package jaxon-core
0 ignored issues
show
Coding Style introduced by
Package name "jaxon-core" is not valid; consider "Jaxoncore" instead
Loading history...
9
 * @author Thierry Feuzeu <[email protected]>
10
 * @copyright 2019 Thierry Feuzeu <[email protected]>
11
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
12
 * @link https://github.com/jaxon-php/jaxon-core
13
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
14
15
namespace Jaxon\Request\Plugin\CallableClass;
16
17
use Jaxon\Container\Container;
18
use Jaxon\Request\Factory\RequestFactory;
19
use Jaxon\Exception\SetupException;
20
21
use Composer\Autoload\ClassLoader;
22
23
use function file_exists;
24
use function in_array;
25
use function str_replace;
26
use function strlen;
27
use function strncmp;
28
use function trim;
29
30
class Registry
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class Registry
Loading history...
31
{
32
    /**
33
     * The DI container
34
     *
35
     * @var Container
36
     */
37
    protected $di;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
38
39
    /**
40
     * The callable repository
41
     *
42
     * @var Repository
43
     */
44
    public $xRepository;
45
46
    /**
47
     * The registered directories
48
     *
49
     * These are directories registered without a namespace.
50
     *
51
     * @var array
52
     */
53
    protected $aDirectories = [];
54
55
    /**
56
     * The registered namespaces
57
     *
58
     * These are the namespaces specified when registering directories.
59
     *
60
     * @var array
61
     */
62
    protected $aNamespaces = [];
63
64
    /**
65
     * If the underscore is used as separator in js class names.
66
     *
67
     * @var bool
0 ignored issues
show
Bug introduced by
Expected "boolean" but found "bool" for @var tag in member variable comment
Loading history...
68
     */
69
    protected $bUsingUnderscore = false;
70
71
    /**
72
     * The Composer autoloader
73
     *
74
     * @var ClassLoader
75
     */
76
    private $xAutoloader = null;
77
78
    /**
79
     * The class constructor
80
     *
81
     * @param Container $di
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
82
     * @param Repository $xRepository
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
83
     */
84
    public function __construct(Container $di, Repository $xRepository)
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
85
    {
86
        $this->di = $di;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
87
        $this->xRepository = $xRepository;
88
89
        // Set the composer autoloader
90
        $sAutoloadFile = __DIR__ . '/../../../../../../autoload.php';
91
        if(file_exists($sAutoloadFile))
92
        {
93
            $this->xAutoloader = require($sAutoloadFile);
94
        }
95
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
96
97
    /**
98
     *
99
     * @param string $sDirectory    The directory being registered
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
100
     * @param array $aOptions    The associated options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
101
     *
102
     * @return void
103
     */
104
    public function addDirectory(string $sDirectory, array $aOptions)
105
    {
106
        // Set the autoload option default value
107
        if(!isset($aOptions['autoload']))
108
        {
109
            $aOptions['autoload'] = true;
110
        }
111
112
        $this->aDirectories[$sDirectory] = $aOptions;
113
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
114
115
    /**
116
     *
117
     * @param string $sNamespace    The namespace of the directory being registered
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
118
     * @param array $aOptions    The associated options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
119
     *
120
     * @return void
121
     */
122
    public function addNamespace(string $sNamespace, array $aOptions)
123
    {
124
        // Separator default value
125
        if(!isset($aOptions['separator']))
126
        {
127
            $aOptions['separator'] = '.';
128
        }
129
        $aOptions['separator'] = trim($aOptions['separator']);
130
        if(!in_array($aOptions['separator'], ['.', '_']))
131
        {
132
            $aOptions['separator'] = '.';
133
        }
134
        if($aOptions['separator'] === '_')
135
        {
136
            $this->bUsingUnderscore = true;
137
        }
138
        // Set the autoload option default value
139
        if(!isset($aOptions['autoload']))
140
        {
141
            $aOptions['autoload'] = true;
142
        }
143
        // Register the dir with PSR4 autoloading
144
        if(($aOptions['autoload']) && $this->xAutoloader != null)
145
        {
146
            $this->xAutoloader->setPsr4($sNamespace . '\\', $aOptions['directory']);
147
        }
148
149
        $this->aNamespaces[$sNamespace] = $aOptions;
150
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
151
152
    /**
153
     * Find options for a class which is registered with namespace
154
     *
155
     * @param string $sClassName    The class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
156
     *
157
     * @return array|null
158
     */
159
    protected function getClassOptionsFromNamespaces(string $sClassName): ?array
160
    {
161
        // Find the corresponding namespace
162
        $sNamespace = null;
163
        $aOptions = null;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
164
        foreach($this->aNamespaces as $_sNamespace => $_aOptions)
165
        {
166
            // Check if the namespace matches the class.
167
            if(strncmp($sClassName, $_sNamespace . '\\', strlen($_sNamespace) + 1) === 0)
168
            {
169
                $sNamespace = $_sNamespace;
170
                $aOptions = $_aOptions;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
171
                break;
172
            }
173
        }
174
        if($sNamespace === null)
175
        {
176
            return null; // Class not registered
177
        }
178
179
        // Get the class options
180
        $aClassOptions = ['namespace' => $sNamespace];
181
        return $this->xRepository->makeClassOptions($sClassName, $aClassOptions, $aOptions);
182
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
183
184
    /**
185
     * Find the options associated with a registered class name
186
     *
187
     * @param string $sClassName    The class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
188
     *
189
     * @return array|null
190
     */
191
    protected function getClassOptions(string $sClassName): ?array
192
    {
193
        // Find options for a class registered with namespace.
194
        $aOptions = $this->getClassOptionsFromNamespaces($sClassName);
195
        if($aOptions !== null)
196
        {
197
            return $aOptions;
198
        }
199
200
        // Without a namespace, we need to parse all classes to be able to find one.
201
        $this->xRepository->parseDirectories($this->aDirectories);
202
203
        // Find options for a class registered without namespace.
204
        return $this->xRepository->getClassOptions($sClassName);
205
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
206
207
    /**
208
     * Check if a callable object is already in the DI, and register if not
209
     *
210
     * @param string $sClassName The class name of the callable object
211
     *
212
     * @return string
213
     * @throws SetupException
214
     */
215
    private function checkCallableObject(string $sClassName): string
216
    {
217
        // Replace all separators ('.' and '_') with antislashes, and remove the antislashes
218
        // at the beginning and the end of the class name.
219
        $sSeparator = $this->bUsingUnderscore ? '_' : '.';
220
        $sClassName = trim(str_replace($sSeparator, '\\', $sClassName), '\\');
221
222
        // Check if the callable object was already created.
223
        if(!$this->di->h($sClassName))
224
        {
225
            $aOptions = $this->getClassOptions($sClassName);
226
            if($aOptions === null)
227
            {
228
                return '';
229
            }
230
            $this->xRepository->registerCallableClass($sClassName, $aOptions);
231
        }
232
        return $sClassName;
233
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
234
235
    /**
236
     * Get the callable object for a given class
237
     *
238
     * @param string $sClassName The class name of the callable object
239
     *
240
     * @return CallableObject|null
241
     * @throws SetupException
242
     */
243
    public function getCallableObject(string $sClassName): ?CallableObject
244
    {
245
        return $this->di->getCallableObject($this->checkCallableObject($sClassName));
246
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
247
248
    /**
249
     * Get the request factory for a given class
250
     *
251
     * @param string $sClassName The class name of the callable object
252
     *
253
     * @return RequestFactory|null
254
     * @throws SetupException
255
     */
256
    public function getRequestFactory(string $sClassName): ?RequestFactory
257
    {
258
        return $this->di->getRequestFactory($this->checkCallableObject($sClassName));
259
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
260
261
    /**
262
     * Register all the callable classes
263
     *
264
     * @return void
265
     */
266
    public function parseCallableClasses()
267
    {
268
        $this->xRepository->parseDirectories($this->aDirectories);
269
        $this->xRepository->parseNamespaces($this->aNamespaces);
270
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
271
272
    /**
273
     * Create callable objects for all registered classes
274
     *
275
     * @return void
276
     * @throws SetupException
277
     */
278
    public function registerCallableClasses()
279
    {
280
        $this->parseCallableClasses();
281
282
        $aClasses = $this->xRepository->getClasses();
283
        foreach($aClasses as $sClassName => $aClassOptions)
284
        {
285
            // Make sure we create each callable object only once.
286
            if(!$this->di->h($sClassName))
287
            {
288
                $this->xRepository->registerCallableClass($sClassName, $aClassOptions);
289
            }
290
        }
291
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
292
}
293