Passed
Push — master ( b34d93...aea763 )
by Thierry
03:02 queued 24s
created

CallableClassPlugin   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 282
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 29
eloc 88
c 0
b 0
f 0
dl 0
loc 282
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 5 1
A getCallableScript() 0 7 2
A getCallable() 0 3 1
A checkOptions() 0 15 4
A processRequest() 0 31 5
A getScript() 0 15 2
A getName() 0 3 1
A getHash() 0 4 1
A __construct() 0 18 2
A canProcessRequest() 0 9 4
A setTarget() 0 10 2
A getNamespacesScript() 0 23 4
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
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
21
22
namespace Jaxon\Plugin\Request\CallableClass;
23
24
use Jaxon\Jaxon;
25
use Jaxon\CallableClass;
26
use Jaxon\Di\Container;
27
use Jaxon\Exception\RequestException;
28
use Jaxon\Exception\SetupException;
29
use Jaxon\Plugin\RequestPlugin;
30
use Jaxon\Request\Handler\ParameterReader;
31
use Jaxon\Request\Target;
32
use Jaxon\Request\Validator;
33
use Jaxon\Response\ResponseInterface;
34
use Jaxon\Utils\Template\TemplateEngine;
35
use Jaxon\Utils\Translation\Translator;
36
use Psr\Http\Message\ServerRequestInterface;
37
38
use ReflectionClass;
39
use ReflectionException;
40
use ReflectionMethod;
41
42
use function is_array;
43
use function is_string;
44
use function is_subclass_of;
45
use function md5;
46
use function strlen;
47
use function trim;
48
use function uksort;
49
50
class CallableClassPlugin extends RequestPlugin
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CallableClassPlugin
Loading history...
51
{
52
    /**
53
     * @var string
54
     */
55
    protected $sPrefix;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
56
57
    /**
58
     * @var Container
59
     */
60
    protected $di;
61
62
    /**
63
     * The parameter reader
64
     *
65
     * @var ParameterReader
66
     */
67
    protected $xParameterReader;
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 methods that must not be exported to js
102
     *
103
     * @var array
104
     */
105
    protected $aProtectedMethods = [];
106
107
    /**
108
     * The class constructor
109
     *
110
     * @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...
111
     * @param Container $di
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 10 spaces after parameter type; 1 found
Loading history...
112
     * @param ParameterReader $xParameterReader
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
113
     * @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...
114
     * @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...
115
     * @param TemplateEngine $xTemplateEngine
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
116
     * @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; 1 found
Loading history...
117
     * @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; 1 found
Loading history...
118
     */
119
    public function __construct(string $sPrefix, Container $di, ParameterReader $xParameterReader,
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
120
        CallableRegistry $xRegistry, CallableRepository $xRepository,
121
        TemplateEngine $xTemplateEngine, Translator $xTranslator, Validator $xValidator)
122
    {
123
        $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...
124
        $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...
125
        $this->xParameterReader = $xParameterReader;
126
        $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...
127
        $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...
128
        $this->xTemplateEngine = $xTemplateEngine;
129
        $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...
130
        $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...
131
132
        // The methods of the CallableClass class must not be exported
133
        $xCallableClass = new ReflectionClass(CallableClass::class);
134
        foreach($xCallableClass->getMethods(ReflectionMethod::IS_PUBLIC) as $xMethod)
135
        {
136
            $this->aProtectedMethods[] = $xMethod->getName();
137
        }
138
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
139
140
    /**
141
     * @inheritDoc
142
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
143
    public function getName(): string
144
    {
145
        return Jaxon::CALLABLE_CLASS;
146
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
147
148
    /**
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...
149
     * @inheritDoc
150
     * @throws SetupException
151
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
152
    public function checkOptions(string $sCallable, $xOptions): array
153
    {
154
        if(!$this->xValidator->validateClass(trim($sCallable)))
155
        {
156
            throw new SetupException($this->xTranslator->trans('errors.objects.invalid-declaration'));
157
        }
158
        if(is_string($xOptions))
159
        {
160
            $xOptions = ['include' => $xOptions];
161
        }
162
        elseif(!is_array($xOptions))
163
        {
164
            throw new SetupException($this->xTranslator->trans('errors.objects.invalid-declaration'));
165
        }
166
        return $xOptions;
167
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
168
169
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $sType should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $sCallable should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $aOptions should have a doc-comment as per coding-style.
Loading history...
170
     * @inheritDoc
171
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
172
    public function register(string $sType, string $sCallable, array $aOptions): bool
173
    {
174
        $sClassName = trim($sCallable);
175
        $this->xRepository->addClass($sClassName, $aOptions);
176
        return true;
177
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
178
179
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $sCallable should have a doc-comment as per coding-style.
Loading history...
180
     * @inheritDoc
181
     * @throws SetupException
182
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
183
    public function getCallable(string $sCallable)
184
    {
185
        return $this->xRegistry->getCallableObject($sCallable);
186
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
187
188
    /**
189
     * @inheritDoc
190
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
191
    public function getHash(): string
192
    {
193
        $this->xRegistry->parseCallableClasses();
194
        return md5($this->xRepository->getHash());
195
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
196
197
    /**
198
     * Generate client side javascript code for namespaces
199
     *
200
     * @return string
201
     */
202
    private function getNamespacesScript(): string
203
    {
204
        $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...
205
        $aJsClasses = [];
206
        $aNamespaces = $this->xRepository->getNamespaces();
207
        foreach($aNamespaces as $sNamespace)
208
        {
209
            $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...
210
            $sJsNamespace = str_replace('\\', '.', $sNamespace);
211
            $sJsNamespace .= '.Null'; // This is a sentinel. The last token is not processed in the while loop.
212
            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...
213
            {
214
                $sJsClass = substr($sJsNamespace, 0, $dotPosition);
215
                // Generate code for this object
216
                if(!isset($aJsClasses[$sJsClass]))
217
                {
218
                    $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...
219
                    $aJsClasses[$sJsClass] = $sJsClass;
220
                }
221
                $offset = $dotPosition + 1;
222
            }
223
        }
224
        return $sCode;
225
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
226
227
    /**
228
     * Generate client side javascript code for a callable class
229
     *
230
     * @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...
231
     * @param CallableObject $xCallableObject The corresponding callable object
232
     *
233
     * @return string
234
     */
235
    private function getCallableScript(string $sClassName, CallableObject $xCallableObject): string
236
    {
237
        $aProtectedMethods = is_subclass_of($sClassName, CallableClass::class) ? $this->aProtectedMethods : [];
238
        return $this->xTemplateEngine->render('jaxon::callables/object.js', [
239
            'sPrefix' => $this->sPrefix,
240
            'sClass' => $xCallableObject->getJsName(),
241
            'aMethods' => $xCallableObject->getMethods($aProtectedMethods),
242
        ]);
243
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
244
245
    /**
246
     * Generate client side javascript code for the registered callable objects
247
     *
248
     * @return string
249
     * @throws SetupException
250
     */
251
    public function getScript(): string
252
    {
253
        $this->xRegistry->parseCallableClasses();
254
        $aCallableObjects = $this->xRepository->getCallableObjects();
255
        // Sort the options by key length asc
256
        uksort($aCallableObjects, function($name1, $name2) {
257
            return strlen($name1) - strlen($name2);
258
        });
259
260
        $sCode = $this->getNamespacesScript();
261
        foreach($aCallableObjects as $sClassName => $xCallableObject)
262
        {
263
            $sCode .= $this->getCallableScript($sClassName, $xCallableObject);
264
        }
265
        return $sCode;
266
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
267
268
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $xRequest should have a doc-comment as per coding-style.
Loading history...
269
     * @inheritDoc
270
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
271
    public static function canProcessRequest(ServerRequestInterface $xRequest): bool
272
    {
273
        $aBody = $xRequest->getParsedBody();
274
        if(is_array($aBody))
275
        {
276
            return isset($aBody['jxncls']) && isset($aBody['jxnmthd']);
277
        }
278
        $aParams = $xRequest->getQueryParams();
279
        return isset($aParams['jxncls']) && isset($aParams['jxnmthd']);
280
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
281
282
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $xRequest should have a doc-comment as per coding-style.
Loading history...
283
     * @inheritDoc
284
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
285
    public function setTarget(ServerRequestInterface $xRequest)
286
    {
287
        $aBody = $xRequest->getParsedBody();
288
        if(is_array($aBody))
289
        {
290
            $this->xTarget = Target::makeClass(trim($aBody['jxncls']), trim($aBody['jxnmthd']));
291
            return;
292
        }
293
        $aParams = $xRequest->getQueryParams();
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...
294
        $this->xTarget = Target::makeClass(trim($aParams['jxncls']), trim($aParams['jxnmthd']));
295
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
296
297
    /**
298
     * @inheritDoc
299
     * @throws RequestException
300
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
301
    public function processRequest(): ?ResponseInterface
302
    {
303
        $sRequestedClass = $this->xTarget->getClassName();
304
        $sRequestedMethod = $this->xTarget->getMethodName();
305
306
        if(!$this->xValidator->validateClass($sRequestedClass) ||
307
            !$this->xValidator->validateMethod($sRequestedMethod))
308
        {
309
            // Unable to find the requested object or method
310
            throw new RequestException($this->xTranslator->trans('errors.objects.invalid',
311
                ['class' => $sRequestedClass, 'method' => $sRequestedMethod]));
312
        }
313
314
        // Call the requested method
315
        try
316
        {
317
            $xCallableObject = $this->xRegistry->getCallableObject($sRequestedClass);
318
            return $xCallableObject->call($sRequestedMethod, $this->xParameterReader->args());
319
        }
320
        catch(ReflectionException $e)
321
        {
322
            // Unable to find the requested class or method
323
            $this->di->logger()->error($e->getMessage());
324
            throw new RequestException($this->xTranslator->trans('errors.objects.invalid',
325
                ['class' => $sRequestedClass, 'method' => $sRequestedMethod]));
326
        }
327
        catch(SetupException $e)
328
        {
329
            // Unable to get the callable object
330
            throw new RequestException($this->xTranslator->trans('errors.objects.invalid',
331
                ['class' => $sRequestedClass, 'method' => $sRequestedMethod]));
332
        }
333
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
334
}
335