Passed
Push — main ( fef313...79e33c )
by Thierry
11:43
created

CallableObject   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 295
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 23
eloc 66
dl 0
loc 295
rs 10
c 5
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getClassDiOptions() 0 4 1
A hasMethod() 0 3 1
A getOptions() 0 3 1
A getCallableMethods() 0 13 2
A getClassName() 0 3 1
A callMethod() 0 5 1
A getMethodDiOptions() 0 4 1
A excluded() 0 3 1
A configure() 0 3 1
A getJsName() 0 3 1
A __construct() 0 19 2
A getProperties() 0 5 1
A getRegisteredObject() 0 3 1
A getPublicMethods() 0 12 3
A call() 0 15 1
A callHookMethods() 0 15 4
1
<?php
2
3
/**
4
 * CallableObject.php
5
 *
6
 * Jaxon callable object
7
 *
8
 * This class stores a reference to an object whose methods can be called from
9
 * the client via a Jaxon request
10
 *
11
 * The Jaxon plugin manager will call <CallableObject->getClientScript> so that
12
 * stub functions can be generated and sent to the browser.
13
 *
14
 * @package jaxon-core
0 ignored issues
show
Coding Style introduced by
Package name "jaxon-core" is not valid; consider "Jaxoncore" instead
Loading history...
15
 * @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...
16
 * @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...
17
 * @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...
18
 * @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...
19
 * @author Thierry Feuzeu <[email protected]>
20
 * @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...
21
 * @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...
22
 * @copyright 2016 Thierry Feuzeu <[email protected]>
23
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
24
 * @link https://github.com/jaxon-php/jaxon-core
25
 */
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...
26
27
namespace Jaxon\Plugin\Request\CallableClass;
28
29
use Jaxon\Di\Container;
30
use Jaxon\Exception\SetupException;
31
use Jaxon\Plugin\AnnotationReaderInterface;
32
use Jaxon\Request\Target;
33
use Jaxon\Response\ResponseInterface;
34
use ReflectionClass;
35
use ReflectionException;
36
use ReflectionMethod;
37
use ReflectionProperty;
38
39
use function array_filter;
40
use function array_map;
41
use function array_merge;
42
use function in_array;
43
use function is_array;
44
use function is_string;
45
use function json_encode;
46
use function str_replace;
47
use function substr;
48
49
class CallableObject
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CallableObject
Loading history...
50
{
51
    /**
52
     * The DI container
53
     *
54
     * @var Container
55
     */
56
    protected $di;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
57
58
    /**
59
     * The reflection class of the user registered callable object
60
     *
61
     * @var ReflectionClass
62
     */
63
    private $xReflectionClass;
64
65
    /**
66
     * The user registered callable object
67
     *
68
     * @var mixed
69
     */
70
    private $xRegisteredObject = null;
71
72
    /**
73
     * The target of the Jaxon call
74
     *
75
     * @var Target
76
     */
77
    private $xTarget;
78
79
    /**
80
     * The options of this callable object
81
     *
82
     * @var CallableObjectOptions
83
     */
84
    private $xOptions;
85
86
    /**
87
     * @var int
0 ignored issues
show
Bug introduced by
Expected "integer" but found "int" for @var tag in member variable comment
Loading history...
88
     */
89
    private $nPropertiesFilter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED;
90
91
    /**
92
     * @var int
0 ignored issues
show
Bug introduced by
Expected "integer" but found "int" for @var tag in member variable comment
Loading history...
93
     */
94
    private $nMethodsFilter = ReflectionMethod::IS_PUBLIC;
95
96
    /**
97
     * The class constructor
98
     *
99
     * @param Container  $di
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 17 spaces after parameter type; 2 found
Loading history...
100
     * @param AnnotationReaderInterface $xAnnotationReader
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
101
     * @param ReflectionClass $xReflectionClass    The reflection class
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Expected 11 spaces after parameter type; 1 found
Loading history...
102
     * @param array $aOptions
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 21 spaces after parameter type; 1 found
Loading history...
103
     * @param array $aProtectedMethods
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 21 spaces after parameter type; 1 found
Loading history...
104
     */
105
    public function __construct(Container $di, AnnotationReaderInterface $xAnnotationReader,
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
106
        ReflectionClass $xReflectionClass, array $aOptions, array $aProtectedMethods)
107
    {
108
        $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...
109
        $this->xReflectionClass = $xReflectionClass;
110
        $this->xOptions = new CallableObjectOptions();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 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...
111
112
        $sClassName = $xReflectionClass->getName();
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...
113
        $aMethods = $this->getPublicMethods($aProtectedMethods);
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...
114
        $aProperties = $this->getProperties();
115
        $aAnnotations = $xAnnotationReader->getAttributes($sClassName, $aMethods, $aProperties);
116
        [$bExcluded,] = $aAnnotations;
117
        if($bExcluded)
118
        {
119
            $this->configure('excluded', true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type array|string expected by parameter $xValue of Jaxon\Plugin\Request\Cal...ableObject::configure(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

119
            $this->configure('excluded', /** @scrutinizer ignore-type */ true);
Loading history...
120
            return;
121
        }
122
123
        $this->xOptions->setOptions($aOptions, $aAnnotations);
124
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
125
126
    /**
127
     * Check if the js code for this object must be generated
128
     *
129
     * @return bool
130
     */
131
    public function excluded(): bool
132
    {
133
        return $this->xOptions->excluded();
134
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
135
136
    /**
137
     * Get the name of the registered PHP class
138
     *
139
     * @return string
140
     */
141
    public function getClassName(): string
142
    {
143
        return $this->xReflectionClass->getName();
144
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
145
146
    /**
147
     * Get the name of the corresponding javascript class
148
     *
149
     * @return string
150
     */
151
    public function getJsName(): string
152
    {
153
        return str_replace('\\', $this->xOptions->separator(), $this->getClassName());
154
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
155
156
    /**
157
     * Set configuration options / call options for each method
158
     *
159
     * @param string $sName    The name of the configuration option
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
160
     * @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...
161
     *
162
     * @return void
163
     */
164
    public function configure(string $sName, $xValue)
165
    {
166
        $this->xOptions->addOption($sName, $xValue);
167
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
168
169
    /**
170
     * @return array
171
     */
172
    public function getClassDiOptions(): array
173
    {
174
        $aDiOptions = $this->xOptions->diOptions();
175
        return $aDiOptions['*'] ?? [];
176
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
177
178
    /**
179
     * @param string $sMethodName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
180
     *
181
     * @return array
182
     */
183
    public function getMethodDiOptions(string $sMethodName): array
184
    {
185
        $aDiOptions = $this->xOptions->diOptions();
186
        return $aDiOptions[$sMethodName] ?? [];
187
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
188
189
    /**
190
     * Get the js options of the callable class
191
     *
192
     * @return array
193
     */
194
    public function getOptions(): array
195
    {
196
        return $this->xOptions->jsOptions();
197
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
198
199
    /**
200
     * Get the public and protected attributes of the callable object
201
     *
202
     * @return array
203
     */
204
    public function getProperties(): array
205
    {
206
        return array_map(function($xProperty) {
207
            return $xProperty->getName();
208
        }, $this->xReflectionClass->getProperties($this->nPropertiesFilter));
209
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
210
211
    /**
212
     * Get the public methods of the callable object
213
     *
214
     * @param array $aProtectedMethods    The protected methods
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
215
     *
216
     * @return array
217
     */
218
    public function getPublicMethods(array $aProtectedMethods = []): array
219
    {
220
        $aMethods = array_map(function($xMethod) {
221
            return $xMethod->getShortName();
222
        }, $this->xReflectionClass->getMethods($this->nMethodsFilter));
223
224
        return array_filter($aMethods, function($sMethodName) use($aProtectedMethods) {
225
            // Don't take magic __call, __construct, __destruct methods
226
            // Don't take protected methods
227
            return substr($sMethodName, 0, 2) !== '__' &&
228
                !in_array($sMethodName, $aProtectedMethods) &&
229
                !in_array($sMethodName, $this->xOptions->protectedMethods());
230
        });
231
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
232
233
    /**
234
     * Return a list of methods of the callable object to export to javascript
235
     *
236
     * @param array $aProtectedMethods    The protected methods
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
237
     *
238
     * @return array
239
     */
240
    public function getCallableMethods(array $aProtectedMethods): array
241
    {
242
        // Convert an option to a string to be displayed in the js script template.
243
        $fConvertOption = function($xOption) {
244
            return is_array($xOption) ? json_encode($xOption) : $xOption;
245
        };
246
247
        return array_map(function($sMethodName) use($fConvertOption) {
248
            return [
249
                'name' => $sMethodName,
250
                'config' => array_map($fConvertOption, $this->xOptions->getMethodOptions($sMethodName)),
251
            ];
252
        }, $this->getPublicMethods($aProtectedMethods));
253
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
254
255
    /**
256
     * Get the registered callable object
257
     *
258
     * @return null|object
259
     */
260
    public function getRegisteredObject()
261
    {
262
        return $this->di->g($this->xReflectionClass->getName());
263
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
264
265
    /**
266
     * Check if the specified method name is one of the methods of the registered callable object
267
     *
268
     * @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...
269
     *
270
     * @return bool
271
     */
272
    public function hasMethod(string $sMethod): bool
273
    {
274
        return $this->xReflectionClass->hasMethod($sMethod);
275
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
276
277
    /**
278
     * Call the specified method of the registered callable object using the specified array of arguments
279
     *
280
     * @param string $sMethod    The method name
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 4 found
Loading history...
281
     * @param array $aArgs    The method arguments
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 7 spaces after parameter name; 4 found
Loading history...
282
     * @param bool $bAccessible    If false, only calls to public method are allowed
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
283
     *
284
     * @return mixed
285
     * @throws ReflectionException
286
     */
287
    private function callMethod(string $sMethod, array $aArgs, bool $bAccessible)
288
    {
289
        $reflectionMethod = $this->xReflectionClass->getMethod($sMethod);
290
        $reflectionMethod->setAccessible($bAccessible); // Make it possible to call protected methods
291
        return $reflectionMethod->invokeArgs($this->xRegisteredObject, $aArgs);
292
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
293
294
    /**
295
     * Call the specified method of the registered callable object using the specified array of arguments
296
     *
297
     * @param array $aHookMethods    The method config options
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
298
     *
299
     * @return void
300
     * @throws ReflectionException
301
     */
302
    private function callHookMethods(array $aHookMethods)
303
    {
304
        $sMethod = $this->xTarget->getMethodName();
305
        // The hooks defined at method level are merged with those defined at class level.
306
        $aMethods = array_merge($aHookMethods['*'] ?? [], $aHookMethods[$sMethod] ?? []);
307
        foreach($aMethods as $xKey => $xValue)
308
        {
309
            $sHookName = $xValue;
310
            $aHookArgs = [];
311
            if(is_string($xKey))
312
            {
313
                $sHookName = $xKey;
314
                $aHookArgs = is_array($xValue) ? $xValue : [$xValue];
315
            }
316
            $this->callMethod($sHookName, $aHookArgs, true);
317
        }
318
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
319
320
    /**
321
     * Call the specified method of the registered callable object using the specified array of arguments
322
     *
323
     * @param Target $xTarget The target of the Jaxon call
324
     *
325
     * @return null|ResponseInterface
326
     * @throws ReflectionException
327
     * @throws SetupException
328
     */
329
    public function call(Target $xTarget): ?ResponseInterface
330
    {
331
        $this->xTarget = $xTarget;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 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...
332
        $this->xRegisteredObject = $this->di->getRegisteredObject($this, $xTarget);
333
334
        // Methods to call before processing the request
335
        $this->callHookMethods($this->xOptions->beforeMethods());
336
337
        // Call the request method
338
        $sMethod = $xTarget->getMethodName();
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...
339
        $xResponse = $this->callMethod($sMethod, $this->xTarget->getMethodArgs(), false);
340
341
        // Methods to call after processing the request
342
        $this->callHookMethods($this->xOptions->afterMethods());
343
        return $xResponse;
344
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
345
}
346