Passed
Push — feature/code_improvement ( 07c142...134f8a )
by Thierry
20:35 queued 17:14
created

CallableClass::getCallableObject()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 6
nop 1
dl 0
loc 26
rs 9.504
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * CallableClass.php - Jaxon callable class plugin
5
 *
6
 * This class registers user defined callable classes, generates client side javascript code,
7
 * and calls their methods on user request
8
 *
9
 * @package jaxon-core
0 ignored issues
show
Coding Style introduced by
Package name "jaxon-core" is not valid; consider "Jaxoncore" instead
Loading history...
10
 * @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...
11
 * @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...
12
 * @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...
13
 * @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...
14
 * @author Thierry Feuzeu <[email protected]>
15
 * @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...
16
 * @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...
17
 * @copyright 2016 Thierry Feuzeu <[email protected]>
18
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
19
 * @link https://github.com/jaxon-php/jaxon-core
20
 */
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...
21
22
namespace Jaxon\Request\Plugin;
23
24
use Jaxon\Jaxon;
25
use Jaxon\CallableClass as UserCallableClass;
26
use Jaxon\Plugin\Request as RequestPlugin;
27
use Jaxon\Request\Support\CallableRegistry;
28
use Jaxon\Request\Support\CallableRepository;
29
use Jaxon\Request\Target;
30
31
class CallableClass extends RequestPlugin
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CallableClass
Loading history...
32
{
33
    use \Jaxon\Features\Config;
34
    use \Jaxon\Features\Template;
35
    use \Jaxon\Features\Validator;
36
    use \Jaxon\Features\Translator;
37
38
    /**
39
     * The callable registrar
40
     *
41
     * @var CallableRegistry
42
     */
43
    protected $xRegistry;
44
45
    /**
46
     * The callable repository
47
     *
48
     * @var CallableRepository
49
     */
50
    protected $xRepository;
51
52
    /**
53
     * The value of the class parameter of the incoming Jaxon request
54
     *
55
     * @var string
56
     */
57
    protected $sRequestedClass = '';
58
59
    /**
60
     * The value of the method parameter of the incoming Jaxon request
61
     *
62
     * @var string
63
     */
64
    protected $sRequestedMethod = '';
65
66
    /**
67
     * The class constructor
68
     *
69
     * @param CallableRegistry        $xRegistry
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 8 found
Loading history...
70
     * @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...
71
     */
72
    public function __construct(CallableRegistry $xRegistry, CallableRepository $xRepository)
73
    {
74
        $this->xRegistry = $xRegistry;
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...
75
        $this->xRepository = $xRepository;
76
77
        if(!empty($_GET['jxncls']))
78
        {
79
            $this->sRequestedClass = trim($_GET['jxncls']);
80
        }
81
        if(!empty($_GET['jxnmthd']))
82
        {
83
            $this->sRequestedMethod = trim($_GET['jxnmthd']);
84
        }
85
        if(!empty($_POST['jxncls']))
86
        {
87
            $this->sRequestedClass = trim($_POST['jxncls']);
88
        }
89
        if(!empty($_POST['jxnmthd']))
90
        {
91
            $this->sRequestedMethod = trim($_POST['jxnmthd']);
92
        }
93
    }
94
95
    /**
96
     * Return the name of this plugin
97
     *
98
     * @return string
99
     */
100
    public function getName()
101
    {
102
        return Jaxon::CALLABLE_CLASS;
103
    }
104
105
    /**
106
     * Return the target class and method
107
     *
108
     * @return Target|null
109
     */
110
    public function getTarget()
111
    {
112
        if(!$this->sRequestedClass || !$this->sRequestedMethod)
113
        {
114
            return null;
115
        }
116
        return Target::makeClass($this->sRequestedClass, $this->sRequestedMethod);
117
    }
118
119
    /**
120
     * Register a callable class
121
     *
122
     * @param string        $sType          The type of request handler being registered
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter name; 10 found
Loading history...
123
     * @param string        $sClassName     The name of the class being registered
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
124
     * @param array|string  $aOptions       The associated options
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 2 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
125
     *
126
     * @return boolean
127
     */
128
    public function register($sType, $sClassName, $aOptions)
129
    {
130
        $sType = trim($sType);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $sType. This often makes code more readable.
Loading history...
131
        if($sType != $this->getName())
132
        {
133
            return false;
134
        }
135
136
        if(!is_string($sClassName))
137
        {
138
            throw new \Jaxon\Exception\Error($this->trans('errors.objects.invalid-declaration'));
139
        }
140
        if(is_string($aOptions))
141
        {
142
            $aOptions = ['include' => $aOptions];
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $aOptions. This often makes code more readable.
Loading history...
143
        }
144
        if(!is_array($aOptions))
145
        {
146
            throw new \Jaxon\Exception\Error($this->trans('errors.objects.invalid-declaration'));
147
        }
148
149
        $sClassName = trim($sClassName);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $sClassName. This often makes code more readable.
Loading history...
150
        $this->xRegistry->addClass($sClassName, $aOptions);
151
152
        return true;
153
    }
154
155
    /**
156
     * Find the options associated with a registered class name
157
     *
158
     * @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...
159
     *
160
     * @return array|null
161
     */
162
    public function getClassOptions($sClassName)
163
    {
164
        // Find options for a class registered with namespace
165
        $aOptions = $this->xRegistry->getClassOptions($sClassName);
166
        if($aOptions !== null)
167
        {
168
            return $aOptions;
169
        }
170
171
        // Without namespace, we need to parse all classes to be able to find one.
172
        $this->xRegistry->parseDirectories();
173
174
        // Find options for a class registered with namespace
175
        return $this->xRepository->getClassOptions($sClassName);
176
    }
177
178
    /**
179
     * Find a callable object by class name
180
     *
181
     * @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...
182
     *
183
     * @return object
184
     */
185
    public function getCallableObject($sClassName)
186
    {
187
        // Replace all separators ('.' and '_') with antislashes, and remove the antislashes
188
        // at the beginning and the end of the class name.
189
        $sClassName = (string)$sClassName;
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $sClassName. This often makes code more readable.
Loading history...
190
        $sClassName = trim(str_replace('.', '\\', $sClassName), '\\');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $sClassName. This often makes code more readable.
Loading history...
191
        if($this->xRegistry->bUsingUnderscore)
192
        {
193
            $sClassName = trim(str_replace('_', '\\', $sClassName), '\\');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $sClassName. This often makes code more readable.
Loading history...
194
        }
195
196
        // Check if the callable object was already created.
197
        $aCallableObjects = $this->xRepository->getCallableObjects();
198
        if(key_exists($sClassName, $aCallableObjects))
199
        {
200
            return $aCallableObjects[$sClassName];
201
        }
202
203
        $aOptions = $this->getClassOptions($sClassName);
204
        if($aOptions === null)
205
        {
206
            return null;
207
        }
208
209
        return $this->xRepository->getCallableObject($sClassName, $aOptions);
210
    }
211
212
    /**
213
     * Create callable objects for all registered namespaces
214
     *
215
     * @return void
216
     */
217
    protected function createCallableObjects()
218
    {
219
        $this->xRegistry->parseDirectories();
220
        $this->xRegistry->parseNamespaces();
221
222
        // Create callable objects for registered directories
223
        foreach($this->xRepository->getClasses() as $sClassName => $aClassOptions)
224
        {
225
            $this->getCallableObject($sClassName, $aClassOptions);
0 ignored issues
show
Unused Code introduced by
The call to CallableClass::getCallableObject() has too many arguments starting with $aClassOptions.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
226
        }
227
    }
228
229
    /**
230
     * Generate a hash for the registered callable objects
231
     *
232
     * @return string
233
     */
234
    public function generateHash()
235
    {
236
        $this->createCallableObjects();
237
        $aNamespaces = $this->xRepository->getNamespaces();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 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...
238
        $aCallableObjects = $this->xRepository->getCallableObjects();
239
        $sHash = '';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 12 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...
240
241
        foreach($aNamespaces as $sNamespace => $aOptions)
242
        {
243
            $sHash .= $sNamespace . $aOptions['separator'];
244
        }
245
        foreach($aCallableObjects as $sClassName => $xCallableObject)
246
        {
247
            $sHash .= $sClassName . implode('|', $xCallableObject->getMethods());
248
        }
249
250
        return md5($sHash);
251
    }
252
253
    /**
254
     * Generate client side javascript code for the registered callable objects
255
     *
256
     * @return string
257
     */
258
    public function getScript()
259
    {
260
        $this->createCallableObjects();
261
        $aNamespaces = $this->xRepository->getNamespaces();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 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...
262
        $aCallableObjects = $this->xRepository->getCallableObjects();
263
        $aCallableOptions = $this->xRepository->getCallableOptions();
264
        $sPrefix = $this->getOption('core.prefix.class');
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...
265
        $aJsClasses = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 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...
266
        $sCode = '';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 12 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...
267
268
        $xCallableClass = new \ReflectionClass(UserCallableClass::class);
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...
269
        $aCallableMethods = [];
270
        foreach($xCallableClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $xMethod)
271
        {
272
            $aCallableMethods[] = $xMethod->getName();
273
        }
274
275
        foreach(array_keys($aNamespaces) as $sNamespace)
276
        {
277
            $offset = 0;
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...
278
            $sJsNamespace = str_replace('\\', '.', $sNamespace);
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 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...
279
            $sJsNamespace .= '.Null'; // This is a sentinel. The last token is not processed in the while loop.
280
            while(($dotPosition = strpos($sJsNamespace, '.', $offset)) !== false)
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
281
            {
282
                $sJsClass = substr($sJsNamespace, 0, $dotPosition);
283
                // Generate code for this object
284
                if(!key_exists($sJsClass, $aJsClasses))
285
                {
286
                    $sCode .= "$sPrefix$sJsClass = {};\n";
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...
287
                    $aJsClasses[$sJsClass] = $sJsClass;
288
                }
289
                $offset = $dotPosition + 1;
290
            }
291
        }
292
293
        foreach($aCallableObjects as $sClassName => $xCallableObject)
294
        {
295
            $aConfig = $aCallableOptions[$sClassName];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 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...
296
            $aCommonConfig = key_exists('*', $aConfig) ? $aConfig['*'] : [];
297
298
            $aProtectedMethods = is_subclass_of($sClassName, UserCallableClass::class) ? $aCallableMethods : [];
299
            $aMethods = [];
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...
300
            foreach($xCallableObject->getMethods() as $sMethodName)
301
            {
302
                // Don't export methods of the CallableClass class
303
                if(in_array($sMethodName, $aProtectedMethods))
304
                {
305
                    continue;
306
                }
307
                // Specific options for this method
308
                $aMethodConfig = key_exists($sMethodName, $aConfig) ?
0 ignored issues
show
Coding Style introduced by
Expected 1 space after "?"; newline found
Loading history...
309
                    array_merge($aCommonConfig, $aConfig[$sMethodName]) : $aCommonConfig;
310
                $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...
311
                    'name' => $sMethodName,
312
                    'config' => $aMethodConfig,
313
                ];
314
            }
315
316
            $sCode .= $this->render('jaxon::support/object.js', [
317
                'sPrefix' => $sPrefix,
318
                'sClass' => $xCallableObject->getJsName(),
319
                'aMethods' => $aMethods,
320
            ]);
321
        }
322
323
        return $sCode;
324
    }
325
326
    /**
327
     * Check if this plugin can process the incoming Jaxon request
328
     *
329
     * @return boolean
330
     */
331
    public function canProcessRequest()
332
    {
333
        // Check the validity of the class name
334
        if(($this->sRequestedClass !== null && !$this->validateClass($this->sRequestedClass)) ||
335
            ($this->sRequestedMethod !== null && !$this->validateMethod($this->sRequestedMethod)))
336
        {
337
            $this->sRequestedClass = null;
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 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...
338
            $this->sRequestedMethod = null;
339
        }
340
        return ($this->sRequestedClass !== null && $this->sRequestedMethod !== null);
341
    }
342
343
    /**
344
     * Process the incoming Jaxon request
345
     *
346
     * @return boolean
347
     */
348
    public function processRequest()
349
    {
350
        if(!$this->canProcessRequest())
351
        {
352
            return false;
353
        }
354
355
        // Find the requested method
356
        $xCallableObject = $this->getCallableObject($this->sRequestedClass);
357
        if(!$xCallableObject || !$xCallableObject->hasMethod($this->sRequestedMethod))
358
        {
359
            // Unable to find the requested object or method
360
            throw new \Jaxon\Exception\Error($this->trans('errors.objects.invalid',
361
                ['class' => $this->sRequestedClass, 'method' => $this->sRequestedMethod]));
362
        }
363
364
        // Call the requested method
365
        $di = jaxon()->di();
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...
366
        $aArgs = $di->getRequestHandler()->processArguments();
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...
367
        $xResponse = $xCallableObject->call($this->sRequestedMethod, $aArgs);
368
        if(($xResponse))
369
        {
370
            $di->getResponseManager()->append($xResponse);
371
        }
372
        return true;
373
    }
374
}
375