Passed
Push — master ( eb1365...37d9b5 )
by Thierry
01:52
created

CallableClassPlugin::processRequest()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 35
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 6
nop 0
dl 0
loc 35
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * CallableClassPlugin.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
Missing @category tag in file comment
Loading history...
Coding Style introduced by
PHP version not specified
Loading history...
21
22
namespace Jaxon\Request\Plugin\CallableClass;
23
24
use Jaxon\Jaxon;
25
use Jaxon\CallableClass;
26
use Jaxon\Plugin\RequestPlugin;
27
use Jaxon\Request\Handler\RequestHandler;
28
use Jaxon\Request\Target;
29
use Jaxon\Request\Validator;
30
use Jaxon\Response\ResponseManager;
31
use Jaxon\Utils\Template\Engine as TemplateEngine;
32
use Jaxon\Utils\Translation\Translator;
33
use Jaxon\Exception\RequestException;
34
use Jaxon\Exception\SetupException;
35
36
use ReflectionClass;
37
use ReflectionMethod;
38
use ReflectionException;
39
40
use function is_array;
41
use function is_string;
42
use function is_subclass_of;
43
use function md5;
44
use function strlen;
45
use function trim;
46
use function uksort;
47
48
class CallableClassPlugin extends RequestPlugin
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CallableClassPlugin
Loading history...
49
{
50
    /**
51
     * @var string
52
     */
53
    protected $sPrefix;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
54
55
    /**
56
     * The request handler
57
     *
58
     * @var RequestHandler
59
     */
60
    protected $xRequestHandler;
61
62
    /**
63
     * The response manager
64
     *
65
     * @var ResponseManager
66
     */
67
    protected $xResponseManager;
68
69
    /**
70
     * The callable registry
71
     *
72
     * @var CallableRegistry
73
     */
74
    protected $xRegistry;
75
76
    /**
77
     * The callable repository
78
     *
79
     * @var CallableRepository
80
     */
81
    protected $xRepository;
82
83
    /**
84
     * The request data validator
85
     *
86
     * @var Validator
87
     */
88
    protected $xValidator;
89
90
    /**
91
     * @var TemplateEngine
92
     */
93
    protected $xTemplateEngine;
94
95
    /**
96
     * @var Translator
97
     */
98
    protected $xTranslator;
99
100
    /**
101
     * The value of the class parameter of the incoming Jaxon request
102
     *
103
     * @var string
104
     */
105
    protected static $sRequestedClass = '';
106
107
    /**
108
     * The value of the method parameter of the incoming Jaxon request
109
     *
110
     * @var string
111
     */
112
    protected static $sRequestedMethod = '';
113
114
    /**
115
     * The methods that must not be exported to js
116
     *
117
     * @var array
118
     */
119
    protected $aProtectedMethods = [];
120
121
    /**
122
     * The class constructor
123
     *
124
     * @param string  $sPrefix
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 13 spaces after parameter type; 2 found
Loading history...
125
     * @param RequestHandler  $xRequestHandler
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter type; 2 found
Loading history...
126
     * @param ResponseManager  $xResponseManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 2 found
Loading history...
127
     * @param CallableRegistry $xRegistry    The callable class registry
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 8 spaces after parameter name; 4 found
Loading history...
128
     * @param CallableRepository $xRepository    The callable object repository
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 4 found
Loading history...
129
     * @param TemplateEngine  $xTemplateEngine
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 2 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
130
     * @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; 2 found
Loading history...
131
     * @param Validator  $xValidator
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 10 spaces after parameter type; 2 found
Loading history...
132
     */
133
    public function __construct(string $sPrefix, RequestHandler $xRequestHandler,
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
134
        ResponseManager $xResponseManager, CallableRegistry $xRegistry, CallableRepository $xRepository,
135
        TemplateEngine  $xTemplateEngine, Translator $xTranslator, Validator $xValidator)
136
    {
137
        $this->sPrefix = $sPrefix;
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...
138
        $this->xRequestHandler = $xRequestHandler;
139
        $this->xResponseManager = $xResponseManager;
140
        $this->xRegistry = $xRegistry;
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...
141
        $this->xRepository = $xRepository;
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...
142
        $this->xTemplateEngine = $xTemplateEngine;
143
        $this->xTranslator = $xTranslator;
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...
144
        $this->xValidator = $xValidator;
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...
145
146
        // The methods of the CallableClass class must not be exported
147
        $xCallableClass = new ReflectionClass(CallableClass::class);
148
        foreach($xCallableClass->getMethods(ReflectionMethod::IS_PUBLIC) as $xMethod)
149
        {
150
            $this->aProtectedMethods[] = $xMethod->getName();
151
        }
152
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
153
154
    /**
155
     * @inheritDoc
156
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
157
    public function getName(): string
158
    {
159
        return Jaxon::CALLABLE_CLASS;
160
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
161
162
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $sCallable should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $xOptions should have a doc-comment as per coding-style.
Loading history...
163
     * @inheritDoc
164
     * @throws SetupException
165
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
166
    public function checkOptions(string $sCallable, $xOptions): array
167
    {
168
        if(!$this->xValidator->validateClass(trim($sCallable)))
169
        {
170
            throw new SetupException($this->xTranslator->trans('errors.objects.invalid-declaration'));
171
        }
172
        if(is_string($xOptions))
173
        {
174
            $xOptions = ['include' => $xOptions];
175
        }
176
        elseif(!is_array($xOptions))
177
        {
178
            throw new SetupException($this->xTranslator->trans('errors.objects.invalid-declaration'));
179
        }
180
        return $xOptions;
181
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
182
183
    /**
184
     * Register a callable class
185
     *
186
     * @param string $sType    The type of request handler being registered
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 4 found
Loading history...
187
     * @param string $sCallable    The name of the class being registered
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
188
     * @param array $aOptions    The associated options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
189
     *
190
     * @return bool
191
     */
192
    public function register(string $sType, string $sCallable, array $aOptions): bool
193
    {
194
        $sClassName = trim($sCallable);
195
        $this->xRepository->addClass($sClassName, $aOptions);
196
        return true;
197
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
198
199
    /**
200
     * @inheritDoc
201
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
202
    public function getHash(): string
203
    {
204
        $this->xRegistry->parseCallableClasses();
205
        $aNamespaces = $this->xRepository->getNamespaces();
206
        $aClasses = $this->xRepository->getClasses();
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...
207
        $sHash = '';
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...
208
209
        foreach($aNamespaces as $sNamespace => $aOptions)
210
        {
211
            $sHash .= $sNamespace . $aOptions['separator'];
212
        }
213
        foreach($aClasses as $sClassName => $aOptions)
214
        {
215
            $sHash .= $sClassName . $aOptions['timestamp'];
216
        }
217
218
        return md5($sHash);
219
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
220
221
    /**
222
     * Generate client side javascript code for namespaces
223
     *
224
     * @return string
225
     */
226
    private function getNamespacesScript(): string
227
    {
228
        $sCode = '';
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...
229
        $aJsClasses = [];
230
        $aNamespaces = array_keys($this->xRepository->getNamespaces());
231
        foreach($aNamespaces as $sNamespace)
232
        {
233
            $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...
234
            $sJsNamespace = str_replace('\\', '.', $sNamespace);
235
            $sJsNamespace .= '.Null'; // This is a sentinel. The last token is not processed in the while loop.
236
            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...
237
            {
238
                $sJsClass = substr($sJsNamespace, 0, $dotPosition);
239
                // Generate code for this object
240
                if(!isset($aJsClasses[$sJsClass]))
241
                {
242
                    $sCode .= $this->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...
243
                    $aJsClasses[$sJsClass] = $sJsClass;
244
                }
245
                $offset = $dotPosition + 1;
246
            }
247
        }
248
        return $sCode;
249
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
250
251
    /**
252
     * Generate client side javascript code for a callable class
253
     *
254
     * @param string $sClassName
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...
255
     * @param CallableObject $xCallableObject The corresponding callable object
256
     *
257
     * @return string
258
     */
259
    private function getCallableScript(string $sClassName, CallableObject $xCallableObject): string
260
    {
261
        $aProtectedMethods = is_subclass_of($sClassName, CallableClass::class) ? $this->aProtectedMethods : [];
262
        return $this->xTemplateEngine->render('jaxon::callables/object.js', [
263
            'sPrefix' => $this->sPrefix,
264
            'sClass' => $xCallableObject->getJsName(),
265
            'aMethods' => $xCallableObject->getMethods($aProtectedMethods),
266
        ]);
267
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
268
269
    /**
270
     * Generate client side javascript code for the registered callable objects
271
     *
272
     * @return string
273
     * @throws SetupException
274
     */
275
    public function getScript(): string
276
    {
277
        $this->xRegistry->registerCallableClasses();
278
279
        $sCode = $this->getNamespacesScript();
280
281
        $aClassNames = $this->xRepository->getClassNames();
282
        // Sort the options by key length asc
283
        uksort($aClassNames, function($name1, $name2) {
284
            return strlen($name1) - strlen($name2);
285
        });
286
        foreach($aClassNames as $sClassName)
287
        {
288
            $xCallableObject = $this->xRegistry->getCallableObject($sClassName);
289
            $sCode .= $this->getCallableScript($sClassName, $xCallableObject);
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...
290
        }
291
292
        return $sCode;
293
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
294
295
    /**
296
     * @inheritDoc
297
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
298
    public static function canProcessRequest(): bool
299
    {
300
        if(isset($_POST['jxncls']))
301
        {
302
            self::$sRequestedClass = trim($_POST['jxncls']);
303
        }
304
        elseif(isset($_GET['jxncls']))
305
        {
306
            self::$sRequestedClass = trim($_GET['jxncls']);
307
        }
308
        if(isset($_POST['jxnmthd']))
309
        {
310
            self::$sRequestedMethod = trim($_POST['jxnmthd']);
311
        }
312
        elseif(isset($_GET['jxnmthd']))
313
        {
314
            self::$sRequestedMethod = trim($_GET['jxnmthd']);
315
        }
316
        return (self::$sRequestedClass !== '' && self::$sRequestedMethod !== '');
317
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
318
319
    /**
320
     * @inheritDoc
321
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
322
    public function getTarget(): ?Target
323
    {
324
        if(!self::$sRequestedClass || !self::$sRequestedMethod)
325
        {
326
            return null;
327
        }
328
        return Target::makeClass(self::$sRequestedClass, self::$sRequestedMethod);
329
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
330
331
    /**
332
     * @inheritDoc
333
     * @throws RequestException
334
     * @throws SetupException
335
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
336
    public function processRequest(): bool
337
    {
338
        if(!$this->xValidator->validateClass(self::$sRequestedClass) ||
339
            !$this->xValidator->validateMethod(self::$sRequestedMethod))
340
        {
341
            // Unable to find the requested object or method
342
            throw new RequestException($this->xTranslator->trans('errors.objects.invalid',
343
                ['class' => self::$sRequestedClass, 'method' => self::$sRequestedMethod]));
344
        }
345
        // Find the requested method
346
        $xCallableObject = $this->xRegistry->getCallableObject(self::$sRequestedClass);
347
        if(!$xCallableObject || !$xCallableObject->hasMethod(self::$sRequestedMethod))
0 ignored issues
show
introduced by
$xCallableObject is of type Jaxon\Request\Plugin\CallableClass\CallableObject, thus it always evaluated to true.
Loading history...
348
        {
349
            // Unable to find the requested object or method
350
            throw new RequestException($this->xTranslator->trans('errors.objects.invalid',
351
                ['class' => self::$sRequestedClass, 'method' => self::$sRequestedMethod]));
352
        }
353
354
        // Call the requested method
355
        $aArgs = $this->xRequestHandler->processArguments();
356
        try
357
        {
358
            $xResponse = $xCallableObject->call(self::$sRequestedMethod, $aArgs);
359
            if(($xResponse))
360
            {
361
                $this->xResponseManager->append($xResponse);
362
            }
363
        }
364
        catch(ReflectionException $e)
365
        {
366
            // Unable to find the requested class
367
            throw new RequestException($this->xTranslator->trans('errors.objects.invalid',
368
                ['class' => self::$sRequestedClass, 'method' => self::$sRequestedMethod]));
369
        }
370
        return true;
371
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
372
}
373