Completed
Push — master ( 75c398...3c71f0 )
by Thierry
01:47
created

CodeGenerator::makePluginsCode()   D

Complexity

Conditions 14
Paths 244

Size

Total Lines 51

Duplication

Lines 8
Ratio 15.69 %

Importance

Changes 0
Metric Value
cc 14
nc 244
nop 0
dl 8
loc 51
rs 4.8833
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
class CodeGenerator
18
{
19
    use \Jaxon\Utils\Traits\Config;
20
    use \Jaxon\Utils\Traits\Cache;
21
    use \Jaxon\Utils\Traits\Minifier;
22
    use \Jaxon\Utils\Traits\Template;
23
24
    /**
25
     * The response type.
26
     *
27
     * @var string
28
     */
29
    const RESPONSE_TYPE = 'JSON';
30
31
    /**
32
     * The plugin manager
33
     *
34
     * @var Manager
35
     */
36
    protected $xPluginManager;
37
38
    /**
39
     * Generated CSS code
40
     *
41
     * @var string|null
42
     */
43
    protected $sCssCode = null;
44
45
    /**
46
     * Generated Javascript code
47
     *
48
     * @var string|null
49
     */
50
    protected $sJsCode = null;
51
52
    /**
53
     * Generated Javascript ready script
54
     *
55
     * @var string|null
56
     */
57
    protected $sJsReady = null;
58
59
    /**
60
     * The constructor
61
     *
62
     * @param Manager    $xPluginManager
63
     */
64
    public function __construct(Manager $xPluginManager)
65
    {
66
        $this->xPluginManager = $xPluginManager;
67
    }
68
69
    /**
70
     * Get the base URI of the Jaxon library javascript files
71
     *
72
     * @return string
73
     */
74
    private function getJsLibUri()
75
    {
76
        if(!$this->hasOption('js.lib.uri'))
77
        {
78
            // return 'https://cdn.jsdelivr.net/jaxon/1.2.0/';
79
            return 'https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist/';
80
        }
81
        // Todo: check the validity of the URI
82
        return rtrim($this->getOption('js.lib.uri'), '/') . '/';
83
    }
84
85
    /**
86
     * Get the extension of the Jaxon library javascript files
87
     *
88
     * The returned string is '.min.js' if the files are minified.
89
     *
90
     * @return string
91
     */
92
    private function getJsLibExt()
93
    {
94
        // $jsDelivrUri = 'https://cdn.jsdelivr.net';
95
        // $nLen = strlen($jsDelivrUri);
96
        // The jsDelivr CDN only hosts minified files
97
        // if(($this->getOption('js.app.minify')) || substr($this->getJsLibUri(), 0, $nLen) == $jsDelivrUri)
98
        // Starting from version 2.0.0 of the js lib, the jsDelivr CDN also hosts non minified files.
99
        if(($this->getOption('js.app.minify')))
100
        {
101
            return '.min.js';
102
        }
103
        return '.js';
104
    }
105
106
    /**
107
     * Check if the javascript code generated by Jaxon can be exported to an external file
108
     *
109
     * @return boolean
110
     */
111
    public function canExportJavascript()
112
    {
113
        // Check config options
114
        // - The js.app.extern option must be set to true
115
        // - The js.app.uri and js.app.dir options must be set to non null values
116
        if(!$this->getOption('js.app.extern') ||
117
            !$this->getOption('js.app.uri') ||
118
            !$this->getOption('js.app.dir'))
119
        {
120
            return false;
121
        }
122
        // Check dir access
123
        // - The js.app.dir must be writable
124
        $sJsAppDir = $this->getOption('js.app.dir');
125
        if(!is_dir($sJsAppDir) || !is_writable($sJsAppDir))
126
        {
127
            return false;
128
        }
129
        return true;
130
    }
131
132
    /**
133
     * Set the cache directory for the template engine
134
     *
135
     * @return void
136
     */
137
    private function setTemplateCacheDir()
138
    {
139
        if($this->hasOption('core.template.cache_dir'))
140
        {
141
            $this->setCacheDir($this->getOption('core.template.cache_dir'));
142
        }
143
    }
144
145
    /**
146
     * Generate a hash for all the javascript code generated by the library
147
     *
148
     * @return string
149
     */
150
    private function generateHash()
151
    {
152
        $sHash = jaxon()->getVersion();
153
        foreach($this->xPluginManager->getRequestPlugins() as $xPlugin)
154
        {
155
            $sHash .= $xPlugin->generateHash();
156
        }
157
        foreach($this->xPluginManager->getResponsePlugins() as $xPlugin)
158
        {
159
            $sHash .= $xPlugin->generateHash();
160
        }
161
        return md5($sHash);
162
    }
163
164
    /**
165
     * Get the HTML tags to include Jaxon javascript files into the page
166
     *
167
     * @return string
168
     */
169
    private function makePluginsCode()
170
    {
171
        if($this->sCssCode === null || $this->sJsCode === null || $this->sJsReady === null)
172
        {
173
            $this->sCssCode = '';
174
            $this->sJsCode = '';
175
            $this->sJsReady = '';
176
            foreach($this->xPluginManager->getResponsePlugins() as $xPlugin)
177
            {
178
                if(($sCssCode = trim($xPlugin->getCss())))
179
                {
180
                    $this->sCssCode .= rtrim($sCssCode, " \n") . "\n";
181
                }
182
                if(($sJsCode = trim($xPlugin->getJs())))
183
                {
184
                    $this->sJsCode .= rtrim($sJsCode, " \n") . "\n";
185
                }
186 View Code Duplication
                if(($sJsReady = trim($xPlugin->getScript())))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
                {
188
                    $this->sJsReady .= trim($sJsReady, " \n") . "\n";
189
                }
190
            }
191
192
            $this->sJsReady = $this->render('jaxon::plugins/ready.js', ['sPluginScript' => $this->sJsReady]);
193
            foreach($this->xPluginManager->getRequestPlugins() as $xPlugin)
194
            {
195 View Code Duplication
                if(($sJsReady = trim($xPlugin->getScript())))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
196
                {
197
                    $this->sJsReady .= trim($sJsReady, " \n") . "\n";
198
                }
199
            }
200
201
            foreach($this->xPluginManager->getPackages() as $sClass)
202
            {
203
                $xPackage = jaxon()->di()->get($sClass);
204
                if(($sCssCode = trim($xPackage->css())))
205
                {
206
                    $this->sCssCode .= rtrim($sCssCode, " \n") . "\n";
207
                }
208
                if(($sJsCode = trim($xPackage->js())))
209
                {
210
                    $this->sJsCode .= rtrim($sJsCode, " \n") . "\n";
211
                }
212
                $xPackage = jaxon()->di()->get($sClass);
213
                if(($sJsReady = trim($xPackage->ready())))
214
                {
215
                    $this->sJsReady .= trim($sJsReady, " \n") . "\n";
216
                }
217
            }
218
        }
219
    }
220
221
    /**
222
     * Get the HTML tags to include Jaxon javascript files into the page
223
     *
224
     * @return string
225
     */
226
    public function getJs()
227
    {
228
        $sJsLibUri = $this->getJsLibUri();
229
        $sJsLibExt = $this->getJsLibExt();
230
        $sJsCoreUrl = $sJsLibUri . 'jaxon.core' . $sJsLibExt;
231
        $sJsDebugUrl = $sJsLibUri . 'jaxon.debug' . $sJsLibExt;
232
        // $sJsVerboseUrl = $sJsLibUri . 'jaxon.verbose' . $sJsLibExt;
233
        $sJsLanguageUrl = $sJsLibUri . 'lang/jaxon.' . $this->getOption('core.language') . $sJsLibExt;
234
235
        // Add component files to the javascript file array;
236
        $aJsFiles = array($sJsCoreUrl);
237
        if($this->getOption('core.debug.on'))
238
        {
239
            $aJsFiles[] = $sJsDebugUrl;
240
            $aJsFiles[] = $sJsLanguageUrl;
241
            /*if($this->getOption('core.debug.verbose'))
242
            {
243
                $aJsFiles[] = $sJsVerboseUrl;
244
            }*/
245
        }
246
247
        // Set the template engine cache dir
248
        $this->setTemplateCacheDir();
249
        $this->makePluginsCode();
250
251
        return $this->render('jaxon::plugins/includes.js', [
252
            'sJsOptions' => $this->getOption('js.app.options'),
253
            'aUrls' => $aJsFiles,
254
        ]) . $this->sJsCode;
255
    }
256
257
    /**
258
     * Get the HTML tags to include Jaxon CSS code and files into the page
259
     *
260
     * @return string
261
     */
262
    public function getCss()
263
    {
264
        // Set the template engine cache dir
265
        $this->setTemplateCacheDir();
266
        $this->makePluginsCode();
267
268
        return $this->sCssCode;
269
    }
270
271
    /**
272
     * Get the correspondances between previous and current config options
273
     *
274
     * They are used to keep the deprecated config options working.
275
     * They will be removed when the deprecated options will lot be supported anymore.
276
     *
277
     * @return array
278
     */
279
    private function getOptionVars()
280
    {
281
        return [
282
            'sResponseType'             => self::RESPONSE_TYPE,
283
            'sVersion'                  => $this->getOption('core.version'),
284
            'sLanguage'                 => $this->getOption('core.language'),
285
            'bLanguage'                 => $this->hasOption('core.language') ? true : false,
286
            'sRequestURI'               => $this->getOption('core.request.uri'),
287
            'sDefaultMode'              => $this->getOption('core.request.mode'),
288
            'sDefaultMethod'            => $this->getOption('core.request.method'),
289
            'sCsrfMetaName'             => $this->getOption('core.request.csrf_meta'),
290
            'bDebug'                    => $this->getOption('core.debug.on'),
291
            'bVerboseDebug'             => $this->getOption('core.debug.verbose'),
292
            'sDebugOutputID'            => $this->getOption('core.debug.output_id'),
293
            'nResponseQueueSize'        => $this->getOption('js.lib.queue_size'),
294
            'sStatusMessages'           => $this->getOption('js.lib.show_status') ? 'true' : 'false',
295
            'sWaitCursor'               => $this->getOption('js.lib.show_cursor') ? 'true' : 'false',
296
            'sDefer'                    => $this->getOption('js.app.options'),
297
        ];
298
    }
299
300
    /**
301
     * Get the javascript code to be sent to the browser
302
     *
303
     * @return string
304
     */
305
    private function _getScript()
306
    {
307
        $aVars = $this->getOptionVars();
308
        $sYesScript = 'jaxon.ajax.response.process(command.response)';
309
        $sNoScript = 'jaxon.confirm.skip(command);jaxon.ajax.response.process(command.response)';
310
        $sConfirmScript = jaxon()->dialog()->confirm('msg', $sYesScript, $sNoScript);
311
        $aVars['sConfirmScript'] = $this->render('jaxon::plugins/confirm.js', ['sConfirmScript' => $sConfirmScript]);
312
313
        return $this->render('jaxon::plugins/config.js', $aVars) . "\n" . $this->sJsReady . "\n";
314
    }
315
316
    /**
317
     * Get the javascript code to be sent to the browser
318
     *
319
     * Also call each of the request plugins giving them the opportunity
320
     * to output some javascript to the page being generated.
321
     * This is called only when the page is being loaded initially.
322
     * This is not called when processing a request.
323
     *
324
     * @return string
325
     */
326
    public function getScript()
327
    {
328
        // Set the template engine cache dir
329
        $this->setTemplateCacheDir();
330
        $this->makePluginsCode();
331
332
        if($this->canExportJavascript())
333
        {
334
            $sJsAppURI = rtrim($this->getOption('js.app.uri'), '/') . '/';
335
            $sJsAppDir = rtrim($this->getOption('js.app.dir'), '/') . '/';
336
337
            // The plugins scripts are written into the javascript app dir
338
            $sHash = $this->generateHash();
339
            $sOutFile = $sHash . '.js';
340
            $sMinFile = $sHash . '.min.js';
341
            if(!is_file($sJsAppDir . $sOutFile))
342
            {
343
                file_put_contents($sJsAppDir . $sOutFile, $this->_getScript());
344
            }
345
            if(($this->getOption('js.app.minify')) && !is_file($sJsAppDir . $sMinFile))
346
            {
347
                if(($this->minify($sJsAppDir . $sOutFile, $sJsAppDir . $sMinFile)))
348
                {
349
                    $sOutFile = $sMinFile;
350
                }
351
            }
352
353
            // The returned code loads the generated javascript file
354
            $sScript = $this->render('jaxon::plugins/include.js', array(
355
                'sJsOptions' => $this->getOption('js.app.options'),
356
                'sUrl' => $sJsAppURI . $sOutFile,
357
            ));
358
        }
359
        else
360
        {
361
            // The plugins scripts are wrapped with javascript tags
362
            $sScript = $this->render('jaxon::plugins/wrapper.js', array(
363
                'sJsOptions' => $this->getOption('js.app.options'),
364
                'sScript' => $this->_getScript(),
365
            ));
366
        }
367
368
        return $sScript;
369
    }
370
}
371