Passed
Push — main ( 18c043...2ebc4f )
by Thierry
05:47 queued 40s
created

CallableObject::isProtectedMethod()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 8
rs 9.6111
cc 5
nc 7
nop 2
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_fill_keys;
40
use function array_filter;
41
use function array_map;
42
use function array_merge;
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|null
83
     */
84
    private $xOptions = null;
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
     * @var array
98
     */
99
    private $aProtectedMethods;
100
101
    /**
102
     * The class constructor
103
     *
104
     * @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...
105
     * @param AnnotationReaderInterface $xAnnotationReader
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
106
     * @param ReflectionClass $xReflectionClass    The reflection class
0 ignored issues
show
Coding Style introduced by
Expected 11 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
107
     * @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...
108
     * @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...
109
     */
110
    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...
111
        ReflectionClass $xReflectionClass, array $aOptions, array $aProtectedMethods)
112
    {
113
        $this->di = $di;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 16 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
        $this->xReflectionClass = $xReflectionClass;
115
        $this->aProtectedMethods = array_fill_keys($aProtectedMethods, true);
116
117
        $aAnnotations = $xAnnotationReader->getAttributes($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...
118
            $this->getPublicMethods(true), $this->getProperties());
119
        $this->xOptions = new CallableObjectOptions($aOptions, $aAnnotations);
120
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
121
122
    /**
123
     * Get the public and protected attributes of the callable object
124
     *
125
     * @return array
126
     */
127
    private function getProperties(): array
128
    {
129
        return array_map(function($xProperty) {
130
            return $xProperty->getName();
131
        }, $this->xReflectionClass->getProperties($this->nPropertiesFilter));
132
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
133
134
    /**
135
     * @param string $sMethodName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
136
     * @param bool $bTakeAll
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
137
     *
138
     * @return bool
139
     */
140
    private function isProtectedMethod(string $sMethodName, bool $bTakeAll): bool
141
    {
142
        // Don't take magic __call, __construct, __destruct methods
143
        // Don't take protected methods
144
        return substr($sMethodName, 0, 2) === '__' ||
145
            isset($this->aProtectedMethods[$sMethodName]) ||
146
            (!$bTakeAll && $this->xOptions !== null &&
147
            $this->xOptions->isProtectedMethod($sMethodName));
148
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
149
150
    /**
151
     * Get the public methods of the callable object
152
     *
153
     * @param bool $bTakeAll
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
154
     *
155
     * @return array
156
     */
157
    public function getPublicMethods(bool $bTakeAll): array
158
    {
159
        $aMethods = array_map(function($xMethod) {
160
            return $xMethod->getShortName();
161
        }, $this->xReflectionClass->getMethods($this->nMethodsFilter));
162
163
        return array_filter($aMethods, function($sMethodName) use($bTakeAll) {
164
            return !$this->isProtectedMethod($sMethodName, $bTakeAll);
165
        });
166
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
167
168
    /**
169
     * @return bool
170
     */
171
    public function excluded(): bool
172
    {
173
        return $this->xOptions->excluded();
0 ignored issues
show
Bug introduced by
The method excluded() does not exist on null. ( Ignorable by Annotation )

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

173
        return $this->xOptions->/** @scrutinizer ignore-call */ excluded();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
174
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
175
176
    /**
177
     * Get the name of the registered PHP class
178
     *
179
     * @return string
180
     */
181
    public function getClassName(): string
182
    {
183
        return $this->xReflectionClass->getName();
184
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
185
186
    /**
187
     * Get the name of the corresponding javascript class
188
     *
189
     * @return string
190
     */
191
    public function getJsName(): string
192
    {
193
        return str_replace('\\', $this->xOptions->separator(), $this->getClassName());
194
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
195
196
    /**
197
     * Set configuration options / call options for each method
198
     *
199
     * @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...
200
     * @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...
201
     *
202
     * @return void
203
     */
204
    public function configure(string $sName, $xValue)
205
    {
206
        $this->xOptions->addOption($sName, $xValue);
207
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
208
209
    /**
210
     * @return array
211
     */
212
    public function getClassDiOptions(): array
213
    {
214
        $aDiOptions = $this->xOptions->diOptions();
215
        return $aDiOptions['*'] ?? [];
216
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
217
218
    /**
219
     * @param string $sMethodName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
220
     *
221
     * @return array
222
     */
223
    public function getMethodDiOptions(string $sMethodName): array
224
    {
225
        $aDiOptions = $this->xOptions->diOptions();
226
        return $aDiOptions[$sMethodName] ?? [];
227
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
228
229
    /**
230
     * Get the js options of the callable class
231
     *
232
     * @return array
233
     */
234
    public function getOptions(): array
235
    {
236
        return $this->xOptions->jsOptions();
237
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
238
239
    /**
240
     * Return a list of methods of the callable object to export to javascript
241
     *
242
     * @return array
243
     */
244
    public function getCallableMethods(): array
245
    {
246
        // Convert an option to a string to be displayed in the js script template.
247
        $fConvertOption = function($xOption) {
248
            return is_array($xOption) ? json_encode($xOption) : $xOption;
249
        };
250
251
        return array_map(function($sMethodName) use($fConvertOption) {
252
            return [
253
                'name' => $sMethodName,
254
                'config' => array_map($fConvertOption, $this->xOptions->getMethodOptions($sMethodName)),
255
            ];
256
        }, $this->getPublicMethods(false));
257
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
258
259
    /**
260
     * Get the registered callable object
261
     *
262
     * @return null|object
263
     */
264
    public function getRegisteredObject()
265
    {
266
        return $this->di->g($this->xReflectionClass->getName());
267
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
268
269
    /**
270
     * Check if the specified method name is one of the methods of the registered callable object
271
     *
272
     * @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...
273
     *
274
     * @return bool
275
     */
276
    public function hasMethod(string $sMethod): bool
277
    {
278
        return $this->xReflectionClass->hasMethod($sMethod);
279
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
280
281
    /**
282
     * Call the specified method of the registered callable object using the specified array of arguments
283
     *
284
     * @param string $sMethod    The method name
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 4 found
Loading history...
285
     * @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...
286
     * @param bool $bAccessible    If false, only calls to public method are allowed
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
287
     *
288
     * @return mixed
289
     * @throws ReflectionException
290
     */
291
    private function callMethod(string $sMethod, array $aArgs, bool $bAccessible)
292
    {
293
        $reflectionMethod = $this->xReflectionClass->getMethod($sMethod);
294
        $reflectionMethod->setAccessible($bAccessible); // Make it possible to call protected methods
295
        return $reflectionMethod->invokeArgs($this->xRegisteredObject, $aArgs);
296
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
297
298
    /**
299
     * Call the specified method of the registered callable object using the specified array of arguments
300
     *
301
     * @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...
302
     *
303
     * @return void
304
     * @throws ReflectionException
305
     */
306
    private function callHookMethods(array $aHookMethods)
307
    {
308
        $sMethod = $this->xTarget->getMethodName();
309
        // The hooks defined at method level are merged with those defined at class level.
310
        $aMethods = array_merge($aHookMethods['*'] ?? [], $aHookMethods[$sMethod] ?? []);
311
        foreach($aMethods as $xKey => $xValue)
312
        {
313
            $sHookName = $xValue;
314
            $aHookArgs = [];
315
            if(is_string($xKey))
316
            {
317
                $sHookName = $xKey;
318
                $aHookArgs = is_array($xValue) ? $xValue : [$xValue];
319
            }
320
            $this->callMethod($sHookName, $aHookArgs, true);
321
        }
322
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
323
324
    /**
325
     * Call the specified method of the registered callable object using the specified array of arguments
326
     *
327
     * @param Target $xTarget The target of the Jaxon call
328
     *
329
     * @return null|ResponseInterface
330
     * @throws ReflectionException
331
     * @throws SetupException
332
     */
333
    public function call(Target $xTarget): ?ResponseInterface
334
    {
335
        $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...
336
        $this->xRegisteredObject = $this->di->getRegisteredObject($this, $xTarget);
337
338
        // Methods to call before processing the request
339
        $this->callHookMethods($this->xOptions->beforeMethods());
340
341
        // Call the request method
342
        $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...
343
        $xResponse = $this->callMethod($sMethod, $this->xTarget->getMethodArgs(), false);
344
345
        // Methods to call after processing the request
346
        $this->callHookMethods($this->xOptions->afterMethods());
347
        return $xResponse;
348
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
349
}
350