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

CallableObject::getJsName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * CallableObject.php - Jaxon callable object
5
 *
6
 * This class stores a reference to an object whose methods can be called from
7
 * the client via an Jaxon request
8
 *
9
 * The Jaxon plugin manager will call <CallableObject->getClientScript> so that
10
 * stub functions can be generated and sent to the browser.
11
 *
12
 * @package jaxon-core
0 ignored issues
show
Coding Style introduced by
Package name "jaxon-core" is not valid; consider "Jaxoncore" instead
Loading history...
13
 * @author Jared White
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
14
 * @author J. Max Wilson
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
15
 * @author Joseph Woolley
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
16
 * @author Steffen Konerow
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
17
 * @author Thierry Feuzeu <[email protected]>
18
 * @copyright Copyright (c) 2005-2007 by Jared White & J. Max Wilson
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
19
 * @copyright Copyright (c) 2008-2010 by Joseph Woolley, Steffen Konerow, Jared White  & J. Max Wilson
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
20
 * @copyright 2016 Thierry Feuzeu <[email protected]>
21
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
22
 * @link https://github.com/jaxon-php/jaxon-core
23
 */
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...
24
25
namespace Jaxon\Request\Plugin\CallableClass;
26
27
use Jaxon\Container\Container;
28
use Jaxon\Response\Response;
29
30
use ReflectionClass;
31
use ReflectionException;
32
33
use function array_map;
34
use function array_merge;
35
use function in_array;
36
use function is_array;
37
use function is_string;
38
use function strlen;
39
40
class CallableObject
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CallableObject
Loading history...
41
{
42
    /**
43
     * The DI container
44
     *
45
     * @var Container
46
     */
47
    protected $di;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
48
49
    /**
50
     * The reflection class of the user registered callable object
51
     *
52
     * @var ReflectionClass
53
     */
54
    private $xReflectionClass;
55
56
    /**
57
     * A list of methods of the user registered callable object the library must not export to javascript
58
     *
59
     * @var array
60
     */
61
    private $aProtectedMethods = [];
62
63
    /**
64
     * A list of methods to call before processing the request
65
     *
66
     * @var array
67
     */
68
    private $aBeforeMethods = [];
69
70
    /**
71
     * A list of methods to call after processing the request
72
     *
73
     * @var array
74
     */
75
    private $aAfterMethods = [];
76
77
    /**
78
     * The callable object options
79
     *
80
     * @var array
81
     */
82
    private $aOptions = [];
83
84
    /**
85
     * The namespace the callable class was registered from
86
     *
87
     * @var string
88
     */
89
    private $sNamespace = '';
90
91
    /**
92
     * The character to use as separator in javascript class names
93
     *
94
     * @var string
95
     */
96
    private $sSeparator = '.';
97
98
    /**
99
     * The class constructor
100
     *
101
     * @param Container  $di
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter type; 2 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
102
     * @param ReflectionClass $xReflectionClass    The reflection class
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
103
     *
104
     */
105
    public function __construct(Container $di, ReflectionClass $xReflectionClass)
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
106
    {
107
        $this->di = $di;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 15 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...
108
        $this->xReflectionClass = $xReflectionClass;
109
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
110
111
    /**
112
     * Set callable object options
113
     *
114
     * @param array  $aOptions
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 2 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
115
     *
116
     * @return void
117
     */
118
    public function setOptions(array $aOptions)
119
    {
120
        $this->aOptions = $aOptions;
121
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
122
123
    /**
124
     * Get callable object options
125
     *
126
     * @return array
127
     */
128
    public function getOptions(): array
129
    {
130
        return $this->aOptions;
131
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
132
133
    /**
134
     * Get the reflection class
135
     *
136
     * @return ReflectionClass
137
     */
138
    public function getReflectionClass(): ReflectionClass
139
    {
140
        return $this->xReflectionClass;
141
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
142
143
    /**
144
     * Get the class name of this callable object, without the namespace if any
145
     *
146
     * @return string
147
     */
148
    public function getClassName(): string
149
    {
150
        // Get the class name without the namespace.
151
        return $this->xReflectionClass->getShortName();
152
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
153
154
    /**
155
     * Get the name of this callable object
156
     *
157
     * @return string
158
     */
159
    public function getName(): string
160
    {
161
        // Get the class name with the namespace.
162
        return $this->xReflectionClass->getName();
163
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
164
165
    /**
166
     * Get the name of the corresponding javascript class
167
     *
168
     * @return string
169
     */
170
    public function getJsName(): string
171
    {
172
        return str_replace('\\', $this->sSeparator, $this->getName());
173
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
174
175
    /**
176
     * Get the namespace of this callable object
177
     *
178
     * @return string
179
     */
180
    public function getNamespace(): string
181
    {
182
        // The namespace of the registered class.
183
        return $this->xReflectionClass->getNamespaceName();
184
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
185
186
    /**
187
     * Get the namespace the callable class was registered from
188
     *
189
     * @return string
190
     */
191
    public function getRootNamespace(): string
192
    {
193
        // The namespace the callable class was registered from.
194
        return $this->sNamespace;
195
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
196
197
    /**
198
     * Set hook methods
199
     *
200
     * @param array $aHookMethods    The array of hook methods
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
201
     * @param string|array $xValue    The value of the configuration option
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter name; 4 found
Loading history...
202
     *
203
     * @return void
204
     */
205
    public function setHookMethods(array &$aHookMethods, $xValue)
206
    {
207
        foreach($xValue as $sCalledMethod => $xMethodToCall)
208
        {
209
            if(is_array($xMethodToCall))
210
            {
211
                $aHookMethods[$sCalledMethod] = $xMethodToCall;
212
            }
213
            elseif(is_string($xMethodToCall))
214
            {
215
                $aHookMethods[$sCalledMethod] = [$xMethodToCall];
216
            }
217
        }
218
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
219
220
    /**
221
     * Set configuration options / call options for each method
222
     *
223
     * @param string $sName    The name of the configuration option
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
224
     * @param string|array $xValue    The value of the configuration option
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
225
     *
226
     * @return void
227
     */
228
    public function configure(string $sName, $xValue)
229
    {
230
        switch($sName)
231
        {
232
        // Set the separator
233
        case 'separator':
234
            if($xValue == '_' || $xValue == '.')
235
            {
236
                $this->sSeparator = $xValue;
237
            }
238
            break;
239
        // Set the namespace
240
        case 'namespace':
241
            if(is_string($xValue))
242
            {
243
                $this->sNamespace = $xValue;
244
            }
245
            break;
246
        // Set the protected methods
247
        case 'protected':
248
            if(is_array($xValue))
249
            {
250
                $this->aProtectedMethods = array_merge($this->aProtectedMethods, $xValue);
251
            }
252
            elseif(is_string($xValue))
0 ignored issues
show
introduced by
The condition is_string($xValue) is always true.
Loading history...
253
            {
254
                $this->aProtectedMethods[] = $xValue;
255
            }
256
            break;
257
        // Set the methods to call before processing the request
258
        case '__before':
259
            $this->setHookMethods($this->aBeforeMethods, $xValue);
260
            break;
261
        // Set the methods to call after processing the request
262
        case '__after':
263
            $this->setHookMethods($this->aAfterMethods, $xValue);
264
            break;
265
        default:
266
            break;
267
        }
268
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
269
270
    /**
271
     * Return a list of methods of the callable object
272
     *
273
     * @param array $aProtectedMethods    The protected methods
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
274
     *
275
     * @return array
276
     */
277
    private function _getMethods(array $aProtectedMethods): array
278
    {
279
        $aMethods = [];
280
        foreach($this->xReflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $xMethod)
281
        {
282
            $sMethodName = $xMethod->getShortName();
283
            // Don't take magic __call, __construct, __destruct methods
284
            if(strlen($sMethodName) > 2 && substr($sMethodName, 0, 2) == '__')
285
            {
286
                continue;
287
            }
288
            // Don't take protected methods
289
            if(in_array($sMethodName, $aProtectedMethods) || in_array($sMethodName, $this->aProtectedMethods))
290
            {
291
                continue;
292
            }
293
            $aMethods[] = $sMethodName;
294
        }
295
        return $aMethods;
296
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
297
298
    /**
299
     * Return a list of methods of the callable object to export to javascript
300
     *
301
     * @param array $aProtectedMethods    The protected methods
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
302
     *
303
     * @return array
304
     */
305
    public function getMethods(array $aProtectedMethods): array
306
    {
307
        $aConfig = $this->getOptions();
308
309
        // Convert an option to string, to be displayed in the js script template.
310
        $fConvertOption = function($xOption) {
311
            return is_array($xOption) ? json_encode($xOption) : $xOption;
312
        };
313
        $aCommonConfig = isset($aConfig['*']) ? array_map($fConvertOption, $aConfig['*']) : [];
314
315
        $aMethods = [];
316
        foreach($this->_getMethods($aProtectedMethods) as $sMethodName)
317
        {
318
            // Specific options for this method
319
            $aMethodConfig = isset($aConfig[$sMethodName]) ?
0 ignored issues
show
Coding Style introduced by
Expected 1 space after "?"; newline found
Loading history...
320
                array_map($fConvertOption, $aConfig[$sMethodName]) : [];
321
            $aMethods[] = [
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...
322
                'name' => $sMethodName,
323
                'config' => array_merge($aCommonConfig, $aMethodConfig),
324
            ];
325
        }
326
        return $aMethods;
327
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
328
329
    /**
330
     * Get the registered callable object
331
     *
332
     * @return null|object
333
     */
334
    public function getRegisteredObject()
335
    {
336
        return $this->di->get($this->xReflectionClass->getName());
337
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
338
339
    /**
340
     * Check if the specified method name is one of the methods of the registered callable object
341
     *
342
     * @param string $sMethod    The name of the method to check
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
343
     *
344
     * @return bool
345
     */
346
    public function hasMethod(string $sMethod): bool
347
    {
348
        return $this->xReflectionClass->hasMethod($sMethod);
349
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
350
351
    /**
352
     * Call the specified method of the registered callable object using the specified array of arguments
353
     *
354
     * @param array $aClassMethods    The method config options
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
355
     * @param string $sMethod    The method called by the request
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter name; 4 found
Loading history...
356
     *
357
     * @return void
358
     * @throws ReflectionException
359
     */
360
    private function callHookMethods(array $aClassMethods, string $sMethod)
361
    {
362
        $aMethods = [];
363
        if(isset($aClassMethods[$sMethod]))
364
        {
365
            $aMethods = $aClassMethods[$sMethod];
366
        }
367
        elseif(isset($aClassMethods['*']))
368
        {
369
            $aMethods = $aClassMethods['*'];
370
        }
371
        foreach($aMethods as $xKey => $xValue)
372
        {
373
            $sMethodName = $xValue;
374
            $aMethodArgs = [];
375
            if(is_string($xKey))
376
            {
377
                $sMethodName = $xKey;
378
                $aMethodArgs = is_array($xValue) ? $xValue : [$xValue];
379
            }
380
            if(!$this->xReflectionClass->hasMethod($sMethodName))
381
            {
382
                continue;
383
            }
384
            $reflectionMethod = $this->xReflectionClass->getMethod($sMethodName);
385
            $reflectionMethod->setAccessible(true); // Make it possible to call protected methods
386
            $reflectionMethod->invokeArgs($this->getRegisteredObject(), $aMethodArgs);
387
        }
388
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
389
390
    /**
391
     * Call the specified method of the registered callable object using the specified array of arguments
392
     *
393
     * @param string $sMethod    The name of the method to call
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
394
     * @param array $aArgs    The arguments to pass to the method
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
395
     *
396
     * @return null|Response
397
     * @throws ReflectionException
398
     */
399
    public function call(string $sMethod, array $aArgs): ?Response
400
    {
401
        if(!$this->hasMethod($sMethod))
402
        {
403
            return null;
404
        }
405
406
        // Methods to call before processing the request
407
        $this->callHookMethods($this->aBeforeMethods, $sMethod);
408
409
        $reflectionMethod = $this->xReflectionClass->getMethod($sMethod);
410
        $xResponse = $reflectionMethod->invokeArgs($this->getRegisteredObject(), $aArgs);
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...
411
412
        // Methods to call after processing the request
413
        $this->callHookMethods($this->aAfterMethods, $sMethod);
414
415
        return $xResponse;
416
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
417
}
418