Passed
Push — feature/code_improvement ( 374d0e...1b7fb9 )
by Thierry
02:42
created

CodeGenerator::canExportJavascript()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 3
nop 0
dl 0
loc 20
rs 8.9777
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;
16
17
use Jaxon\Utils\Template\Engine as TemplateEngine;
18
use Jaxon\Utils\Http\URI;
19
20
class CodeGenerator
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CodeGenerator
Loading history...
21
{
22
    use \Jaxon\Features\Config;
23
    use \Jaxon\Features\Minifier;
24
25
    /**
26
     * The response type.
27
     *
28
     * @var string
29
     */
30
    const RESPONSE_TYPE = 'JSON';
31
32
    /**
33
     * The plugin manager
34
     *
35
     * @var Manager
36
     */
37
    protected $xPluginManager;
38
39
    /**
40
     * The Jaxon template engine
41
     *
42
     * @var TemplateEngine
43
     */
44
    protected $xTemplate;
45
46
    /**
47
     * Generated CSS code
48
     *
49
     * @var string
50
     */
51
    protected $sCssCode = '';
52
53
    /**
54
     * Generated Javascript code
55
     *
56
     * @var string
57
     */
58
    protected $sJsCode = '';
59
60
    /**
61
     * Generated Javascript ready script
62
     *
63
     * @var string
64
     */
65
    protected $sJsScript = '';
66
67
    /**
68
     * Code already generated
69
     *
70
     * @var boolean
71
     */
72
    protected $sCodeGenerated = false;
73
74
    /**
75
     * Default library URL
76
     *
77
     * @var string
78
     */
79
    protected $sJsLibraryUrl = 'https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist';
80
81
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $xTemplate should have a doc-comment as per coding-style.
Loading history...
82
     * The constructor
83
     *
84
     * @param Manager    $xPluginManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter type; 4 found
Loading history...
85
     */
86
    public function __construct(Manager $xPluginManager, TemplateEngine $xTemplate)
87
    {
88
        $this->xPluginManager = $xPluginManager;
89
        $this->xTemplate = $xTemplate;
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...
90
    }
91
92
    /**
93
     * Get the base URI of the Jaxon library javascript files
94
     *
95
     * @return string
96
     */
97
    private function getJsLibUri()
98
    {
99
        return rtrim($this->getOption('js.lib.uri', $this->sJsLibraryUrl), '/') . '/';
100
    }
101
102
    /**
103
     * Get the extension of the Jaxon library javascript files
104
     *
105
     * The returned string is '.min.js' if the files are minified.
106
     *
107
     * @return string
108
     */
109
    private function getJsLibExt()
110
    {
111
        if(($this->getOption('js.app.minify')))
112
        {
113
            return '.min.js';
114
        }
115
        return '.js';
116
    }
117
118
    /**
119
     * Check if the javascript code generated by Jaxon can be exported to an external file
120
     *
121
     * @return boolean
122
     */
123
    public function canExportJavascript()
124
    {
125
        // Check config options
126
        // - The js.app.export option must be set to true
127
        // - The js.app.uri and js.app.dir options must be set to non null values
128
        if(!$this->getOption('js.app.export') ||
129
            !$this->getOption('js.app.uri') ||
130
            !$this->getOption('js.app.dir'))
131
        {
132
            return false;
133
        }
134
        // Check dir access
135
        // - The js.app.dir must be writable
136
        $sJsAppDir = $this->getOption('js.app.dir');
137
        if(!is_dir($sJsAppDir) || !is_writable($sJsAppDir))
138
        {
139
            return false;
140
        }
141
        return true;
142
    }
143
144
    /**
145
     * Generate a hash for all the javascript code generated by the library
146
     *
147
     * @return string
148
     */
149
    private function generateHash()
150
    {
151
        $sHash = jaxon()->getVersion();
152
        foreach($this->xPluginManager->getRequestPlugins() as $xPlugin)
153
        {
154
            $sHash .= $xPlugin->generateHash();
155
        }
156
        foreach($this->xPluginManager->getResponsePlugins() as $xPlugin)
157
        {
158
            $sHash .= $xPlugin->generateHash();
159
        }
160
        return md5($sHash);
161
    }
162
163
    /**
164
     * Get the HTML tags to include Jaxon javascript files into the page
165
     *
166
     * @return void
167
     */
168
    private function makePluginsCode()
169
    {
170
        if($this->sCodeGenerated)
171
        {
172
            return;
173
        }
174
        $this->sCodeGenerated = true;
175
176
        foreach($this->xPluginManager->getPlugins() as $xPlugin)
177
        {
178
            if($xPlugin instanceof Response)
179
            {
180
                if(($sCssCode = trim($xPlugin->getCss())))
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
181
                {
182
                    $this->sCssCode .= rtrim($sCssCode, " \n") . "\n";
183
                }
184
                if(($sJsCode = trim($xPlugin->getJs())))
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
185
                {
186
                    $this->sJsCode .= rtrim($sJsCode, " \n") . "\n";
187
                }
188
            }
189
            if(($sJsScript = trim($xPlugin->getScript())))
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->sJsScript .= trim($sJsScript, " \n") . "\n";
192
            }
193
        }
194
195
        // foreach($this->xPluginManager->getPackages() as $sPackageClass)
196
        // {
197
        //     $xPackage = jaxon()->di()->get($sPackageClass);
198
        //     if(($sCssCode = trim($xPackage->css())))
199
        //     {
200
        //         $this->sCssCode .= rtrim($sCssCode, " \n") . "\n";
201
        //     }
202
        //     if(($sJsCode = trim($xPackage->js())))
203
        //     {
204
        //         $this->sJsCode .= rtrim($sJsCode, " \n") . "\n";
205
        //     }
206
        //     if(($sJsScript = trim($xPackage->ready())))
207
        //     {
208
        //         $this->sJsScript .= trim($sJsScript, " \n") . "\n";
209
        //     }
210
        // }
211
    }
212
213
    /**
214
     * Get the HTML tags to include Jaxon javascript files into the page
215
     *
216
     * @return string
217
     */
218
    public function getJs()
219
    {
220
        $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...
221
        $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...
222
        $sJsCoreUrl = $sJsLibUri . 'jaxon.core' . $sJsLibExt;
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

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

To visualize

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

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

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

will produce no issues.

Loading history...
223
        $sJsDebugUrl = $sJsLibUri . 'jaxon.debug' . $sJsLibExt;
224
        // $sJsVerboseUrl = $sJsLibUri . 'jaxon.verbose' . $sJsLibExt;
225
        $sJsLanguageUrl = $sJsLibUri . 'lang/jaxon.' . $this->getOption('core.language') . $sJsLibExt;
226
227
        // Add component files to the javascript file array;
228
        $aJsFiles = [$sJsCoreUrl];
229
        if($this->getOption('core.debug.on'))
230
        {
231
            $aJsFiles[] = $sJsDebugUrl;
232
            $aJsFiles[] = $sJsLanguageUrl;
233
            /*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...
234
            {
235
                $aJsFiles[] = $sJsVerboseUrl;
236
            }*/
237
        }
238
239
        // Set the template engine cache dir
240
        $this->makePluginsCode();
241
242
        return $this->xTemplate->render('jaxon::plugins/includes.js', [
243
            'sJsOptions' => $this->getOption('js.app.options', ''),
244
            'aUrls' => $aJsFiles,
245
        ]) . $this->sJsCode;
246
    }
247
248
    /**
249
     * Get the HTML tags to include Jaxon CSS code and files into the page
250
     *
251
     * @return string
252
     */
253
    public function getCss()
254
    {
255
        // Set the template engine cache dir
256
        $this->makePluginsCode();
257
258
        return $this->sCssCode;
259
    }
260
261
    /**
262
     * Get the correspondances between previous and current config options
263
     *
264
     * They are used to keep the deprecated config options working.
265
     * They will be removed when the deprecated options will lot be supported anymore.
266
     *
267
     * @return array
268
     */
269
    private function getOptionVars()
270
    {
271
        return [
272
            'sResponseType'             => self::RESPONSE_TYPE,
273
            'sVersion'                  => $this->getOption('core.version'),
274
            'sLanguage'                 => $this->getOption('core.language'),
275
            'bLanguage'                 => $this->hasOption('core.language') ? true : false,
276
            'sRequestURI'               => $this->getOption('core.request.uri'),
277
            'sDefaultMode'              => $this->getOption('core.request.mode'),
278
            'sDefaultMethod'            => $this->getOption('core.request.method'),
279
            'sCsrfMetaName'             => $this->getOption('core.request.csrf_meta'),
280
            'bDebug'                    => $this->getOption('core.debug.on'),
281
            'bVerboseDebug'             => $this->getOption('core.debug.verbose'),
282
            'sDebugOutputID'            => $this->getOption('core.debug.output_id'),
283
            'nResponseQueueSize'        => $this->getOption('js.lib.queue_size'),
284
            'sStatusMessages'           => $this->getOption('js.lib.show_status') ? 'true' : 'false',
285
            'sWaitCursor'               => $this->getOption('js.lib.show_cursor') ? 'true' : 'false',
286
            'sDefer'                    => $this->getOption('js.app.options', ''),
287
        ];
288
    }
289
290
    /**
291
     * Get the javascript code to be sent to the browser
292
     *
293
     * @return string
294
     */
295
    private function _getScript()
296
    {
297
        $aVars = $this->getOptionVars();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 20 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...
298
        $sYesScript = 'jaxon.ajax.response.process(command.response)';
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...
299
        $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 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...
300
        $sQuestionScript = jaxon()->dialog()->confirm('msg', $sYesScript, $sNoScript);
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...
301
        $aVars['sQuestionScript'] = $this->xTemplate->render('jaxon::plugins/confirm.js', [
302
            'sQuestionScript' => $sQuestionScript,
303
        ]);
304
305
        return $this->xTemplate->render('jaxon::plugins/config.js', $aVars) . "\n" . $this->sJsScript . '
306
jaxon.dom.ready(function() {
307
    jaxon.command.handler.register("cc", jaxon.confirm.commands);
308
});
309
';
310
    }
311
312
    /**
313
     * Write javascript files and return the corresponding URI
314
     *
315
     * @return string
316
     */
317
    private function _writeFiles()
318
    {
319
        $sJsAppURI = rtrim($this->getOption('js.app.uri'), '/') . '/';
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

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

To visualize

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

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

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

will produce no issues.

Loading history...
320
        $sJsAppDir = rtrim($this->getOption('js.app.dir'), '/') . '/';
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

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

To visualize

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

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

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

will produce no issues.

Loading history...
321
        $sFinalFile = $this->getOption('js.app.file');
322
        $sExtension = $this->getJsLibExt();
323
324
        // Check if the final file already exists
325
        if(($sFinalFile) && is_file($sJsAppDir . $sFinalFile . $sExtension))
326
        {
327
            return $sJsAppURI . $sFinalFile . $sExtension;
328
        }
329
330
        // The plugins scripts are written into the javascript app dir
331
        $sHash = $this->generateHash();
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...
332
        $sOutFile = $sHash . '.js';
333
        $sMinFile = $sHash . '.min.js';
334
        if(!is_file($sJsAppDir . $sOutFile))
335
        {
336
            file_put_contents($sJsAppDir . $sOutFile, $this->_getScript());
337
        }
338
        if(($this->getOption('js.app.minify')))
339
        {
340
            if(is_file($sJsAppDir . $sMinFile))
341
            {
342
                $sOutFile = $sMinFile; // The file was already minified
343
            }
344
            elseif(($this->minify($sJsAppDir . $sOutFile, $sJsAppDir . $sMinFile)))
345
            {
346
                $sOutFile = $sMinFile;
347
            }
348
        }
349
        // Copy the file to its final location
350
        if(($sFinalFile))
351
        {
352
            if(copy($sJsAppDir . $sOutFile, $sJsAppDir . $sFinalFile . $sExtension))
353
            {
354
                $sOutFile = $sFinalFile . $sExtension;
355
            }
356
        }
357
358
        return $sJsAppURI . $sOutFile;
359
    }
360
361
    /**
362
     * Get the javascript code to be sent to the browser
363
     *
364
     * Also call each of the request plugins giving them the opportunity
365
     * to output some javascript to the page being generated.
366
     * This is called only when the page is being loaded initially.
367
     * This is not called when processing a request.
368
     *
369
     * @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...
370
     * @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...
371
     *
372
     * @return string
373
     */
374
    public function getScript($bIncludeJs = false, $bIncludeCss = false)
375
    {
376
        if(!$this->getOption('core.request.uri'))
377
        {
378
            $this->setOption('core.request.uri', jaxon()->di()->get(URI::class)->detect());
379
        }
380
381
        // Set the template engine cache dir
382
        $this->makePluginsCode();
383
384
        $sScript = '';
385
        if(($bIncludeCss))
386
        {
387
            $sScript .= $this->getCss() . "\n";
388
        }
389
        if(($bIncludeJs))
390
        {
391
            $sScript .= $this->getJs() . "\n";
392
        }
393
394
        if($this->canExportJavascript())
395
        {
396
            // The returned code loads the generated javascript file
397
            return $sScript . $this->xTemplate->render('jaxon::plugins/include.js', [
398
                'sJsOptions' => $this->getOption('js.app.options', ''),
399
                'sUrl' => $this->_writeFiles(),
400
            ]);
401
        }
402
403
        // The plugins scripts are wrapped with javascript tags
404
        return $sScript . $this->xTemplate->render('jaxon::plugins/wrapper.js', [
405
            'sJsOptions' => $this->getOption('js.app.options', ''),
406
            'sScript' => $this->_getScript(),
407
        ]);
408
    }
409
}
410