Passed
Push — master ( 68b778...1b1614 )
by Thierry
07:15 queued 04:29
created

Generator   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 294
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 44
eloc 95
c 1
b 0
f 0
dl 0
loc 294
rs 8.8798

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getScript() 0 27 5
A addGenerator() 0 9 2
B createFiles() 0 29 10
A getJsFileName() 0 14 5
A getJs() 0 26 4
A __construct() 0 3 1
A getCss() 0 8 2
A getOptionVars() 0 18 4
A _getScript() 0 18 4
A _getInlineScript() 0 12 4
A _render() 0 4 1
A getHash() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like Generator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Generator, and based on these observations, apply Extract Interface, too.

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\Plugin\Code\Contracts\Generator as GeneratorContract;
18
use Jaxon\Utils\Template\Engine as TemplateEngine;
19
use Jaxon\Utils\Http\URI;
20
21
class Generator
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class Generator
Loading history...
22
{
23
    use \Jaxon\Features\Config;
24
    use \Jaxon\Features\Minifier;
25
26
    /**
27
     * Default library URL
28
     *
29
     * @var string
30
     */
31
    const JS_LIB_URL = 'https://cdn.jsdelivr.net/gh/jaxon-php/[email protected]/dist';
32
33
    /**
34
     * The objects that generate code
35
     *
36
     * @var array<GeneratorContract>
37
     */
38
    protected $aGenerators = [];
39
40
    /**
41
     * The Jaxon template engine
42
     *
43
     * @var TemplateEngine
44
     */
45
    protected $xTemplateEngine;
46
47
    /**
48
     * The constructor
49
     *
50
     * @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...
51
     */
52
    public function __construct(TemplateEngine $xTemplateEngine)
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
53
    {
54
        $this->xTemplateEngine = $xTemplateEngine;
55
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
56
57
    /**
58
     * Get the correspondances between previous and current config options
59
     *
60
     * @return array
61
     */
62
    private function getOptionVars()
63
    {
64
        return [
65
            'sResponseType'             => 'JSON',
66
            'sVersion'                  => $this->getOption('core.version'),
67
            'sLanguage'                 => $this->getOption('core.language'),
68
            'bLanguage'                 => $this->hasOption('core.language') ? true : false,
69
            'sRequestURI'               => $this->getOption('core.request.uri'),
70
            'sDefaultMode'              => $this->getOption('core.request.mode'),
71
            'sDefaultMethod'            => $this->getOption('core.request.method'),
72
            'sCsrfMetaName'             => $this->getOption('core.request.csrf_meta'),
73
            'bDebug'                    => $this->getOption('core.debug.on'),
74
            'bVerboseDebug'             => $this->getOption('core.debug.verbose'),
75
            'sDebugOutputID'            => $this->getOption('core.debug.output_id'),
76
            'nResponseQueueSize'        => $this->getOption('js.lib.queue_size'),
77
            'sStatusMessages'           => $this->getOption('js.lib.show_status') ? 'true' : 'false',
78
            'sWaitCursor'               => $this->getOption('js.lib.show_cursor') ? 'true' : 'false',
79
            'sDefer'                    => $this->getOption('js.app.options', ''),
80
        ];
81
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
82
83
    /**
84
     * Render a template in the 'plugins' subdir
85
     *
86
     * @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...
87
     * @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...
88
     *
89
     * @return string
90
     */
91
    private function _render($sTemplate, array $aVars = [])
92
    {
93
        $aVars['sJsOptions'] = $this->getOption('js.app.options', '');
94
        return $this->xTemplateEngine->render("jaxon::plugins/$sTemplate", $aVars);
95
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
96
97
    /**
98
     * Add a new generator to the list
99
     *
100
     * @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...
101
     * @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...
102
     *
103
     * @return void
104
     */
105
    public function addGenerator(GeneratorContract $xGenerator, $nPriority)
106
    {
107
        while(isset($this->aGenerators[$nPriority]))
108
        {
109
            $nPriority++;
110
        }
111
        $this->aGenerators[$nPriority] = $xGenerator;
112
        // Sort the array by ascending keys
113
        ksort($this->aGenerators);
114
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
115
116
    /**
117
     * Generate a hash for all the javascript code generated by the library
118
     *
119
     * @return string
120
     */
121
    private function getHash()
122
    {
123
        $sHash = jaxon()->getVersion();
124
        foreach($this->aGenerators as $xGenerator)
125
        {
126
            $sHash .= $xGenerator->getHash();
127
        }
128
        return md5($sHash);
129
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
130
131
    /**
132
     * Get the HTML tags to include Jaxon CSS code and files into the page
133
     *
134
     * @return string
135
     */
136
    public function getCss()
137
    {
138
        $sCssCode = '';
139
        foreach($this->aGenerators as $xGenerator)
140
        {
141
            $sCssCode = rtrim($sCssCode, " \n") . "\n" . $xGenerator->getCss();
142
        }
143
        return rtrim($sCssCode, " \n") . "\n";
144
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
145
146
    /**
147
     * Get the HTML tags to include Jaxon javascript files into the page
148
     *
149
     * @return string
150
     */
151
    public function getJs()
152
    {
153
        $sJsExtension = $this->getOption('js.app.minify') ? '.min.js' : '.js';
154
155
        // The URI for the javascript library files
156
        $sJsLibUri = rtrim($this->getOption('js.lib.uri', self::JS_LIB_URL), '/') . '/';
157
        // Add component files to the javascript file array;
158
        $aJsFiles = [$sJsLibUri . 'jaxon.core' . $sJsExtension];
159
        if($this->getOption('core.debug.on'))
160
        {
161
            $sLanguage = $this->getOption('core.language');
162
            $aJsFiles[] = $sJsLibUri . 'jaxon.debug' . $sJsExtension;
163
            $aJsFiles[] = $sJsLibUri . 'lang/jaxon.' . $sLanguage . $sJsExtension;
164
            /*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...
165
            {
166
                $aJsFiles[] = $sJsLibUri . 'jaxon.verbose' . $sJsExtension;
167
            }*/
168
        }
169
        $sJsFiles = $this->_render('includes.js', ['aUrls' => $aJsFiles]);
170
171
        $sJsCode = '';
172
        foreach($this->aGenerators as $xGenerator)
173
        {
174
            $sJsCode = rtrim($sJsCode, " \n") . "\n" . $xGenerator->getJs();
175
        }
176
        return $sJsFiles . "\n" . rtrim($sJsCode, " \n") . "\n";
177
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
178
179
    /**
180
     * Get the javascript code to be sent to the browser
181
     *
182
     * @return string
183
     */
184
    private function _getScript()
185
    {
186
        $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...
187
        $sReadyScript = '';
188
        foreach($this->aGenerators as $xGenerator)
189
        {
190
            $sScript .= rtrim($xGenerator->getScript(), " \n") . "\n";
191
            if($xGenerator->readyEnabled() && !$xGenerator->readyInlined())
192
            {
193
                // Ready code which can nbe exported to an external file.
194
                $sReadyScript .= rtrim($xGenerator->getReadyScript(), " \n") . "\n";
195
            }
196
        }
197
198
        // These three parts are always rendered together
199
        $aConfigVars = $this->getOptionVars();
200
        return $this->_render('config.js', $aConfigVars) . "\n" . $sScript . "\n" .
201
            $this->_render('ready.js', ['sScript' => $sReadyScript]);
202
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
203
204
    /**
205
     * Get the javascript code to include directly in HTML
206
     *
207
     * @return string
208
     */
209
    private function _getInlineScript()
210
    {
211
        $sScript = '';
212
        foreach($this->aGenerators as $xGenerator)
213
        {
214
            if($xGenerator->readyEnabled() && $xGenerator->readyInlined())
215
            {
216
                // Ready code which must be inlined in HTML.
217
                $sScript .= rtrim($xGenerator->getReadyScript(), " \n") . "\n";
218
            }
219
        }
220
        return $this->_render('ready.js', ['sScript' => $sScript]);
221
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
222
223
    /**
224
     * Get the javascript file name
225
     *
226
     * @return void
227
     */
228
    private function getJsFileName()
229
    {
230
        // Check config options
231
        // - The js.app.export option must be set to true
232
        // - The js.app.uri and js.app.dir options must be set to non null values
233
        if(!$this->getOption('js.app.export') ||
234
            !$this->getOption('js.app.uri') ||
235
            !$this->getOption('js.app.dir'))
236
        {
237
            return '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '' returns the type string which is incompatible with the documented return type void.
Loading history...
238
        }
239
240
        // The file name
241
        return $this->hasOption('js.app.file') ? $this->getOption('js.app.file') : $this->getHash();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hasOption(...le') : $this->getHash() also could return the type string which is incompatible with the documented return type void.
Loading history...
242
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
243
244
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $sJsDirectory should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $sJsFileName should have a doc-comment as per coding-style.
Loading history...
245
     * Write javascript files and return the corresponding URI
246
     *
247
     * @return string
248
     */
249
    public function createFiles($sJsDirectory, $sJsFileName)
250
    {
251
        // Check dir access
252
        // - The js.app.dir must be writable
253
        if(!$sJsFileName || !is_dir($sJsDirectory) || !is_writable($sJsDirectory))
254
        {
255
            return '';
256
        }
257
258
        $sOutFile = $sJsFileName . '.js';
259
        $sMinFile = $sJsFileName . '.min.js';
260
        if(!is_file($sJsDirectory . $sOutFile))
261
        {
262
            if(!file_put_contents($sJsDirectory . $sOutFile, $this->_getScript()))
263
            {
264
                return '';
265
            }
266
        }
267
        if(($this->getOption('js.app.minify')) && !is_file($sJsDirectory . $sMinFile))
268
        {
269
            if(!$this->minify($sJsDirectory . $sOutFile, $sJsDirectory . $sMinFile))
270
            {
271
                return '';
272
            }
273
        }
274
275
        $sJsAppUri = rtrim($this->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...
276
        $sJsExtension = $this->getOption('js.app.minify') ? '.min.js' : '.js';
277
        return $sJsAppUri . $sJsFileName . $sJsExtension;
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 be sent to the browser
282
     *
283
     * @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; 9 found
Loading history...
284
     * @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...
285
     *
286
     * @return string
287
     */
288
    public function getScript($bIncludeJs, $bIncludeCss)
289
    {
290
        if(!$this->getOption('core.request.uri'))
291
        {
292
            $this->setOption('core.request.uri', jaxon()->di()->get(URI::class)->detect());
293
        }
294
295
        $sScript = '';
296
        if(($bIncludeCss))
297
        {
298
            $sScript .= $this->getCss() . "\n";
299
        }
300
        if(($bIncludeJs))
301
        {
302
            $sScript .= $this->getJs() . "\n";
303
        }
304
305
        $sJsDirectory = rtrim($this->getOption('js.app.dir'), '/') . '/';
306
        $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...
Bug introduced by
Are you sure the usage of $this->getJsFileName() targeting Jaxon\Plugin\Code\Generator::getJsFileName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
307
        if(($sUrl))
308
        {
309
            return $sScript . $this->_render('include.js', ['sUrl' => $sUrl]) . "\n" .
310
                $this->_render('wrapper.js', ['sScript' => $this->_getInlineScript()]);
311
        }
312
313
        return $sScript . $this->_render('wrapper.js', [
314
            'sScript' => $this->_getScript() . "\n" . $this->_getInlineScript()
315
        ]);
316
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
317
}
318