Passed
Push — master ( 7c83a0...cd350b )
by Thierry
02:08
created

CodeGenerator::getJs()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 12
nop 0
dl 0
loc 33
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * CodeGenerator.php - Jaxon code generator
5
 *
6
 * Generate HTML, CSS and Javascript code for Jaxon.
7
 *
8
 * @package jaxon-core
0 ignored issues
show
Coding Style introduced by
Package name "jaxon-core" is not valid; consider "Jaxoncore" instead
Loading history...
9
 * @author Thierry Feuzeu <[email protected]>
10
 * @copyright 2016 Thierry Feuzeu <[email protected]>
11
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
12
 * @link https://github.com/jaxon-php/jaxon-core
13
 */
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...
14
15
namespace Jaxon\Plugin\Code;
16
17
use Jaxon\Jaxon;
18
use Jaxon\Plugin\Plugin;
19
use Jaxon\Utils\Config\Config;
20
use Jaxon\Utils\File\Minifier;
21
use Jaxon\Utils\Http\UriDetector;
22
use Jaxon\Utils\Http\UriException;
23
use Jaxon\Utils\Template\Engine as TemplateEngine;
24
25
use function ksort;
26
use function md5;
27
use function rtrim;
28
use function is_file;
29
use function file_put_contents;
30
use function is_subclass_of;
31
32
class CodeGenerator
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CodeGenerator
Loading history...
33
{
34
    /**
35
     * @var Jaxon
36
     */
37
    private $jaxon;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
38
39
    /**
40
     * @var Config
41
     */
42
    protected $xConfig;
43
44
    /**
45
     * @var UriDetector
46
     */
47
    private $xUriDetector;
48
49
    /**
50
     * @var Minifier
51
     */
52
    private $xMinifier;
53
54
    /**
55
     * Default library URL
56
     *
57
     * @var string
58
     */
59
    const JS_LIB_URL = 'https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist';
60
61
    /**
62
     * The class names of objects that generate code
63
     *
64
     * @var array<string>
65
     */
66
    protected $aClassNames = [];
67
68
    /**
69
     * The Jaxon template engine
70
     *
71
     * @var TemplateEngine
72
     */
73
    protected $xTemplateEngine;
74
75
    /**
76
     * The constructor
77
     *
78
     * @param Jaxon $jaxon
0 ignored issues
show
Coding Style introduced by
Expected 10 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
79
     * @param Config $xConfig
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...
80
     * @param UriDetector $xUriDetector
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...
81
     * @param TemplateEngine $xTemplateEngine    The template engine
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
82
     * @param Minifier $xMinifier
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
83
     */
84
    public function __construct(Jaxon $jaxon, Config $xConfig, UriDetector $xUriDetector,
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
85
        TemplateEngine $xTemplateEngine, Minifier $xMinifier)
86
    {
87
        $this->jaxon = $jaxon;
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...
88
        $this->xConfig = $xConfig;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
89
        $this->xUriDetector = $xUriDetector;
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...
90
        $this->xTemplateEngine = $xTemplateEngine;
91
        $this->xMinifier = $xMinifier;
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...
92
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
93
94
    /**
95
     * Get the mappings between previous and current config options
96
     *
97
     * @return array
98
     */
99
    private function getOptionVars(): array
100
    {
101
        return [
102
            'sResponseType'             => 'JSON',
103
            'sVersion'                  => $this->xConfig->getOption('core.version'),
104
            'sLanguage'                 => $this->xConfig->getOption('core.language'),
105
            'bLanguage'                 => $this->xConfig->hasOption('core.language'),
106
            'sRequestURI'               => $this->xConfig->getOption('core.request.uri'),
107
            'sDefaultMode'              => $this->xConfig->getOption('core.request.mode'),
108
            'sDefaultMethod'            => $this->xConfig->getOption('core.request.method'),
109
            'sCsrfMetaName'             => $this->xConfig->getOption('core.request.csrf_meta'),
110
            'bDebug'                    => $this->xConfig->getOption('core.debug.on'),
111
            'bVerboseDebug'             => $this->xConfig->getOption('core.debug.verbose'),
112
            'sDebugOutputID'            => $this->xConfig->getOption('core.debug.output_id'),
113
            'nResponseQueueSize'        => $this->xConfig->getOption('js.lib.queue_size'),
114
            'sStatusMessages'           => $this->xConfig->getOption('js.lib.show_status') ? 'true' : 'false',
115
            'sWaitCursor'               => $this->xConfig->getOption('js.lib.show_cursor') ? 'true' : 'false',
116
            'sDefer'                    => $this->xConfig->getOption('js.app.options', ''),
117
        ];
118
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
119
120
    /**
121
     * Render a template in the 'plugins' subdir
122
     *
123
     * @param string $sTemplate    The template filename
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
124
     * @param array $aVars    The template variables
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 4 found
Loading history...
125
     *
126
     * @return string
127
     */
128
    private function _render(string $sTemplate, array $aVars = []): string
129
    {
130
        $aVars['sJsOptions'] = $this->xConfig->getOption('js.app.options', '');
131
        return $this->xTemplateEngine->render("jaxon::plugins/$sTemplate", $aVars);
132
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
133
134
    /**
135
     * Add a new generator to the list
136
     *
137
     * @param string $sClassName    The code generator class
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
138
     * @param int $nPriority    The desired priority, used to order the plugins
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
139
     *
140
     * @return void
141
     */
142
    public function addGenerator(string $sClassName, int $nPriority)
143
    {
144
        while(isset($this->aClassNames[$nPriority]))
145
        {
146
            $nPriority++;
147
        }
148
        $this->aClassNames[$nPriority] = $sClassName;
149
        // Sort the array by ascending keys
150
        ksort($this->aClassNames);
151
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
152
153
    /**
154
     * Generate a hash for all the javascript code generated by the library
155
     *
156
     * @return string
157
     */
158
    private function getHash(): string
159
    {
160
        $sHash = $this->jaxon->getVersion();
161
        foreach($this->aClassNames as $sClassName)
162
        {
163
            $xGenerator = $this->jaxon->di()->get($sClassName);
164
            $sHash .= $xGenerator->getHash();
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...
165
        }
166
        return md5($sHash);
167
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
168
169
    /**
170
     * Check if all plugins assets shall be included in Jaxon generated code.
171
     *
172
     * @return bool
173
     */
174
    protected function shallIncludeAllAssets(): bool
175
    {
176
        return $this->xConfig->getOption('assets.include.all', true);
177
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
178
179
    /**
180
     * Check if the assets of this plugin shall be included in Jaxon generated code.
181
     *
182
     * @param Plugin $xPlugin
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
183
     *
184
     * @return bool
185
     */
186
    protected function shallIncludeAssets(Plugin $xPlugin): bool
187
    {
188
        $sPluginOptionName = 'assets.include.' . $xPlugin->getName();
189
        return $this->xConfig->getOption($sPluginOptionName, true);
190
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
191
192
    /**
193
     * Get the HTML tags to include Jaxon CSS code and files into the page
194
     *
195
     * @return string
196
     */
197
    public function getCss(): string
198
    {
199
        $bIncludeAllAssets = $this->shallIncludeAllAssets();
200
        $sCssCode = '';
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...
201
        foreach($this->aClassNames as $sClassName)
202
        {
203
            $xGenerator = $this->jaxon->di()->get($sClassName);
204
            if(is_subclass_of($xGenerator, Plugin::class) &&
205
                (!$this->shallIncludeAssets($xGenerator) || !$bIncludeAllAssets))
206
            {
207
                continue;
208
            }
209
            $sCssCode = rtrim($sCssCode, " \n") . "\n" . $xGenerator->getCss();
210
        }
211
        return rtrim($sCssCode, " \n") . "\n";
212
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
213
214
    /**
215
     * Get the HTML tags to include Jaxon javascript files into the page
216
     *
217
     * @return string
218
     */
219
    public function getJs(): string
220
    {
221
        $sJsExtension = $this->xConfig->getOption('js.app.minify') ? '.min.js' : '.js';
222
223
        // The URI for the javascript library files
224
        $sJsLibUri = rtrim($this->xConfig->getOption('js.lib.uri', self::JS_LIB_URL), '/') . '/';
225
        // Add component files to the javascript file array;
226
        $aJsFiles = [$sJsLibUri . 'jaxon.core' . $sJsExtension];
227
        if($this->xConfig->getOption('core.debug.on'))
228
        {
229
            $sLanguage = $this->xConfig->getOption('core.language');
230
            $aJsFiles[] = $sJsLibUri . 'jaxon.debug' . $sJsExtension;
231
            $aJsFiles[] = $sJsLibUri . 'lang/jaxon.' . $sLanguage . $sJsExtension;
232
            /*if($this->xConfig->getOption('core.debug.verbose'))
0 ignored issues
show
Coding Style introduced by
Block comment text must start on a new line
Loading history...
233
            {
234
                $aJsFiles[] = $sJsLibUri . 'jaxon.verbose' . $sJsExtension;
235
            }*/
236
        }
237
        $sJsFiles = $this->_render('includes.js', ['aUrls' => $aJsFiles]);
238
239
        $bIncludeAllAssets = $this->shallIncludeAllAssets();
240
        $sJsCode = '';
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...
241
        foreach($this->aClassNames as $sClassName)
242
        {
243
            $xGenerator = $this->jaxon->di()->get($sClassName);
244
            if(is_subclass_of($xGenerator, Plugin::class) &&
245
                (!$this->shallIncludeAssets($xGenerator) || !$bIncludeAllAssets))
246
            {
247
                continue;
248
            }
249
            $sJsCode = rtrim($sJsCode, " \n") . "\n" . $xGenerator->getJs();
250
        }
251
        return $sJsFiles . "\n" . rtrim($sJsCode, " \n") . "\n";
252
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
253
254
    /**
255
     * Get the javascript code to be sent to the browser
256
     *
257
     * @return string
258
     */
259
    private function _getScript(): string
260
    {
261
        $sScript = '';
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
        $sReadyScript = '';
263
        foreach($this->aClassNames as $sClassName)
264
        {
265
            $xGenerator = $this->jaxon->di()->get($sClassName);
266
            $sScript .= rtrim($xGenerator->getScript(), " \n") . "\n";
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...
267
            if($xGenerator->readyEnabled() && !$xGenerator->readyInlined())
268
            {
269
                // Ready code which can nbe exported to an external file.
270
                $sReadyScript .= rtrim($xGenerator->getReadyScript(), " \n") . "\n";
271
            }
272
        }
273
274
        // These three parts are always rendered together
275
        $aConfigVars = $this->getOptionVars();
276
        return $this->_render('config.js', $aConfigVars) . "\n" . $sScript . "\n" .
277
            $this->_render('ready.js', ['sScript' => $sReadyScript]);
278
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
279
280
    /**
281
     * Get the javascript code to include directly in HTML
282
     *
283
     * @return string
284
     */
285
    private function _getInlineScript(): string
286
    {
287
        $sScript = '';
288
        foreach($this->aClassNames as $sClassName)
289
        {
290
            $xGenerator = $this->jaxon->di()->get($sClassName);
291
            if($xGenerator->readyEnabled() && $xGenerator->readyInlined())
292
            {
293
                // Ready code which must be inlined in HTML.
294
                $sScript .= rtrim($xGenerator->getReadyScript(), " \n") . "\n";
295
            }
296
        }
297
        return $this->_render('ready.js', ['sScript' => $sScript]);
298
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
299
300
    /**
301
     * Get the javascript file name
302
     *
303
     * @return string
304
     */
305
    private function getJsFileName(): string
306
    {
307
        // Check config options
308
        // - The js.app.export option must be set to true
309
        // - The js.app.uri and js.app.dir options must be set to non null values
310
        if(!$this->xConfig->getOption('js.app.export', false) ||
311
            !$this->xConfig->getOption('js.app.uri', false) ||
312
            !$this->xConfig->getOption('js.app.dir', false))
313
        {
314
            return '';
315
        }
316
317
        // The file name
318
        return $this->xConfig->getOption('js.app.file', $this->getHash());
319
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
320
321
    /**
322
     * Write javascript files and return the corresponding URI
323
     *
324
     * @param string $sJsDirectory
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
325
     * @param string $sJsFileName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
326
     *
327
     * @return string
328
     */
329
    public function createFiles(string $sJsDirectory, string $sJsFileName): string
330
    {
331
        // Check dir access
332
        // - The js.app.dir must be writable
333
        if(!$sJsFileName || !is_dir($sJsDirectory) || !is_writable($sJsDirectory))
334
        {
335
            return '';
336
        }
337
338
        $sOutFile = $sJsFileName . '.js';
339
        $sMinFile = $sJsFileName . '.min.js';
340
        if(!is_file($sJsDirectory . $sOutFile))
341
        {
342
            if(!file_put_contents($sJsDirectory . $sOutFile, $this->_getScript()))
343
            {
344
                return '';
345
            }
346
        }
347
        if(($this->xConfig->getOption('js.app.minify')) && !is_file($sJsDirectory . $sMinFile))
348
        {
349
            if(!$this->xMinifier->minify($sJsDirectory . $sOutFile, $sJsDirectory . $sMinFile))
350
            {
351
                return '';
352
            }
353
        }
354
355
        $sJsAppUri = rtrim($this->xConfig->getOption('js.app.uri'), '/') . '/';
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...
Bug introduced by
It seems like $this->xConfig->getOption('js.app.uri') can also be of type null; however, parameter $string of rtrim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

355
        $sJsAppUri = rtrim(/** @scrutinizer ignore-type */ $this->xConfig->getOption('js.app.uri'), '/') . '/';
Loading history...
356
        $sJsExtension = $this->xConfig->getOption('js.app.minify') ? '.min.js' : '.js';
357
        return $sJsAppUri . $sJsFileName . $sJsExtension;
358
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
359
360
    /**
361
     * Get the javascript code to be sent to the browser
362
     *
363
     * @param bool $bIncludeJs    Also get the JS files
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 4 found
Loading history...
364
     * @param bool $bIncludeCss    Also get the CSS files
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
365
     *
366
     * @return string
367
     * @throws UriException
368
     */
369
    public function getScript(bool $bIncludeJs, bool $bIncludeCss): string
370
    {
371
        if(!$this->xConfig->getOption('core.request.uri'))
372
        {
373
            $this->xConfig->setOption('core.request.uri', $this->xUriDetector->detect($_SERVER));
374
        }
375
376
        $sScript = '';
377
        if(($bIncludeCss))
378
        {
379
            $sScript .= $this->getCss() . "\n";
380
        }
381
        if(($bIncludeJs))
382
        {
383
            $sScript .= $this->getJs() . "\n";
384
        }
385
386
        $sJsDirectory = rtrim($this->xConfig->getOption('js.app.dir'), '/') . '/';
0 ignored issues
show
Bug introduced by
It seems like $this->xConfig->getOption('js.app.dir') can also be of type null; however, parameter $string of rtrim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

386
        $sJsDirectory = rtrim(/** @scrutinizer ignore-type */ $this->xConfig->getOption('js.app.dir'), '/') . '/';
Loading history...
387
        $sUrl = $this->createFiles($sJsDirectory, $this->getJsFileName());
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
388
        if(($sUrl))
389
        {
390
            return $sScript . $this->_render('include.js', ['sUrl' => $sUrl]) . "\n" .
391
                $this->_render('wrapper.js', ['sScript' => $this->_getInlineScript()]);
392
        }
393
394
        return $sScript . $this->_render('wrapper.js', [
395
            'sScript' => $this->_getScript() . "\n" . $this->_getInlineScript()
396
        ]);
397
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
398
}
399