Passed
Push — master ( a07882...2b8759 )
by Thierry
02:21
created

CallableRegistry   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 264
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 62
dl 0
loc 264
rs 10
c 0
b 0
f 0
wmc 26

10 Methods

Rating   Name   Duplication   Size   Complexity  
B addNamespace() 0 28 7
A getClassOptions() 0 18 3
A getClassOptionsFromNamespaces() 0 23 4
A parseCallableClasses() 0 4 1
A addDirectory() 0 9 2
A registerCallableClasses() 0 8 2
A __construct() 0 11 2
A getCallableObject() 0 3 1
A getRequestFactory() 0 3 1
A checkCallableObject() 0 14 3
1
<?php
2
3
/**
4
 * CallableRegistry.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\Utils\Translation\Translator;
20
use Jaxon\Exception\SetupException;
21
22
use Composer\Autoload\ClassLoader;
23
24
use function file_exists;
25
use function in_array;
26
use function str_replace;
27
use function strlen;
28
use function strncmp;
29
use function trim;
30
31
class CallableRegistry
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CallableRegistry
Loading history...
32
{
33
    /**
34
     * The DI container
35
     *
36
     * @var Container
37
     */
38
    protected $di;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
39
40
    /**
41
     * The callable repository
42
     *
43
     * @var CallableRepository
44
     */
45
    protected $xRepository;
46
47
    /**
48
     * @var Translator
49
     */
50
    protected $xTranslator;
51
52
    /**
53
     * The registered directories
54
     *
55
     * These are directories registered without a namespace.
56
     *
57
     * @var array
58
     */
59
    protected $aDirectories = [];
60
61
    /**
62
     * The registered namespaces
63
     *
64
     * These are the namespaces specified when registering directories.
65
     *
66
     * @var array
67
     */
68
    protected $aNamespaces = [];
69
70
    /**
71
     * If the underscore is used as separator in js class names.
72
     *
73
     * @var bool
0 ignored issues
show
Bug introduced by
Expected "boolean" but found "bool" for @var tag in member variable comment
Loading history...
74
     */
75
    protected $bUsingUnderscore = false;
76
77
    /**
78
     * The Composer autoloader
79
     *
80
     * @var ClassLoader
81
     */
82
    private $xAutoloader = null;
83
84
    /**
85
     * The class constructor
86
     *
87
     * @param Container $di
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 10 spaces after parameter type; 1 found
Loading history...
88
     * @param CallableRepository $xRepository
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
89
     * @param Translator $xTranslator
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 9 spaces after parameter type; 1 found
Loading history...
90
     */
91
    public function __construct(Container $di, CallableRepository $xRepository, Translator $xTranslator)
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
92
    {
93
        $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...
94
        $this->xTranslator = $xTranslator;
95
        $this->xRepository = $xRepository;
96
97
        // Set the composer autoloader
98
        $sAutoloadFile = __DIR__ . '/../../../../../../autoload.php';
99
        if(file_exists($sAutoloadFile))
100
        {
101
            $this->xAutoloader = require($sAutoloadFile);
102
        }
103
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
104
105
    /**
106
     *
107
     * @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...
108
     * @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...
109
     *
110
     * @return void
111
     */
112
    public function addDirectory(string $sDirectory, array $aOptions)
113
    {
114
        // Set the autoload option default value
115
        if(!isset($aOptions['autoload']))
116
        {
117
            $aOptions['autoload'] = true;
118
        }
119
120
        $this->aDirectories[$sDirectory] = $aOptions;
121
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
122
123
    /**
124
     *
125
     * @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...
126
     * @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...
127
     *
128
     * @return void
129
     */
130
    public function addNamespace(string $sNamespace, array $aOptions)
131
    {
132
        // Separator default value
133
        if(!isset($aOptions['separator']))
134
        {
135
            $aOptions['separator'] = '.';
136
        }
137
        $aOptions['separator'] = trim($aOptions['separator']);
138
        if(!in_array($aOptions['separator'], ['.', '_']))
139
        {
140
            $aOptions['separator'] = '.';
141
        }
142
        if($aOptions['separator'] === '_')
143
        {
144
            $this->bUsingUnderscore = true;
145
        }
146
        // Set the autoload option default value
147
        if(!isset($aOptions['autoload']))
148
        {
149
            $aOptions['autoload'] = true;
150
        }
151
        // Register the dir with PSR4 autoloading
152
        if(($aOptions['autoload']) && $this->xAutoloader != null)
153
        {
154
            $this->xAutoloader->setPsr4($sNamespace . '\\', $aOptions['directory']);
155
        }
156
157
        $this->aNamespaces[$sNamespace] = $aOptions;
158
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
159
160
    /**
161
     * Find options for a class which is registered with namespace
162
     *
163
     * @param string $sClassName    The class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
164
     *
165
     * @return array|null
166
     */
167
    protected function getClassOptionsFromNamespaces(string $sClassName): ?array
168
    {
169
        // Find the corresponding namespace
170
        $sNamespace = null;
171
        $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...
172
        foreach($this->aNamespaces as $_sNamespace => $_aOptions)
173
        {
174
            // Check if the namespace matches the class.
175
            if(strncmp($sClassName, $_sNamespace . '\\', strlen($_sNamespace) + 1) === 0)
176
            {
177
                $sNamespace = $_sNamespace;
178
                $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...
179
                break;
180
            }
181
        }
182
        if($sNamespace === null)
183
        {
184
            return null; // Class not registered
185
        }
186
187
        // Get the class options
188
        $aClassOptions = ['namespace' => $sNamespace];
189
        return $this->xRepository->makeClassOptions($sClassName, $aClassOptions, $aOptions);
190
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
191
192
    /**
193
     * Find the options associated with a registered class name
194
     *
195
     * @param string $sClassName The class name
196
     *
197
     * @return array
198
     * @throws SetupException
199
     */
200
    protected function getClassOptions(string $sClassName): array
201
    {
202
        // Find options for a class registered with namespace.
203
        $aOptions = $this->getClassOptionsFromNamespaces($sClassName);
204
        if($aOptions !== null)
205
        {
206
            return $aOptions;
207
        }
208
        // Without a namespace, we need to parse all classes to be able to find one.
209
        $this->xRepository->parseDirectories($this->aDirectories);
210
        // Find options for a class registered without namespace.
211
        $aOptions = $this->xRepository->getClassOptions($sClassName);
212
        if($aOptions !== null)
213
        {
214
            return $aOptions;
215
        }
216
        $sMessage = $this->xTranslator->trans('errors.class.invalid', ['name' => $sClassName]);
217
        throw new SetupException($sMessage);
218
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
219
220
    /**
221
     * Check if a callable object is already in the DI, and register if not
222
     *
223
     * @param string $sClassName The class name of the callable object
224
     *
225
     * @return string
226
     * @throws SetupException
227
     */
228
    private function checkCallableObject(string $sClassName): string
229
    {
230
        // Replace all separators ('.' and '_') with antislashes, and remove the antislashes
231
        // at the beginning and the end of the class name.
232
        $sSeparator = $this->bUsingUnderscore ? '_' : '.';
233
        $sClassName = trim(str_replace($sSeparator, '\\', $sClassName), '\\');
234
235
        // Check if the callable object was already created.
236
        if(!$this->di->h($sClassName))
237
        {
238
            $aOptions = $this->getClassOptions($sClassName);
239
            $this->xRepository->registerCallableClass($sClassName, $aOptions);
240
        }
241
        return $sClassName;
242
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
243
244
    /**
245
     * Get the callable object for a given class
246
     *
247
     * @param string $sClassName The class name of the callable object
248
     *
249
     * @return CallableObject|null
250
     * @throws SetupException
251
     */
252
    public function getCallableObject(string $sClassName): ?CallableObject
253
    {
254
        return $this->di->getCallableObject($this->checkCallableObject($sClassName));
255
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
256
257
    /**
258
     * Get the request factory for a given class
259
     *
260
     * @param string $sClassName The class name of the callable object
261
     *
262
     * @return RequestFactory|null
263
     * @throws SetupException
264
     */
265
    public function getRequestFactory(string $sClassName): ?RequestFactory
266
    {
267
        return $this->di->getRequestFactory($this->checkCallableObject($sClassName));
268
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
269
270
    /**
271
     * Register all the callable classes
272
     *
273
     * @return void
274
     */
275
    public function parseCallableClasses()
276
    {
277
        $this->xRepository->parseDirectories($this->aDirectories);
278
        $this->xRepository->parseNamespaces($this->aNamespaces);
279
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
280
281
    /**
282
     * Create callable objects for all registered classes
283
     *
284
     * @return void
285
     * @throws SetupException
286
     */
287
    public function registerCallableClasses()
288
    {
289
        $this->parseCallableClasses();
290
291
        $aClasses = $this->xRepository->getClasses();
292
        foreach($aClasses as $sClassName => $aClassOptions)
293
        {
294
            $this->xRepository->registerCallableClass($sClassName, $aClassOptions);
295
        }
296
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
297
}
298