Completed
Push — master ( 9cf8bc...8e87e9 )
by Thierry
01:35
created

CodeGenerator::getJsLibUri()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
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
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
 */
14
15
namespace Jaxon\Plugin;
16
17
use Jaxon\Utils\Template\Engine as TemplateEngine;
18
use Jaxon\Utils\Http\URI;
19
20
class CodeGenerator
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|null
50
     */
51
    protected $sCssCode = null;
52
53
    /**
54
     * Generated Javascript code
55
     *
56
     * @var string|null
57
     */
58
    protected $sJsCode = null;
59
60
    /**
61
     * Generated Javascript ready script
62
     *
63
     * @var string|null
64
     */
65
    protected $sJsScript = null;
66
67
    /**
68
     * Default library URL
69
     *
70
     * @var string
71
     */
72
    protected $sJsLibraryUrl = 'https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist';
73
74
    /**
75
     * The constructor
76
     *
77
     * @param Manager    $xPluginManager
78
     */
79
    public function __construct(Manager $xPluginManager, TemplateEngine $xTemplate)
80
    {
81
        $this->xPluginManager = $xPluginManager;
82
        $this->xTemplate = $xTemplate;
83
    }
84
85
    /**
86
     * Get the base URI of the Jaxon library javascript files
87
     *
88
     * @return string
89
     */
90
    private function getJsLibUri()
91
    {
92
        return rtrim($this->getOption('js.lib.uri', $this->sJsLibraryUrl), '/') . '/';
93
    }
94
95
    /**
96
     * Get the extension of the Jaxon library javascript files
97
     *
98
     * The returned string is '.min.js' if the files are minified.
99
     *
100
     * @return string
101
     */
102
    private function getJsLibExt()
103
    {
104
        if(($this->getOption('js.app.minify')))
105
        {
106
            return '.min.js';
107
        }
108
        return '.js';
109
    }
110
111
    /**
112
     * Check if the javascript code generated by Jaxon can be exported to an external file
113
     *
114
     * @return boolean
115
     */
116
    public function canExportJavascript()
117
    {
118
        // Check config options
119
        // - The js.app.export option must be set to true
120
        // - The js.app.uri and js.app.dir options must be set to non null values
121
        if(!$this->getOption('js.app.export') ||
122
            !$this->getOption('js.app.uri') ||
123
            !$this->getOption('js.app.dir'))
124
        {
125
            return false;
126
        }
127
        // Check dir access
128
        // - The js.app.dir must be writable
129
        $sJsAppDir = $this->getOption('js.app.dir');
130
        if(!is_dir($sJsAppDir) || !is_writable($sJsAppDir))
131
        {
132
            return false;
133
        }
134
        return true;
135
    }
136
137
    /**
138
     * Generate a hash for all the javascript code generated by the library
139
     *
140
     * @return string
141
     */
142
    private function generateHash()
143
    {
144
        $sHash = jaxon()->getVersion();
145
        foreach($this->xPluginManager->getRequestPlugins() as $xPlugin)
146
        {
147
            $sHash .= $xPlugin->generateHash();
148
        }
149
        foreach($this->xPluginManager->getResponsePlugins() as $xPlugin)
150
        {
151
            $sHash .= $xPlugin->generateHash();
152
        }
153
        return md5($sHash);
154
    }
155
156
    /**
157
     * Get the HTML tags to include Jaxon javascript files into the page
158
     *
159
     * @return string
160
     */
161
    private function makePluginsCode()
162
    {
163
        if($this->sCssCode === null || $this->sJsCode === null || $this->sJsScript === null)
164
        {
165
            $this->sCssCode = '';
166
            $this->sJsCode = '';
167
            $this->sJsScript = '';
168
            foreach($this->xPluginManager->getPlugins() as $xPlugin)
169
            {
170
                if($xPlugin instanceof Response)
171
                {
172
                    if(($sCssCode = trim($xPlugin->getCss())))
173
                    {
174
                        $this->sCssCode .= rtrim($sCssCode, " \n") . "\n";
175
                    }
176
                    if(($sJsCode = trim($xPlugin->getJs())))
177
                    {
178
                        $this->sJsCode .= rtrim($sJsCode, " \n") . "\n";
179
                    }
180
                }
181
                if(($sJsScript = trim($xPlugin->getScript())))
182
                {
183
                    $this->sJsScript .= trim($sJsScript, " \n") . "\n";
184
                }
185
            }
186
187
            // foreach($this->xPluginManager->getPackages() as $sPackageClass)
188
            // {
189
            //     $xPackage = jaxon()->di()->get($sPackageClass);
190
            //     if(($sCssCode = trim($xPackage->css())))
191
            //     {
192
            //         $this->sCssCode .= rtrim($sCssCode, " \n") . "\n";
193
            //     }
194
            //     if(($sJsCode = trim($xPackage->js())))
195
            //     {
196
            //         $this->sJsCode .= rtrim($sJsCode, " \n") . "\n";
197
            //     }
198
            //     if(($sJsScript = trim($xPackage->ready())))
199
            //     {
200
            //         $this->sJsScript .= trim($sJsScript, " \n") . "\n";
201
            //     }
202
            // }
203
        }
204
    }
205
206
    /**
207
     * Get the HTML tags to include Jaxon javascript files into the page
208
     *
209
     * @return string
210
     */
211
    public function getJs()
212
    {
213
        $sJsLibUri = $this->getJsLibUri();
214
        $sJsLibExt = $this->getJsLibExt();
215
        $sJsCoreUrl = $sJsLibUri . 'jaxon.core' . $sJsLibExt;
216
        $sJsDebugUrl = $sJsLibUri . 'jaxon.debug' . $sJsLibExt;
217
        // $sJsVerboseUrl = $sJsLibUri . 'jaxon.verbose' . $sJsLibExt;
218
        $sJsLanguageUrl = $sJsLibUri . 'lang/jaxon.' . $this->getOption('core.language') . $sJsLibExt;
219
220
        // Add component files to the javascript file array;
221
        $aJsFiles = [$sJsCoreUrl];
222
        if($this->getOption('core.debug.on'))
223
        {
224
            $aJsFiles[] = $sJsDebugUrl;
225
            $aJsFiles[] = $sJsLanguageUrl;
226
            /*if($this->getOption('core.debug.verbose'))
227
            {
228
                $aJsFiles[] = $sJsVerboseUrl;
229
            }*/
230
        }
231
232
        // Set the template engine cache dir
233
        $this->makePluginsCode();
234
235
        return $this->xTemplate->render('jaxon::plugins/includes.js', [
236
            'sJsOptions' => $this->getOption('js.app.options', ''),
237
            'aUrls' => $aJsFiles,
238
        ]) . $this->sJsCode;
239
    }
240
241
    /**
242
     * Get the HTML tags to include Jaxon CSS code and files into the page
243
     *
244
     * @return string
245
     */
246
    public function getCss()
247
    {
248
        // Set the template engine cache dir
249
        $this->makePluginsCode();
250
251
        return $this->sCssCode;
252
    }
253
254
    /**
255
     * Get the correspondances between previous and current config options
256
     *
257
     * They are used to keep the deprecated config options working.
258
     * They will be removed when the deprecated options will lot be supported anymore.
259
     *
260
     * @return array
261
     */
262
    private function getOptionVars()
263
    {
264
        return [
265
            'sResponseType'             => self::RESPONSE_TYPE,
266
            'sVersion'                  => $this->getOption('core.version'),
267
            'sLanguage'                 => $this->getOption('core.language'),
268
            'bLanguage'                 => $this->hasOption('core.language') ? true : false,
269
            'sRequestURI'               => $this->getOption('core.request.uri'),
270
            'sDefaultMode'              => $this->getOption('core.request.mode'),
271
            'sDefaultMethod'            => $this->getOption('core.request.method'),
272
            'sCsrfMetaName'             => $this->getOption('core.request.csrf_meta'),
273
            'bDebug'                    => $this->getOption('core.debug.on'),
274
            'bVerboseDebug'             => $this->getOption('core.debug.verbose'),
275
            'sDebugOutputID'            => $this->getOption('core.debug.output_id'),
276
            'nResponseQueueSize'        => $this->getOption('js.lib.queue_size'),
277
            'sStatusMessages'           => $this->getOption('js.lib.show_status') ? 'true' : 'false',
278
            'sWaitCursor'               => $this->getOption('js.lib.show_cursor') ? 'true' : 'false',
279
            'sDefer'                    => $this->getOption('js.app.options', ''),
280
        ];
281
    }
282
283
    /**
284
     * Get the javascript code to be sent to the browser
285
     *
286
     * @return string
287
     */
288
    private function _getScript()
289
    {
290
        $aVars = $this->getOptionVars();
291
        $sYesScript = 'jaxon.ajax.response.process(command.response)';
292
        $sNoScript = 'jaxon.confirm.skip(command);jaxon.ajax.response.process(command.response)';
293
        $sConfirmScript = jaxon()->dialog()->confirm('msg', $sYesScript, $sNoScript);
294
        $aVars['sConfirmScript'] = $this->xTemplate->render('jaxon::plugins/confirm.js', [
295
            'sConfirmScript' => $sConfirmScript,
296
        ]);
297
298
        return $this->xTemplate->render('jaxon::plugins/config.js', $aVars) . "\n" . $this->sJsScript . '
299
jaxon.dom.ready(function() {
300
    jaxon.command.handler.register("cc", jaxon.confirm.commands);
301
});
302
';
303
    }
304
305
    /**
306
     * Get the javascript code to be sent to the browser
307
     *
308
     * Also call each of the request plugins giving them the opportunity
309
     * to output some javascript to the page being generated.
310
     * This is called only when the page is being loaded initially.
311
     * This is not called when processing a request.
312
     *
313
     * @param boolean        $bIncludeJs            Also get the JS files
314
     * @param boolean        $bIncludeCss        Also get the CSS files
315
     *
316
     * @return string
317
     */
318
    public function getScript($bIncludeJs = false, $bIncludeCss = false)
319
    {
320
        if(!$this->getOption('core.request.uri'))
321
        {
322
            $this->setOption('core.request.uri', URI::detect());
323
        }
324
325
        // Set the template engine cache dir
326
        $this->makePluginsCode();
327
328
        $sScript = '';
329
        if(($bIncludeCss))
330
        {
331
            $sScript .= $this->getCss() . "\n";
332
        }
333
        if(($bIncludeJs))
334
        {
335
            $sScript .= $this->getJs() . "\n";
336
        }
337
338
        if($this->canExportJavascript())
339
        {
340
            $sJsAppURI = rtrim($this->getOption('js.app.uri'), '/') . '/';
341
            $sJsAppDir = rtrim($this->getOption('js.app.dir'), '/') . '/';
342
            $sFinalFile = $this->getOption('js.app.file');
343
            $sExtension = $this->getJsLibExt();
344
345
            // Check if the final file already exists
346
            if(($sFinalFile) && is_file($sJsAppDir . $sFinalFile . $sExtension))
347
            {
348
                $sOutFile = $sFinalFile . $sExtension;
349
            }
350
            else
351
            {
352
                // The plugins scripts are written into the javascript app dir
353
                $sHash = $this->generateHash();
354
                $sOutFile = $sHash . '.js';
355
                $sMinFile = $sHash . '.min.js';
356
                if(!is_file($sJsAppDir . $sOutFile))
357
                {
358
                    file_put_contents($sJsAppDir . $sOutFile, $this->_getScript());
359
                }
360
                if(($this->getOption('js.app.minify')))
361
                {
362
                    if(is_file($sJsAppDir . $sMinFile))
363
                    {
364
                        $sOutFile = $sMinFile; // The file was already minified
365
                    }
366
                    elseif(($this->minify($sJsAppDir . $sOutFile, $sJsAppDir . $sMinFile)))
367
                    {
368
                        $sOutFile = $sMinFile;
369
                    }
370
                }
371
                // Copy the file to its final location
372
                if(($sFinalFile))
373
                {
374
                    if(copy($sJsAppDir . $sOutFile, $sJsAppDir . $sFinalFile . $sExtension))
375
                    {
376
                        $sOutFile = $sFinalFile . $sExtension;
377
                    }
378
                }
379
            }
380
381
            // The returned code loads the generated javascript file
382
            $sScript .= $this->xTemplate->render('jaxon::plugins/include.js', [
383
                'sJsOptions' => $this->getOption('js.app.options', ''),
384
                'sUrl' => $sJsAppURI . $sOutFile,
385
            ]);
386
        }
387
        else
388
        {
389
            // The plugins scripts are wrapped with javascript tags
390
            $sScript .= $this->xTemplate->render('jaxon::plugins/wrapper.js', [
391
                'sJsOptions' => $this->getOption('js.app.options', ''),
392
                'sScript' => $this->_getScript(),
393
            ]);
394
        }
395
396
        return $sScript;
397
    }
398
}
399