Passed
Push — master ( 68b778...1b1614 )
by Thierry
07:15 queued 04:29
created

CallableRegistry::getClassOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 14
rs 10
cc 2
nc 2
nop 1
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 directories
31
     *
32
     * These are directories registered without a namespace.
33
     *
34
     * @var array
35
     */
36
    protected $aDirectories = [];
37
38
    /**
39
     * Indicate if the registered directories are already parsed
40
     *
41
     * @var boolean
42
     */
43
    protected $bParsedDirectories = false;
44
45
    /**
46
     * The registered namespaces
47
     *
48
     * These are the namespaces specified when registering directories.
49
     *
50
     * @var array
51
     */
52
    protected $aNamespaces = [];
53
54
    /**
55
     * Indicate if the registered namespaces are already parsed
56
     *
57
     * @var boolean
58
     */
59
    protected $bParsedNamespaces = false;
60
61
    /**
62
     * If the underscore is used as separator in js class names.
63
     *
64
     * @var boolean
65
     */
66
    protected $bUsingUnderscore = false;
67
68
    /**
69
     * The Composer autoloader
70
     *
71
     * @var Autoloader
0 ignored issues
show
Bug introduced by
The type Jaxon\Request\Support\Autoloader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
72
     */
73
    private $xAutoloader = null;
74
75
    /**
76
     * The class constructor
77
     *
78
     * @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...
79
     */
80
    public function __construct(CallableRepository $xRepository)
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
81
    {
82
        $this->xRepository = $xRepository;
83
84
        // Set the composer autoloader
85
        $sAutoloadFile = __DIR__ . '/../../../../../autoload.php';
86
        if(file_exists($sAutoloadFile))
87
        {
88
            $this->xAutoloader = require($sAutoloadFile);
89
        }
90
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
91
92
    /**
93
     *
94
     * @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...
95
     * @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...
96
     *
97
     * @return void
98
     */
99
    public function addDirectory($sDirectory, array $aOptions)
100
    {
101
        // Set the autoload option default value
102
        if(!key_exists('autoload', $aOptions))
103
        {
104
            $aOptions['autoload'] = true;
105
        }
106
107
        $this->aDirectories[$sDirectory] = $aOptions;
108
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
109
110
    /**
111
     *
112
     * @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...
113
     * @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...
114
     *
115
     * @return void
116
     */
117
    public function addNamespace($sNamespace, array $aOptions)
118
    {
119
        // Separator default value
120
        if(!key_exists('separator', $aOptions))
121
        {
122
            $aOptions['separator'] = '.';
123
        }
124
        $aOptions['separator'] = trim($aOptions['separator']);
125
        if(!in_array($aOptions['separator'], ['.', '_']))
126
        {
127
            $aOptions['separator'] = '.';
128
        }
129
        if($aOptions['separator'] == '_')
130
        {
131
            $this->bUsingUnderscore = true;
132
        }
133
        // Set the autoload option default value
134
        if(!key_exists('autoload', $aOptions))
135
        {
136
            $aOptions['autoload'] = true;
137
        }
138
        // Register the dir with PSR4 autoloading
139
        if(($aOptions['autoload']) && $this->xAutoloader != null)
140
        {
141
            $this->xAutoloader->setPsr4($sNamespace . '\\', $aOptions['directory']);
142
        }
143
144
        $this->aNamespaces[$sNamespace] = $aOptions;
145
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
146
147
    /**
148
     * Read classes from registered directories (without namespaces)
149
     *
150
     * @return void
151
     */
152
    protected function parseDirectories()
153
    {
154
        // Browse directories without namespaces and read all the files.
155
        // This is to be done only once.
156
        if($this->bParsedDirectories)
157
        {
158
            return;
159
        }
160
        $this->bParsedDirectories = true;
161
162
        foreach($this->aDirectories as $sDirectory => $aOptions)
163
        {
164
            $itFile = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($sDirectory));
165
            // Iterate on dir content
166
            foreach($itFile as $xFile)
167
            {
168
                // skip everything except PHP files
169
                if(!$xFile->isFile() || $xFile->getExtension() != 'php')
170
                {
171
                    continue;
172
                }
173
174
                $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...
175
                $aClassOptions = ['timestamp' => $xFile->getMTime()];
176
                // No more classmap autoloading. The file will be included when needed.
177
                if(($aOptions['autoload']))
178
                {
179
                    $aClassOptions['include'] = $xFile->getPathname();
180
                }
181
                $this->xRepository->addClass($sClassName, $aClassOptions, $aOptions);
182
            }
183
        }
184
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
185
186
    /**
187
     * Read classes from registered directories (with namespaces)
188
     *
189
     * @return void
190
     */
191
    protected function parseNamespaces()
192
    {
193
        // Browse directories with namespaces and read all the files.
194
        // This is to be done only once.
195
        if($this->bParsedNamespaces)
196
        {
197
            return;
198
        }
199
        $this->bParsedNamespaces = true;
200
201
        $sDS = DIRECTORY_SEPARATOR;
202
        foreach($this->aNamespaces as $sNamespace => $aOptions)
203
        {
204
            $this->xRepository->addNamespace($sNamespace, ['separator' => $aOptions['separator']]);
205
206
            // Iterate on dir content
207
            $sDirectory = $aOptions['directory'];
208
            $itFile = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($sDirectory));
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...
209
            foreach($itFile as $xFile)
210
            {
211
                // skip everything except PHP files
212
                if(!$xFile->isFile() || $xFile->getExtension() != 'php')
213
                {
214
                    continue;
215
                }
216
217
                // Find the class path (the same as the class namespace)
218
                $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...
219
                $sRelativePath = substr($xFile->getPath(), strlen($sDirectory));
220
                $sRelativePath = trim(str_replace($sDS, '\\', $sRelativePath), '\\');
221
                if($sRelativePath != '')
222
                {
223
                    $sClassPath .= '\\' . $sRelativePath;
224
                }
225
226
                $this->xRepository->addNamespace($sClassPath, ['separator' => $aOptions['separator']]);
227
228
                $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...
229
                $aClassOptions = ['namespace' => $sNamespace, 'timestamp' => $xFile->getMTime()];
230
                $this->xRepository->addClass($sClassName, $aClassOptions, $aOptions);
231
            }
232
        }
233
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
234
235
    /**
236
     * Find options for a class which is registered with namespace
237
     *
238
     * @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...
239
     *
240
     * @return array|null
241
     */
242
    protected function getClassOptionsFromNamespaces($sClassName)
243
    {
244
        // Find the corresponding namespace
245
        $sNamespace = null;
246
        $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...
247
        foreach($this->aNamespaces as $_sNamespace => $_aOptions)
248
        {
249
            // Check if the namespace matches the class.
250
            if(strncmp($sClassName, $_sNamespace . '\\', strlen($_sNamespace) + 1) === 0)
251
            {
252
                $sNamespace = $_sNamespace;
253
                $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...
254
                break;
255
            }
256
        }
257
        if($sNamespace === null)
258
        {
259
            return null; // Class not registered
260
        }
261
262
        // Get the class options
263
        $aClassOptions = ['namespace' => $sNamespace];
264
        return $this->xRepository->makeClassOptions($sClassName, $aClassOptions, $aOptions);
265
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
266
267
    /**
268
     * Find the options associated with a registered class name
269
     *
270
     * @param string        $sClassName            The class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 12 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter type; 8 found
Loading history...
271
     *
272
     * @return array|null
273
     */
274
    protected function getClassOptions($sClassName)
275
    {
276
        // Find options for a class registered with namespace.
277
        $aOptions = $this->getClassOptionsFromNamespaces($sClassName);
278
        if($aOptions !== null)
279
        {
280
            return $aOptions;
281
        }
282
283
        // Without a namespace, we need to parse all classes to be able to find one.
284
        $this->parseDirectories();
285
286
        // Find options for a class registered without namespace.
287
        return $this->xRepository->getClassOptions($sClassName);
288
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
289
290
    /**
291
     * Find a callable object by class name
292
     *
293
     * @param string        $sClassName            The class name of the callable object
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...
294
     *
295
     * @return CallableObject
296
     */
297
    public function getCallableObject($sClassName)
298
    {
299
        // Replace all separators ('.' and '_') with antislashes, and remove the antislashes
300
        // at the beginning and the end of the class name.
301
        $sClassName = (string)$sClassName;
302
        $sClassName = trim(str_replace('.', '\\', $sClassName), '\\');
303
        if($this->bUsingUnderscore)
304
        {
305
            $sClassName = trim(str_replace('_', '\\', $sClassName), '\\');
306
        }
307
308
        // Check if the callable object was already created.
309
        if(($xCallableObject = $this->xRepository->getCallableObject($sClassName)) != null)
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
310
        {
311
            return $xCallableObject;
312
        }
313
314
        $aOptions = $this->getClassOptions($sClassName);
315
        if($aOptions === null)
316
        {
317
            return null;
318
        }
319
320
        return $this->xRepository->createCallableObject($sClassName, $aOptions);
321
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
322
323
    /**
324
     * Register all the callable classes
325
     *
326
     * @return void
327
     */
328
    public function registerCallableClasses()
329
    {
330
        $this->parseDirectories();
331
        $this->parseNamespaces();
332
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
333
334
    /**
335
     * Create callable objects for all registered classes
336
     *
337
     * @return void
338
     */
339
    public function createCallableObjects()
340
    {
341
        $this->registerCallableClasses();
342
343
        foreach($this->xRepository->getClasses() as $sClassName => $aClassOptions)
344
        {
345
            // Make sure we create each callable object only once.
346
            if(!$this->xRepository->getCallableObject($sClassName))
347
            {
348
                $this->xRepository->createCallableObject($sClassName, $aClassOptions);
349
            }
350
        }
351
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
352
}
353