Passed
Push — feature/code_improvement ( 07c142...134f8a )
by Thierry
20:35 queued 17:14
created

CallableRegistry::_makeClassOptions()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 16
nop 3
dl 0
loc 22
rs 9.2568
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * CallableRegistry.php - Jaxon callable object registrar
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\Support;
16
17
use RecursiveDirectoryIterator;
18
use RecursiveIteratorIterator;
19
20
class CallableRegistry
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CallableRegistry
Loading history...
21
{
22
    /**
23
     * The callable repository
24
     *
25
     * @var CallableRepository
26
     */
27
    public $xRepository;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
28
29
    /**
30
     * The registered classes
31
     *
32
     * These are registered classes, and classes in directories registered without a namespace.
33
     *
34
     * @var array
35
     */
36
    protected $aClasses = [];
37
38
    /**
39
     * The registered directories
40
     *
41
     * These are directories registered without a namespace.
42
     *
43
     * @var array
44
     */
45
    protected $aDirectories = [];
46
47
    /**
48
     * Indicate if the registered directories are already parsed
49
     *
50
     * @var array
51
     */
52
    protected $bParsedDirectories = false;
53
54
    /**
55
     * The registered namespaces
56
     *
57
     * These are the namespaces specified when registering directories.
58
     *
59
     * @var array
60
     */
61
    protected $aNamespaces = [];
62
63
    /**
64
     * Indicate if the registered namespaces are already parsed
65
     *
66
     * @var array
67
     */
68
    protected $bParsedNamespaces = false;
69
70
    /**
71
     * If the underscore is used as separator in js class names.
72
     *
73
     * @var boolean
74
     */
75
    public $bUsingUnderscore = false;
76
77
    /**
78
     * The Composer autoloader
79
     *
80
     * @var Autoloader
81
     */
82
    private $xAutoloader = null;
83
84
    /**
85
     * The class constructor
86
     *
87
     * @param CallableRepository        $xRepository
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter type; 8 found
Loading history...
88
     */
89
    public function __construct(CallableRepository $xRepository)
90
    {
91
        $this->xRepository = $xRepository;
92
93
        // Set the composer autoloader
94
        $sAutoloadFile = __DIR__ . '/../../../../../autoload.php';
95
        if(file_exists($sAutoloadFile))
96
        {
97
            $this->xAutoloader = require($sAutoloadFile);
98
        }
99
    }
100
101
    /**
102
     *
103
     * @param string        $sClassName     The name of the class being registered
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
104
     * @param array|string  $aOptions       The associated options
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 2 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
105
     *
106
     * @return void
107
     */
108
    public function addClass($sClassName, $aOptions)
109
    {
110
        $sClassName = trim($sClassName, '\\ ');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 18 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...
Coding Style introduced by
Consider using a different name than the parameter $sClassName. This often makes code more readable.
Loading history...
111
        $this->aClasses[$sClassName] = $aOptions;
112
    }
113
114
    /**
115
     *
116
     * @param string        $sDirectory     The directory being registered
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
117
     * @param array         $aOptions       The associated options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 9 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
118
     *
119
     * @return void
120
     */
121
    public function addDirectory($sDirectory, array $aOptions)
122
    {
123
        // Set the autoload option default value
124
        if(!key_exists('autoload', $aOptions))
125
        {
126
            $aOptions['autoload'] = true;
127
        }
128
129
        $this->aDirectories[$sDirectory] = $aOptions;
130
    }
131
132
    /**
133
     *
134
     * @param string        $sNamespace     The namespace of the directory being registered
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
135
     * @param array         $aOptions       The associated options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 9 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
136
     *
137
     * @return void
138
     */
139
    public function addNamespace($sNamespace, array $aOptions)
140
    {
141
        // Separator default value
142
        if(!key_exists('separator', $aOptions))
143
        {
144
            $aOptions['separator'] = '.';
145
        }
146
        $aOptions['separator'] = trim($aOptions['separator']);
147
        if(!in_array($aOptions['separator'], ['.', '_']))
148
        {
149
            $aOptions['separator'] = '.';
150
        }
151
        if($aOptions['separator'] == '_')
152
        {
153
            $this->bUsingUnderscore = true;
154
        }
155
        // Set the autoload option default value
156
        if(!key_exists('autoload', $aOptions))
157
        {
158
            $aOptions['autoload'] = true;
159
        }
160
        // Register the dir with PSR4 autoloading
161
        if(($aOptions['autoload']) && $this->xAutoloader != null)
162
        {
163
            $this->xAutoloader->setPsr4($sNamespace . '\\', $aOptions['directory']);
164
        }
165
166
        $this->aNamespaces[$sNamespace] = $aOptions;
167
    }
168
169
    /**
170
     * Get a given class options from specified directory options
171
     *
172
     * @param string        $sClassName         The name of the class
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 8 spaces after parameter name; 9 found
Loading history...
173
     * @param array         $aDirectoryOptions  The directory options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 9 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
174
     * @param array         $aDefaultOptions    The default options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 9 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
175
     *
176
     * @return array
177
     */
178
    private function _makeClassOptions($sClassName, array $aDirectoryOptions, array $aDefaultOptions = [])
179
    {
180
        $aOptions = $aDefaultOptions;
181
        if(key_exists('separator', $aDirectoryOptions))
182
        {
183
            $aOptions['separator'] = $aDirectoryOptions['separator'];
184
        }
185
        if(key_exists('protected', $aDirectoryOptions))
186
        {
187
            $aOptions['protected'] = $aDirectoryOptions['protected'];
188
        }
189
        if(key_exists('*', $aDirectoryOptions))
190
        {
191
            $aOptions = array_merge($aOptions, $aDirectoryOptions['*']);
192
        }
193
        if(key_exists($sClassName, $aDirectoryOptions))
194
        {
195
            $aOptions = array_merge($aOptions, $aDirectoryOptions[$sClassName]);
196
        }
197
198
        return $aOptions;
199
    }
200
201
    /**
202
     * Read classes from registered directories (without namespaces)
203
     *
204
     * @return void
205
     */
206
    public function parseDirectories()
207
    {
208
        // Browse directories without namespaces and read all the files.
209
        // This is to be done only once.
210
        if($this->bParsedDirectories)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->bParsedDirectories of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
211
        {
212
            return;
213
        }
214
        $this->bParsedDirectories = true;
0 ignored issues
show
Documentation Bug introduced by
It seems like true of type boolean is incompatible with the declared type array of property $bParsedDirectories.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
215
216
        foreach($this->aClasses as $sClassName => $aClassOptions)
217
        {
218
            $this->xRepository->addClass($sClassName, $aClassOptions);
219
        }
220
221
        foreach($this->aDirectories as $sDirectory => $aOptions)
222
        {
223
            $itDir = new RecursiveDirectoryIterator($sDirectory);
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 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...
224
            $itFile = new RecursiveIteratorIterator($itDir);
225
            // Iterate on dir content
226
            foreach($itFile as $xFile)
227
            {
228
                // skip everything except PHP files
229
                if(!$xFile->isFile() || $xFile->getExtension() != 'php')
230
                {
231
                    continue;
232
                }
233
234
                $sClassName = $xFile->getBasename('.php');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 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...
235
                $aClassOptions = [];
236
                // No more classmap autoloading. The file will be included when needed.
237
                if(($aOptions['autoload']))
238
                {
239
                    $aClassOptions['include'] = $xFile->getPathname();
240
                }
241
                $aClassOptions = $this->_makeClassOptions($sClassName, $aOptions, $aClassOptions);
242
                $this->xRepository->addClass($sClassName, $aClassOptions);
243
            }
244
        }
245
    }
246
247
    /**
248
     * Read classes from registered directories (with namespaces)
249
     *
250
     * @return void
251
     */
252
    public function parseNamespaces()
253
    {
254
        // Browse directories with namespaces and read all the files.
255
        // This is to be done only once.
256
        if($this->bParsedNamespaces)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->bParsedNamespaces of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
257
        {
258
            return;
259
        }
260
        $this->bParsedNamespaces = true;
0 ignored issues
show
Documentation Bug introduced by
It seems like true of type boolean is incompatible with the declared type array of property $bParsedNamespaces.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
261
262
        $sDS = DIRECTORY_SEPARATOR;
263
        foreach($this->aNamespaces as $sNamespace => $aOptions)
264
        {
265
            $this->xRepository->addNamespace($sNamespace, ['separator' => $aOptions['separator']]);
266
267
            // Iterate on dir content
268
            $sDirectory = $aOptions['directory'];
269
            $itDir = new RecursiveDirectoryIterator($sDirectory);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 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...
270
            $itFile = new RecursiveIteratorIterator($itDir);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 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...
271
            foreach($itFile as $xFile)
272
            {
273
                // skip everything except PHP files
274
                if(!$xFile->isFile() || $xFile->getExtension() != 'php')
275
                {
276
                    continue;
277
                }
278
279
                // Find the class path (the same as the class namespace)
280
                $sClassPath = $sNamespace;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 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...
281
                $sRelativePath = substr($xFile->getPath(), strlen($sDirectory));
282
                $sRelativePath = trim(str_replace($sDS, '\\', $sRelativePath), '\\');
283
                if($sRelativePath != '')
284
                {
285
                    $sClassPath .= '\\' . $sRelativePath;
286
                }
287
288
                $this->xRepository->addNamespace($sClassPath, ['separator' => $aOptions['separator']]);
289
290
                $sClassName = $sClassPath . '\\' . $xFile->getBasename('.php');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 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...
291
                $aClassOptions = ['namespace' => $sNamespace];
292
                $aClassOptions = $this->_makeClassOptions($sClassName, $aOptions, $aClassOptions);
293
                $this->xRepository->addClass($sClassName, $aClassOptions);
294
            }
295
        }
296
    }
297
298
    /**
299
     * Find options for a class which is registered with namespace
300
     *
301
     * @param string        $sClassName            The class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 12 found
Loading history...
302
     *
303
     * @return array|null
304
     */
305
    public function getClassOptions($sClassName)
306
    {
307
        // Find the corresponding namespace
308
        $sNamespace = null;
309
        foreach(array_keys($this->aNamespaces) as $_sNamespace)
310
        {
311
            if(substr($sClassName, 0, strlen($_sNamespace) + 1) == $_sNamespace . '\\')
312
            {
313
                $sNamespace = $_sNamespace;
314
                break;
315
            }
316
        }
317
        if($sNamespace === null)
318
        {
319
            return null; // Class not registered
320
        }
321
322
        // Get the class options
323
        $aOptions = $this->aNamespaces[$sNamespace];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 8 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...
324
        $aDefaultOptions = ['namespace' => $sNamespace];
325
        return $this->_makeClassOptions($sClassName, $aOptions, $aDefaultOptions);
326
    }
327
}
328