CodeGenerator::render()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * CodeGenerator.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\Code;
16
17
use Jaxon\App\I18n\Translator;
18
use Jaxon\Di\Container;
19
use Jaxon\Plugin\AbstractPlugin;
20
use Jaxon\Utils\Http\UriException;
21
use Jaxon\Utils\Template\TemplateEngine;
22
23
use function array_reduce;
24
use function is_subclass_of;
25
use function ksort;
26
use function md5;
27
use function trim;
28
29
class CodeGenerator
30
{
31
    /**
32
     * @var AssetManager
33
     */
34
    private $xAssetManager;
35
36
    /**
37
     * The classes that generate code
38
     *
39
     * @var array<string>
40
     */
41
    protected $aCodeGenerators = [];
42
43
    /**
44
     * @var string
45
     */
46
    protected $sJsOptions;
47
48
    /**
49
     * @var string
50
     */
51
    protected $sCss = '';
52
53
    /**
54
     * @var string
55
     */
56
    protected $sJs = '';
57
58
    /**
59
     * @var string
60
     */
61
    protected $sJsScript = '';
62
63
    /**
64
     * @var string
65
     */
66
    protected $sJsReadyScript = '';
67
68
    /**
69
     * @var string
70
     */
71
    protected $sJsInlineScript = '';
72
73
    /**
74
     * @var string
75
     */
76
    protected $bGenerated = false;
77
78
    /**
79
     * The constructor
80
     *
81
     * @param string $sVersion
82
     * @param Container $di
83
     * @param Translator $xTranslator
84
     * @param TemplateEngine $xTemplateEngine
85
     */
86
    public function __construct(private string $sVersion, private Container $di,
87
        private Translator $xTranslator, private TemplateEngine $xTemplateEngine)
88
    {}
89
90
    /**
91
     * Add a code generator to the list
92
     *
93
     * @param string $sClassName    The code generator class
94
     * @param int $nPriority    The desired priority, used to order the plugins
95
     *
96
     * @return void
97
     */
98
    public function addCodeGenerator(string $sClassName, int $nPriority)
99
    {
100
        while(isset($this->aCodeGenerators[$nPriority]))
101
        {
102
            $nPriority++;
103
        }
104
        $this->aCodeGenerators[$nPriority] = $sClassName;
105
    }
106
107
    /**
108
     * Generate a hash for all the javascript code generated by the library
109
     *
110
     * @return string
111
     */
112
    public function getHash(): string
113
    {
114
        return md5(array_reduce($this->aCodeGenerators,
115
            function($sHash, $sClassName) {
116
                return $sHash . $this->di->g($sClassName)->getHash();
117
            }, $this->sVersion));
118
    }
119
120
    /**
121
     * Render a template in the 'plugins' subdir
122
     *
123
     * @param string $sTemplate    The template filename
124
     * @param array $aVars    The template variables
125
     *
126
     * @return string
127
     */
128
    private function render(string $sTemplate, array $aVars = []): string
129
    {
130
        $aVars['sJsOptions'] = $this->sJsOptions;
131
        return $this->xTemplateEngine->render("jaxon::plugins/$sTemplate", $aVars);
132
    }
133
134
    /**
135
     * Generate the Jaxon CSS and js codes for a given plugin
136
     *
137
     * @param string $sClassName
138
     *
139
     * @return void
140
     */
141
    private function generatePluginCodes(string $sClassName)
142
    {
143
        $xGenerator = $this->di->g($sClassName);
144
        if(!is_subclass_of($xGenerator, AbstractPlugin::class) ||
145
            $this->xAssetManager->shallIncludeAssets($xGenerator))
146
        {
147
            // HTML tags for CSS
148
            $this->sCss = trim($this->sCss) . "\n" . trim($xGenerator->getCss(), " \n");
149
            // HTML tags for js
150
            $this->sJs = trim($this->sJs) . "\n" . trim($xGenerator->getJs(), " \n");
151
        }
152
        // Javascript code
153
        $this->sJsScript = trim($this->sJsScript) . "\n\n" . trim($xGenerator->getScript(), " \n");
154
        if($xGenerator->readyEnabled())
155
        {
156
            $sScriptAttr = $xGenerator->readyInlined() ? 'sJsInlineScript' : 'sJsReadyScript';
157
            $this->$sScriptAttr = trim($this->$sScriptAttr) . "\n\n" .
158
                trim($xGenerator->getReadyScript(), " \n");
159
        }
160
    }
161
162
    /**
163
     * @return string
164
     */
165
    private function getJsInit(): string
166
    {
167
        return '
168
    jaxon.processCustomAttrs();
169
    jaxon.labels && jaxon.labels(' . json_encode($this->xTranslator->translations('labels')) . ');
170
';
171
    }
172
173
    /**
174
     * Render the generated CSS ans js codes
175
     *
176
     * @return void
177
     */
178
    private function renderCodes()
179
    {
180
        $this->sCss = trim($this->sCss, " \n");
181
        $this->sJs = trim($this->sJs, " \n");
182
        $this->sJsScript = trim($this->sJsScript, " \n");
183
        $this->sJsReadyScript = $this->render('ready.js', [
184
            'sScript' => $this->getJsInit() . trim($this->sJsReadyScript, " \n"),
185
        ]);
186
        $this->sJsInlineScript = trim($this->sJsInlineScript, " \n");
187
        if(($this->sJsInlineScript))
188
        {
189
            $this->sJsInlineScript = $this->render('ready.js', [
190
                'sScript' => $this->sJsInlineScript . "\n",
191
            ]);
192
        }
193
        // Prepend Jaxon javascript files to HTML tags for Js
194
        $aJsFiles = $this->xAssetManager->getJsLibFiles();
195
        $this->sJs = trim($this->render('includes.js', [
196
            'aUrls' => $aJsFiles,
197
        ])) . "\n\n" . $this->sJs;
198
    }
199
200
    /**
201
     * Generate the Jaxon CSS ans js codes
202
     *
203
     * @return void
204
     * @throws UriException
205
     */
206
    private function generateCodes()
207
    {
208
        if($this->bGenerated)
209
        {
210
            return;
211
        }
212
213
        // Sort the code generators by ascending priority
214
        ksort($this->aCodeGenerators);
215
216
        $this->xAssetManager = $this->di->getAssetManager();
217
        $this->sJsOptions = $this->xAssetManager->getJsOptions();
218
        foreach($this->aCodeGenerators as $sClassName)
219
        {
220
            $this->generatePluginCodes($sClassName);
221
        }
222
        $this->renderCodes();
223
224
        $sJsConfigVars = $this->render('config.js', $this->xAssetManager->getOptionVars());
225
        // These three parts are always rendered together
226
        $this->sJsScript = trim($sJsConfigVars) . "\n\n" .
227
            trim($this->sJsScript) . "\n\n" . trim($this->sJsReadyScript);
228
229
        // The codes are already generated.
230
        $this->bGenerated = true;
0 ignored issues
show
Documentation Bug introduced by
The property $bGenerated was declared of type string, but true is of type true. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
231
    }
232
233
    /**
234
     * Get the HTML tags to include Jaxon CSS code and files into the page
235
     *
236
     * @return string
237
     * @throws UriException
238
     */
239
    public function getCss(): string
240
    {
241
        $this->generateCodes();
242
        return $this->sCss;
243
    }
244
245
    /**
246
     * Get the HTML tags to include Jaxon javascript files into the page
247
     *
248
     * @return string
249
     * @throws UriException
250
     */
251
    public function getJs(): string
252
    {
253
        $this->generateCodes();
254
        return $this->sJs;
255
    }
256
257
    /**
258
     * Get the generated javascript code
259
     *
260
     * @return string
261
     */
262
    public function getJsScript(): string
263
    {
264
        return $this->sJsScript;
265
    }
266
267
    /**
268
     * Get the javascript code to be sent to the browser
269
     *
270
     * @param bool $bIncludeJs Also get the JS files
271
     * @param bool $bIncludeCss Also get the CSS files
272
     *
273
     * @return string
274
     * @throws UriException
275
     */
276
    public function getScript(bool $bIncludeJs, bool $bIncludeCss): string
277
    {
278
        $this->generateCodes();
279
        $sScript = '';
280
        if(($bIncludeCss))
281
        {
282
            $sScript .= $this->getCss() . "\n";
283
        }
284
        if(($bIncludeJs))
285
        {
286
            $sScript .= $this->getJs() . "\n";
287
        }
288
289
        if(!($sUrl = $this->xAssetManager->createJsFiles($this)))
290
        {
291
            return trim($sScript) . "\n\n" .
292
                $this->render('wrapper.js', [
293
                    'sScript' => trim($this->sJsScript) . "\n\n" .
294
                        trim($this->sJsInlineScript),
295
                ]);
296
        }
297
        return trim($sScript) . "\n\n" .
298
            trim($this->render('include.js', [
299
                'sUrl' => $sUrl,
300
            ])) . "\n\n" .
301
            trim($this->render('wrapper.js', [
302
                'sScript' => $this->sJsInlineScript,
303
            ]));
304
    }
305
}
306