Completed
Branch unit-test-asset-handler-connec... (029d08)
by Romain
01:55
created

JavaScriptAssetHandlerConnector   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 349
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 14
dl 0
loc 349
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A includeDefaultJavaScriptFiles() 0 15 3
A includeGeneratedJavaScript() 0 7 1
B includeLanguageJavaScriptFiles() 0 24 1
A includeFormzConfigurationJavaScriptFile() 0 20 1
A generateAndIncludeJavaScript() 0 49 2
A getJavaScriptFiles() 0 17 2
A saveAndGetJavaScriptFiles() 0 15 1
B generateAndIncludeInlineJavaScript() 0 31 2
A includeJavaScriptValidationFiles() 0 13 3
A getFormInitializationJavaScriptAssetHandler() 0 6 1
A getFieldsValidationJavaScriptAssetHandler() 0 6 1
A getFieldsActivationJavaScriptAssetHandler() 0 6 1
A getFieldsValidationActivationJavaScriptAssetHandler() 0 6 1
A getFormRequestDataJavaScriptAssetHandler() 0 6 1
1
<?php
2
/*
3
 * 2016 Romain CANON <[email protected]>
4
 *
5
 * This file is part of the TYPO3 Formz project.
6
 * It is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License, either
8
 * version 3 of the License, or any later version.
9
 *
10
 * For the full copyright and license information, see:
11
 * http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Romm\Formz\AssetHandler\Connector;
15
16
use Romm\Formz\AssetHandler\JavaScript\FieldsActivationJavaScriptAssetHandler;
17
use Romm\Formz\AssetHandler\JavaScript\FieldsValidationActivationJavaScriptAssetHandler;
18
use Romm\Formz\AssetHandler\JavaScript\FieldsValidationJavaScriptAssetHandler;
19
use Romm\Formz\AssetHandler\JavaScript\FormInitializationJavaScriptAssetHandler;
20
use Romm\Formz\AssetHandler\JavaScript\FormRequestDataJavaScriptAssetHandler;
21
use Romm\Formz\AssetHandler\JavaScript\FormzConfigurationJavaScriptAssetHandler;
22
use Romm\Formz\AssetHandler\JavaScript\FormzLocalizationJavaScriptAssetHandler;
23
use Romm\Formz\Condition\Processor\ConditionProcessorFactory;
24
use Romm\Formz\Core\Core;
25
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
26
27
class JavaScriptAssetHandlerConnector
28
{
29
    /**
30
     * List of JavaScript files which will be included whenever this view helper
31
     * is used.
32
     *
33
     * @var array
34
     */
35
    private $javaScriptFiles = [
36
        'Formz.Main.js',
37
        'Formz.Misc.js',
38
        'Formz.EventsManager.js',
39
        'Formz.Result.js',
40
        'Formz.Localization.js',
41
        'Form/Formz.Form.js',
42
        'Form/Formz.Form.SubmissionService.js',
43
        'Field/Formz.Field.js',
44
        'Field/Formz.Field.DataAttributesService.js',
45
        'Field/Formz.Field.ValidationService.js',
46
        'Conditions/Formz.Condition.js',
47
        'Validators/Formz.Validation.js',
48
        'Validators/Formz.Validator.Ajax.js'
49
    ];
50
51
    /**
52
     * @var AssetHandlerConnectorManager
53
     */
54
    private $assetHandlerConnectorManager;
55
56
    /**
57
     * @param AssetHandlerConnectorManager $assetHandlerConnectorManager
58
     */
59
    public function __construct(AssetHandlerConnectorManager $assetHandlerConnectorManager)
60
    {
61
        $this->assetHandlerConnectorManager = $assetHandlerConnectorManager;
62
    }
63
64
    /**
65
     * Will include all default JavaScript files declared in the property
66
     * `$javaScriptFiles` of this class, as well as the main Formz
67
     * configuration.
68
     *
69
     * @return $this
70
     */
71
    public function includeDefaultJavaScriptFiles()
72
    {
73
        if (Core::get()->isInDebugMode()) {
74
            $this->javaScriptFiles[] = 'Formz.Debug.js';
75
        }
76
77
        foreach ($this->javaScriptFiles as $file) {
78
            $filePath = Core::get()->getExtensionRelativePath('Resources/Public/JavaScript/' . $file);
79
            $this->assetHandlerConnectorManager->getPageRenderer()->addJsFile($filePath);
80
        }
81
82
        $this->includeFormzConfigurationJavaScriptFile();
83
84
        return $this;
85
    }
86
87
    /**
88
     * Will take care of generating the JavaScript with the
89
     * `AssetHandlerFactory`. The code will be put in a `.js` file in the
90
     * `typo3temp` directory.
91
     *
92
     * If the file already exists, it is included directly before the code
93
     * generation.
94
     *
95
     * @return $this
96
     */
97
    public function includeGeneratedJavaScript()
98
    {
99
        $this->generateAndIncludeJavaScript();
100
        $this->generateAndIncludeInlineJavaScript();
101
102
        return $this;
103
    }
104
105
    /**
106
     * This function will handle the JavaScript language files.
107
     *
108
     * A file will be created for the current language (there can be as many
109
     * files as languages), containing the translations handling for JavaScript.
110
     * If the file already exists, it is directly included.
111
     *
112
     * @return $this
113
     */
114
    public function includeLanguageJavaScriptFiles()
115
    {
116
        $filePath = $this->assetHandlerConnectorManager->getFormzGeneratedFilePath('local-' . Core::get()->getLanguageKey()) . '.js';
117
118
        $this->assetHandlerConnectorManager->createFileInTemporaryDirectory(
119
            $filePath,
120
            function() {
121
                /** @var FormzLocalizationJavaScriptAssetHandler $formzLocalizationJavaScriptAssetHandler */
122
                $formzLocalizationJavaScriptAssetHandler = $this->assetHandlerConnectorManager
123
                    ->getAssetHandlerFactory()
124
                    ->getAssetHandler(FormzLocalizationJavaScriptAssetHandler::class);
125
126
                return $formzLocalizationJavaScriptAssetHandler
127
                    ->injectTranslationsForFormFieldsValidation()
128
                    ->getJavaScriptCode();
129
            }
130
        );
131
132
        $this->assetHandlerConnectorManager
133
            ->getPageRenderer()
134
            ->addJsFooterFile($filePath);
135
136
        return $this;
137
    }
138
139
    /**
140
     * Includes Formz configuration JavaScript declaration. If the file exists,
141
     * it is directly included, otherwise the JavaScript code is calculated,
142
     * then put in the cache file.
143
     */
144
    private function includeFormzConfigurationJavaScriptFile()
145
    {
146
        /** @var FormzConfigurationJavaScriptAssetHandler $formzConfigurationJavaScriptAssetHandler */
147
        $formzConfigurationJavaScriptAssetHandler = $this->assetHandlerConnectorManager
148
            ->getAssetHandlerFactory()
149
            ->getAssetHandler(FormzConfigurationJavaScriptAssetHandler::class);
150
151
        $formzConfigurationJavaScriptFileName = $formzConfigurationJavaScriptAssetHandler->getJavaScriptFileName();
152
153
        $this->assetHandlerConnectorManager->createFileInTemporaryDirectory(
154
            $formzConfigurationJavaScriptFileName,
155
            function () use ($formzConfigurationJavaScriptAssetHandler) {
156
                return $formzConfigurationJavaScriptAssetHandler->getJavaScriptCode();
157
            }
158
        );
159
160
        $this->assetHandlerConnectorManager
161
            ->getPageRenderer()
162
            ->addJsFooterFile($formzConfigurationJavaScriptFileName);
163
    }
164
165
    /**
166
     * Will include the generated JavaScript, from multiple asset handlers
167
     * sources.
168
     */
169
    private function generateAndIncludeJavaScript()
170
    {
171
        $formClassName = $this->assetHandlerConnectorManager
172
            ->getAssetHandlerFactory()
173
            ->getFormObject()
174
            ->getClassName();
175
176
        $javaScriptValidationFilesCacheIdentifier = Core::get()
177
            ->getCacheIdentifier('js-files-', $formClassName);
178
179
        $filePath = $this->assetHandlerConnectorManager->getFormzGeneratedFilePath() . '.js';
180
181
        $fileWasCreated = $this->assetHandlerConnectorManager->createFileInTemporaryDirectory(
182
            $filePath,
183
            function () {
184
                // Form initialization code.
185
                return $this->getFormInitializationJavaScriptAssetHandler()
186
                        ->getFormInitializationJavaScriptCode() .
187
                    LF .
188
                    // Fields validation code.
189
                    $this->getFieldsValidationJavaScriptAssetHandler()
190
                        ->process()
191
                        ->getJavaScriptCode() .
192
                    LF .
193
                    // Fields activation conditions code.
194
                    $this->getFieldsActivationJavaScriptAssetHandler()
195
                        ->getFieldsActivationJavaScriptCode() .
196
                    LF .
197
                    // Fields validation activation conditions code.
198
                    $this->getFieldsValidationActivationJavaScriptAssetHandler()
199
                        ->getFieldsValidationActivationJavaScriptCode();
200
            }
201
        );
202
203
        if (true === $fileWasCreated) {
204
            $javaScriptFiles = $this->saveAndGetJavaScriptFiles(
205
                $javaScriptValidationFilesCacheIdentifier,
206
                $this->getFieldsValidationJavaScriptAssetHandler()->getJavaScriptValidationFiles()
207
            );
208
        } else {
209
            $javaScriptFiles = $this->getJavaScriptFiles($javaScriptValidationFilesCacheIdentifier);
210
        }
211
212
        $this->assetHandlerConnectorManager
213
            ->getPageRenderer()
214
            ->addJsFooterFile($filePath);
215
216
        $this->includeJavaScriptValidationFiles($javaScriptFiles);
217
    }
218
219
    /**
220
     * Returns the list of JavaScript files which are used for the current form
221
     * object.
222
     *
223
     * @param string $cacheIdentifier
224
     * @return array
225
     */
226
    private function getJavaScriptFiles($cacheIdentifier)
227
    {
228
        $cacheInstance = Core::get()->getCacheInstance();
229
230
        if ($cacheInstance->has($cacheIdentifier)) {
231
            $javaScriptFiles = $cacheInstance->get($cacheIdentifier);
232
        } else {
233
            $fieldValidationConfigurationAssetHandler = $this->getFieldsValidationJavaScriptAssetHandler()->process();
234
235
            $javaScriptFiles = $this->saveAndGetJavaScriptFiles(
236
                $cacheIdentifier,
237
                $fieldValidationConfigurationAssetHandler->getJavaScriptValidationFiles()
238
            );
239
        }
240
241
        return $javaScriptFiles;
242
    }
243
244
    /**
245
     * Will save in cache and return the list of files which must be included in
246
     * order to make validation rules and conditions work properly.
247
     *
248
     * @param string $cacheIdentifier
249
     * @param array  $javaScriptFiles
250
     * @return array
251
     */
252
    private function saveAndGetJavaScriptFiles($cacheIdentifier, array $javaScriptFiles)
253
    {
254
        $formObject = $this->assetHandlerConnectorManager
255
            ->getAssetHandlerFactory()
256
            ->getFormObject();
257
258
        $conditionProcessor = ConditionProcessorFactory::getInstance()
259
            ->get($formObject);
260
261
        $javaScriptFiles = array_merge($javaScriptFiles, $conditionProcessor->getJavaScriptFiles());
262
263
        Core::get()->getCacheInstance()->set($cacheIdentifier, $javaScriptFiles);
264
265
        return $javaScriptFiles;
266
    }
267
268
    /**
269
     * Here we generate the JavaScript code containing the submitted values, and
270
     * the existing errors, which is dynamically created at each request.
271
     *
272
     * The code is then injected as inline code in the DOM.
273
     */
274
    private function generateAndIncludeInlineJavaScript()
275
    {
276
        $formClassName = $this->assetHandlerConnectorManager
277
            ->getAssetHandlerFactory()
278
            ->getFormObject()
279
            ->getClassName();
280
281
        $javaScriptCode = $this->getFormRequestDataJavaScriptAssetHandler()
282
            ->getFormRequestDataJavaScriptCode();
283
284
        if (Core::get()->isInDebugMode()) {
285
            $javaScriptCode .= LF;
286
            $javaScriptCode .= 'Formz.Debug.activate();';
287
        }
288
289
        /** @var UriBuilder $uriBuilder */
290
        $uriBuilder = Core::get()->getObjectManager()->get(UriBuilder::class);
291
        $uri = $uriBuilder->reset()
292
            ->setTargetPageType(1473682545)
293
            ->setNoCache(true)
294
            ->setUseCacheHash(false)
295
            ->setCreateAbsoluteUri(true)
296
            ->build();
297
298
        $javaScriptCode .= LF;
299
        $javaScriptCode .= "Formz.setAjaxUrl('$uri');";
300
301
        $this->assetHandlerConnectorManager
302
            ->getPageRenderer()
303
            ->addJsFooterInlineCode('Formz - Initialization ' . $formClassName, $javaScriptCode);
304
    }
305
306
    /**
307
     * Will include all new JavaScript files given, by checking that every given
308
     * file was not already included.
309
     *
310
     * @param array $javaScriptValidationFiles List of JavaScript validation files.
311
     */
312
    protected function includeJavaScriptValidationFiles(array $javaScriptValidationFiles)
313
    {
314
        $javaScriptValidationFiles = array_unique($javaScriptValidationFiles);
315
        $assetHandlerConnectorStates = $this->assetHandlerConnectorManager->getAssetHandlerConnectorStates();
316
317
        foreach ($javaScriptValidationFiles as $file) {
318
            if (false === in_array($file, $assetHandlerConnectorStates->getAlreadyIncludedValidationJavaScriptFiles())) {
319
                $path = Core::get()->getResourceRelativePath($file);
320
                $this->assetHandlerConnectorManager->getPageRenderer()->addJsFooterFile($path);
321
                $assetHandlerConnectorStates->registerIncludedValidationJavaScriptFiles($file);
322
            }
323
        }
324
    }
325
326
    /**
327
     * @return FormInitializationJavaScriptAssetHandler
328
     */
329
    protected function getFormInitializationJavaScriptAssetHandler()
330
    {
331
        return $this->assetHandlerConnectorManager
332
            ->getAssetHandlerFactory()
333
            ->getAssetHandler(FormInitializationJavaScriptAssetHandler::class);
334
    }
335
336
    /**
337
     * @return FieldsValidationJavaScriptAssetHandler
338
     */
339
    protected function getFieldsValidationJavaScriptAssetHandler()
340
    {
341
        return $this->assetHandlerConnectorManager
342
            ->getAssetHandlerFactory()
343
            ->getAssetHandler(FieldsValidationJavaScriptAssetHandler::class);
344
    }
345
346
    /**
347
     * @return FieldsActivationJavaScriptAssetHandler
348
     */
349
    protected function getFieldsActivationJavaScriptAssetHandler()
350
    {
351
        return $this->assetHandlerConnectorManager
352
            ->getAssetHandlerFactory()
353
            ->getAssetHandler(FieldsActivationJavaScriptAssetHandler::class);
354
    }
355
356
    /**
357
     * @return FieldsValidationActivationJavaScriptAssetHandler
358
     */
359
    protected function getFieldsValidationActivationJavaScriptAssetHandler()
360
    {
361
        return $this->assetHandlerConnectorManager
362
            ->getAssetHandlerFactory()
363
            ->getAssetHandler(FieldsValidationActivationJavaScriptAssetHandler::class);
364
    }
365
366
    /**
367
     * @return FormRequestDataJavaScriptAssetHandler
368
     */
369
    protected function getFormRequestDataJavaScriptAssetHandler()
370
    {
371
        return $this->assetHandlerConnectorManager
372
            ->getAssetHandlerFactory()
373
            ->getAssetHandler(FormRequestDataJavaScriptAssetHandler::class);
374
    }
375
}
376