Passed
Push — master ( 1a06f6...56a418 )
by Thierry
02:34
created

Generator::render()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Generator.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
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
14
15
namespace Jaxon\Plugin\Code;
16
17
use Jaxon\Utils\Template\Engine as TemplateEngine;
18
use Jaxon\Utils\Http\URI;
19
20
use Jaxon\Plugin\Code\Contracts\Generator as GeneratorContract;
21
22
class Generator
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class Generator
Loading history...
23
{
24
    use \Jaxon\Features\Config;
25
    use \Jaxon\Features\Minifier;
26
27
    /**
28
     * The response type.
29
     *
30
     * @var string
31
     */
32
    const RESPONSE_TYPE = 'JSON';
33
34
    /**
35
     * The objects that generate code
36
     *
37
     * @var array<GeneratorContract>
38
     */
39
    protected $aGenerators = [];
40
41
    /**
42
     * The Jaxon template engine
43
     *
44
     * @var TemplateEngine
45
     */
46
    protected $xTemplateEngine;
47
48
    /**
49
     * HTML tags to include CSS code and files into the page
50
     *
51
     * @var string
52
     */
53
    protected $sCssCode = '';
54
55
    /**
56
     * HTML tags to include javascript code and files into the page
57
     *
58
     * @var string
59
     */
60
    protected $sJsCode = '';
61
62
    /**
63
     * Javascript code to include into the page
64
     *
65
     * @var string
66
     */
67
    protected $sJsScript = '';
68
69
    /**
70
     * Javascript code to execute after page load
71
     *
72
     * @var string
73
     */
74
    protected $sJsReadyScript = '';
75
76
    /**
77
     * Javascript code to include in HTML code and execute after page load
78
     *
79
     * @var string
80
     */
81
    protected $sJsInlineScript = '';
82
83
    /**
84
     * Code already generated
85
     *
86
     * @var boolean
87
     */
88
    protected $sCodeGenerated = false;
89
90
    /**
91
     * Default library URL
92
     *
93
     * @var string
94
     */
95
    protected $sJsLibraryUrl = 'https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist';
96
97
    /**
98
     * The constructor
99
     *
100
     * @param TemplateEngine        $xTemplateEngine      The template engine
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; 6 found
Loading history...
101
     */
102
    public function __construct(TemplateEngine $xTemplateEngine)
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
103
    {
104
        $this->xTemplateEngine = $xTemplateEngine;
105
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
106
107
    /**
108
     * Add a new generator to the list
109
     *
110
     * @param GeneratorContract     $xGenerator     The code generator
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 5 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
111
     * @param integer               $nPriority      The desired priority, used to order the plugins
0 ignored issues
show
Coding Style introduced by
Expected 11 spaces after parameter type; 15 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
112
     *
113
     * @return void
114
     */
115
    public function addGenerator(GeneratorContract $xGenerator, $nPriority)
116
    {
117
        while(isset($this->aGenerators[$nPriority]))
118
        {
119
            $nPriority++;
120
        }
121
        $this->aGenerators[$nPriority] = $xGenerator;
122
        // Sort the array by ascending keys
123
        ksort($this->aGenerators);
124
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
125
126
    /**
127
     * Generate a hash for all the javascript code generated by the library
128
     *
129
     * @return string
130
     */
131
    private function getHash()
132
    {
133
        $sHash = jaxon()->getVersion();
134
        foreach($this->aGenerators as $xGenerator)
135
        {
136
            $sHash .= $xGenerator->getHash();
137
        }
138
        return md5($sHash);
139
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
140
141
    /**
142
     * Render a template in the 'plugins' subdir
143
     *
144
     * @param string    $sTemplate      The template filename
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 4 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 6 found
Loading history...
145
     * @param array     $aVars          The template variables
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 5 found
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 10 found
Loading history...
146
     *
147
     * @return string
148
     */
149
    private function render($sTemplate, array $aVars = [])
150
    {
151
        $aVars['sJsOptions'] = $this->getOption('js.app.options', '');
152
        return $this->xTemplateEngine->render("jaxon::plugins/$sTemplate", $aVars);
153
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
154
155
    /**
156
     * Get the HTML tags to include Jaxon javascript files into the page
157
     *
158
     * @return void
159
     */
160
    private function generateCode()
161
    {
162
        if($this->sCodeGenerated)
163
        {
164
            return;
165
        }
166
        $this->sCodeGenerated = true;
167
168
        foreach($this->aGenerators as $xGenerator)
169
        {
170
            if(($sCssCode = $xGenerator->getCss()))
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
171
            {
172
                $this->sCssCode .= rtrim($sCssCode, " \n") . "\n";
173
            }
174
            if(($sJsCode = $xGenerator->getJs()))
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
175
            {
176
                $this->sJsCode .= rtrim($sJsCode, " \n") . "\n";
177
            }
178
            if(($sJsScript = $xGenerator->getScript()))
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
179
            {
180
                $this->sJsScript .= rtrim($sJsScript, " \n") . "\n";
181
            }
182
            if(!$xGenerator->readyInlined() &&
183
                ($sJsReadyScript = $xGenerator->getReadyScript()))
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
184
            {
185
                $this->sJsReadyScript .= rtrim($sJsReadyScript, " \n") . "\n";
186
            }
187
            if($xGenerator->readyInlined() &&
188
                $xGenerator->readyEnabled() &&
189
                ($sJsInlineScript = $xGenerator->getReadyScript()))
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
190
            {
191
                $this->sJsInlineScript .= rtrim($sJsInlineScript, " \n") . "\n";
192
            }
193
        }
194
195
        if(($this->sJsInlineScript))
196
        {
197
            $this->sJsInlineScript = $this->render('ready.js', ['script' => $this->sJsInlineScript]);
198
        }
199
        if(($this->sJsReadyScript))
200
        {
201
            // These two parts are always rendered together
202
            $this->sJsScript .= "\n" . $this->render('ready.js', ['script' => $this->sJsReadyScript]);
203
        }
204
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
205
206
    /**
207
     * Get the base URI of the Jaxon library javascript files
208
     *
209
     * @return string
210
     */
211
    private function getJsLibUri()
212
    {
213
        return rtrim($this->getOption('js.lib.uri', $this->sJsLibraryUrl), '/') . '/';
214
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
215
216
    /**
217
     * Get the extension of the Jaxon library javascript files
218
     *
219
     * The returned string is '.min.js' if the files are minified.
220
     *
221
     * @return string
222
     */
223
    private function getJsLibExt()
224
    {
225
        if(($this->getOption('js.app.minify')))
226
        {
227
            return '.min.js';
228
        }
229
        return '.js';
230
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
231
232
    /**
233
     * Check if the javascript code generated by Jaxon can be exported to an external file
234
     *
235
     * @return boolean
236
     */
237
    public function canExportJavascript()
238
    {
239
        // Check config options
240
        // - The js.app.export option must be set to true
241
        // - The js.app.uri and js.app.dir options must be set to non null values
242
        if(!$this->getOption('js.app.export') ||
243
            !$this->getOption('js.app.uri') ||
244
            !$this->getOption('js.app.dir'))
245
        {
246
            return false;
247
        }
248
        // Check dir access
249
        // - The js.app.dir must be writable
250
        $sJsAppDir = $this->getOption('js.app.dir');
251
        if(!is_dir($sJsAppDir) || !is_writable($sJsAppDir))
252
        {
253
            return false;
254
        }
255
        return true;
256
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
257
258
    /**
259
     * Get the HTML tags to include Jaxon javascript files into the page
260
     *
261
     * @return string
262
     */
263
    public function getJs()
264
    {
265
        $sJsLibUri = $this->getJsLibUri();
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...
266
        $sJsLibExt = $this->getJsLibExt();
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
        $sJsCoreUrl = $sJsLibUri . 'jaxon.core' . $sJsLibExt;
268
        $sJsDebugUrl = $sJsLibUri . 'jaxon.debug' . $sJsLibExt;
269
        // $sJsVerboseUrl = $sJsLibUri . 'jaxon.verbose' . $sJsLibExt;
270
        $sJsLanguageUrl = $sJsLibUri . 'lang/jaxon.' . $this->getOption('core.language') . $sJsLibExt;
271
272
        // Add component files to the javascript file array;
273
        $aJsFiles = [$sJsCoreUrl];
274
        if($this->getOption('core.debug.on'))
275
        {
276
            $aJsFiles[] = $sJsDebugUrl;
277
            $aJsFiles[] = $sJsLanguageUrl;
278
            /*if($this->getOption('core.debug.verbose'))
0 ignored issues
show
Coding Style introduced by
Block comment text must start on a new line
Loading history...
279
            {
280
                $aJsFiles[] = $sJsVerboseUrl;
281
            }*/
282
        }
283
284
        // Set the template engine cache dir
285
        $this->generateCode();
286
287
        return $this->render('includes.js', ['aUrls' => $aJsFiles]) . $this->sJsCode;
288
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
289
290
    /**
291
     * Get the HTML tags to include Jaxon CSS code and files into the page
292
     *
293
     * @return string
294
     */
295
    public function getCss()
296
    {
297
        // Set the template engine cache dir
298
        $this->generateCode();
299
300
        return $this->sCssCode;
301
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
302
303
    /**
304
     * Get the correspondances between previous and current config options
305
     *
306
     * They are used to keep the deprecated config options working.
307
     * They will be removed when the deprecated options will lot be supported anymore.
308
     *
309
     * @return array
310
     */
311
    private function getOptionVars()
312
    {
313
        return [
314
            'sResponseType'             => self::RESPONSE_TYPE,
315
            'sVersion'                  => $this->getOption('core.version'),
316
            'sLanguage'                 => $this->getOption('core.language'),
317
            'bLanguage'                 => $this->hasOption('core.language') ? true : false,
318
            'sRequestURI'               => $this->getOption('core.request.uri'),
319
            'sDefaultMode'              => $this->getOption('core.request.mode'),
320
            'sDefaultMethod'            => $this->getOption('core.request.method'),
321
            'sCsrfMetaName'             => $this->getOption('core.request.csrf_meta'),
322
            'bDebug'                    => $this->getOption('core.debug.on'),
323
            'bVerboseDebug'             => $this->getOption('core.debug.verbose'),
324
            'sDebugOutputID'            => $this->getOption('core.debug.output_id'),
325
            'nResponseQueueSize'        => $this->getOption('js.lib.queue_size'),
326
            'sStatusMessages'           => $this->getOption('js.lib.show_status') ? 'true' : 'false',
327
            'sWaitCursor'               => $this->getOption('js.lib.show_cursor') ? 'true' : 'false',
328
            'sDefer'                    => $this->getOption('js.app.options', ''),
329
        ];
330
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
331
332
    /**
333
     * Get the javascript code to be sent to the browser
334
     *
335
     * @return string
336
     */
337
    private function _getScript()
338
    {
339
        $aConfigVars = $this->getOptionVars();
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...
340
        $sYesScript = 'jaxon.ajax.response.process(command.response)';
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...
341
        $sNoScript = 'jaxon.confirm.skip(command);jaxon.ajax.response.process(command.response)';
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...
342
        $sQuestionScript = jaxon()->dialog()->confirm('msg', $sYesScript, $sNoScript);
343
344
        $aConfigVars['sQuestionScript'] = $this->render('confirm.js', [
345
            'sQuestionScript' => $sQuestionScript,
346
        ]);
347
348
        return $this->render('config.js', $aConfigVars) . "\n" . $this->sJsScript;
349
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
350
351
    /**
352
     * Write javascript files and return the corresponding URI
353
     *
354
     * @return string
355
     */
356
    private function _writeFiles()
357
    {
358
        $sJsAppURI = rtrim($this->getOption('js.app.uri'), '/') . '/';
359
        $sJsAppDir = rtrim($this->getOption('js.app.dir'), '/') . '/';
360
        $sFinalFile = $this->getOption('js.app.file');
361
        $sExtension = $this->getJsLibExt();
362
363
        // Check if the final file already exists
364
        if(($sFinalFile) && is_file($sJsAppDir . $sFinalFile . $sExtension))
365
        {
366
            return $sJsAppURI . $sFinalFile . $sExtension;
367
        }
368
369
        // The plugins scripts are written into the javascript app dir
370
        $sHash = $this->getHash();
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...
371
        $sOutFile = $sHash . '.js';
372
        $sMinFile = $sHash . '.min.js';
373
        if(!is_file($sJsAppDir . $sOutFile))
374
        {
375
            file_put_contents($sJsAppDir . $sOutFile, $this->_getScript());
376
        }
377
        if(($this->getOption('js.app.minify')))
378
        {
379
            if(is_file($sJsAppDir . $sMinFile))
380
            {
381
                $sOutFile = $sMinFile; // The file was already minified
382
            }
383
            elseif(($this->minify($sJsAppDir . $sOutFile, $sJsAppDir . $sMinFile)))
384
            {
385
                $sOutFile = $sMinFile;
386
            }
387
        }
388
        // Copy the file to its final location
389
        if(($sFinalFile))
390
        {
391
            if(copy($sJsAppDir . $sOutFile, $sJsAppDir . $sFinalFile . $sExtension))
392
            {
393
                $sOutFile = $sFinalFile . $sExtension;
394
            }
395
        }
396
397
        return $sJsAppURI . $sOutFile;
398
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
399
400
    /**
401
     * Get the javascript code to be sent to the browser
402
     *
403
     * Also call each of the request plugins giving them the opportunity
404
     * to output some javascript to the page being generated.
405
     * This is called only when the page is being loaded initially.
406
     * This is not called when processing a request.
407
     *
408
     * @param boolean        $bIncludeJs            Also get the JS files
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 8 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 12 found
Loading history...
409
     * @param boolean        $bIncludeCss        Also get the CSS files
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; 8 found
Loading history...
410
     *
411
     * @return string
412
     */
413
    public function getScript($bIncludeJs, $bIncludeCss)
414
    {
415
        if(!$this->getOption('core.request.uri'))
416
        {
417
            $this->setOption('core.request.uri', jaxon()->di()->get(URI::class)->detect());
418
        }
419
420
        // Set the template engine cache dir
421
        $this->generateCode();
422
423
        $sScript = '';
424
        if(($bIncludeCss))
425
        {
426
            $sScript .= $this->getCss() . "\n";
427
        }
428
        if(($bIncludeJs))
429
        {
430
            $sScript .= $this->getJs() . "\n";
431
        }
432
433
        if($this->canExportJavascript())
434
        {
435
            $sJsInlineScript = '';
436
            if(($this->sJsInlineScript))
437
            {
438
                $sJsInlineScript = $this->render('wrapper.js', ['sScript' => $this->sJsInlineScript]);
439
            }
440
            // The returned code loads the generated javascript file
441
            return $sScript . $this->render('include.js', ['sUrl' => $this->_writeFiles()]) . $sJsInlineScript;
442
        }
443
444
        // The plugins scripts are wrapped with javascript tags
445
        return $sScript . $this->render('wrapper.js', [
446
            'sScript' => $this->_getScript() . "\n" . $this->sJsInlineScript,
447
        ]);
448
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
449
}
450