Passed
Push — master ( caa24b...5f12a0 )
by jelmer
08:43 queued 12s
created

Header::getFirstPossibleSessionTimeout()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 2
nop 0
dl 0
loc 10
ccs 0
cts 8
cp 0
crap 12
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backend\Core\Engine;
4
5
use Common\Core\Header\Asset;
6
use Common\Core\Header\AssetCollection;
7
use Common\Core\Header\JsData;
8
use Common\Core\Header\Minifier;
9
use Common\Core\Header\Priority;
10
use ForkCMS\App\KernelLoader;
11
use Symfony\Component\HttpKernel\KernelInterface;
12
use Backend\Core\Language\Language as BL;
13
14
/**
15
 * This class will be used to alter the head-part of the HTML-document that will be created by he Backend
16
 * Therefore it will handle meta-stuff (title, including JS, including CSS, ...)
17
 */
18
final class Header extends KernelLoader
19
{
20
    /**
21
     * The added css-files
22
     *
23
     * @var AssetCollection
24
     */
25
    private $cssFiles;
26
27
    /**
28
     * Data that will be passed to js
29
     *
30
     * @var JsData
31
     */
32
    private $jsData;
33
34
    /**
35
     * The added js-files
36
     *
37
     * @var AssetCollection
38
     */
39
    private $jsFiles;
40
41
    /**
42
     * Template instance
43
     *
44
     * @var TwigTemplate
45
     */
46
    private $template;
47
48
    /**
49
     * URL-instance
50
     *
51
     * @var Url
52
     */
53
    private $url;
54
55
    public function __construct(KernelInterface $kernel)
56
    {
57
        parent::__construct($kernel);
58
59
        $container = $this->getContainer();
60
        $container->set('header', $this);
61
62
        $this->url = $container->get('url');
63
        $this->template = $container->get('template');
64
65
        $this->cssFiles = new AssetCollection(
66
            Minifier::css(
67
                $container->getParameter('site.path_www'),
68
                BACKEND_CACHE_URL . '/MinifiedCss/',
69
                BACKEND_CACHE_PATH . '/MinifiedCss/'
70
            )
71
        );
72
        $this->jsFiles = new AssetCollection(
73
            Minifier::js(
74
                $container->getParameter('site.path_www'),
75
                BACKEND_CACHE_URL . '/MinifiedJs/',
76
                BACKEND_CACHE_PATH . '/MinifiedJs/'
77
            )
78
        );
79
        $this->jsData = new JsData(
80
            [
81
                'interface_language' => $this->getInterfaceLanguage(),
82
                'debug' => $this->getContainer()->getParameter('kernel.debug'),
83
            ]
84
        );
85
86
        $this->addCoreJs();
87
        $this->addCoreCss();
88
    }
89
90
    private function addCoreJs(): void
91
    {
92
        $this->addJS('/js/vendors/jquery.min.js', 'Core', false, true, true, Priority::core());
93
        $this->addJS('/js/vendors/jquery-migrate.min.js', 'Core', false, true, true, Priority::core());
94
        $this->addJS('/js/vendors/jquery-ui.min.js', 'Core', false, true, true, Priority::core());
95
        $this->addJS('/js/vendors/bootstrap.min.js', 'Core', false, true, true, Priority::core());
96
        $this->addJS('/js/vendors/typeahead.bundle.min.js', 'Core', false, true, true, Priority::core());
97
        $this->addJS('/js/vendors/bootstrap-tagsinput.min.js', 'Core', false, true, true, Priority::core());
98
        $this->addJS('jquery/jquery.backend.js', 'Core', true, false, true, Priority::core());
99
        $this->addJS('utils.js', 'Core', true, false, true, Priority::core());
100
        $this->addJS('backend.js', 'Core', true, false, true, Priority::core());
101
    }
102
103
    private function addCoreCss(): void
104
    {
105
        $this->addCSS('/css/vendors/bootstrap-tagsinput.css', 'Core', true, true, true, Priority::core());
106
        $this->addCSS('/css/vendors/bootstrap-tagsinput-typeahead.css', 'Core', true, true, true, Priority::core());
107
        $this->addCSS('/css/vendors/bootstrap-accessibility.css', 'Core', true, true, true, Priority::core());
108
        $this->addCSS('screen.css', 'Core', false, true, true, Priority::core());
109
        $this->addCSS('debug.css', 'Core', false, true, true, Priority::debug());
110
    }
111
112
    private function buildPathForModule(string $fileName, string $module, string $subDirectory): string
113
    {
114
        if ($module === 'Core') {
115
            return '/src/Backend/Core/' . $subDirectory . '/' . $fileName;
116
        }
117
118
        return '/src/Backend/Modules/' . $module . '/' . $subDirectory . '/' . $fileName;
119
    }
120
121
    /**
122
     * Add a CSS-file.
123
     *
124
     * If you don't specify a module, the current one will be used to automatically create the path to the file.
125
     * Automatic creation of the filename will result in
126
     *   src/Backend/Modules/MODULE/Layout/Css/FILE (for modules)
127
     *   src/Backend/Core/Layout/Css/FILE (for core)
128
     *
129
     * If you set overwritePath to true, the above-described automatic path creation will not happen, instead the
130
     * file-parameter will be used as path; which we then expect to be a full path (It has to start with a slash '/')
131
     *
132
     * @param string $file The name of the file to load.
133
     * @param string $module The module wherein the file is located.
134
     * @param bool $overwritePath Should we overwrite the full path?
135
     *                            An external url will always be handled with $overwritePath as true.
136
     * @param bool $minify Should the CSS be minified?
137
     * @param bool $addTimestamp May we add a timestamp for caching purposes?
138
     * @param Priority $priority the files are added based on the priority
139
     *                           defaults to standard for full links or core or module for core or module css
140
     */
141
    public function addCSS(
142
        string $file,
143
        string $module = null,
144
        bool $overwritePath = false,
145
        bool $minify = true,
146
        bool $addTimestamp = false,
147
        Priority $priority = null
148
    ): void {
149
        $module = $module ?? $this->url->getModule();
150
        $isExternalUrl = $this->get('fork.validator.url')->isExternalUrl($file);
151
        $overwritePath = $overwritePath || $isExternalUrl; // external urls always overwrite the path
152
        $minify = $minify && !$isExternalUrl;
153
154
        $this->cssFiles->add(
155
            new Asset(
156
                $overwritePath ? $file : $this->buildPathForModule($file, $module, 'Layout/Css'),
157
                $addTimestamp,
158
                $priority ?? ($overwritePath ? Priority::standard() : Priority::forModule($module))
159
            ),
160
            $minify
161
        );
162
    }
163
164
    /**
165
     * Add a JS-file.
166
     * If you don't specify a module, the current one will be used
167
     * If you set overwritePath to true we expect a full path (It has to start with a /)
168
     *
169
     * @param string $file The file to load.
170
     * @param string $module The module wherein the file is located.
171
     * @param bool $minify Should the javascript be minified?
172
     * @param bool $overwritePath Should we overwrite the full path?
173
     *                            An external url will always be handled with $overwritePath as true.
174
     * @param bool $addTimestamp May we add a timestamp for caching purposes?
175
     * @param Priority $priority the files are added based on the priority
176
     *                           defaults to standard for full links or core or module for core or module css
177
     */
178
    public function addJS(
179
        string $file,
180
        string $module = null,
181
        bool $minify = true,
182
        bool $overwritePath = false,
183
        bool $addTimestamp = false,
184
        Priority $priority = null
185
    ): void {
186
        $module = $module ?? $this->url->getModule();
187
        $isExternalUrl = $this->get('fork.validator.url')->isExternalUrl($file);
188
        $overwritePath = $overwritePath || $isExternalUrl; // external urls always overwrite the path
189
        $minify = $minify && !$isExternalUrl;
190
191
        $this->jsFiles->add(
192
            new Asset(
193
                $overwritePath ? $file : $this->buildPathForModule($file, $module ?? $this->url->getModule(), 'Js'),
194
                $addTimestamp,
195
                $priority ?? ($overwritePath ? Priority::standard() : Priority::forModule($module))
196
            ),
197
            $minify
198
        );
199
    }
200
201
    /**
202
     * Add data into the jsData
203
     *
204
     * @param string $module The name of the module.
205
     * @param string $key The key under which the value will be stored.
206
     * @param mixed $value The value
207
     */
208
    public function addJsData(string $module, string $key, $value): void
209
    {
210
        $this->jsData->add($module, $key, $value);
211
    }
212
213
    /**
214
     * Parse the header into the template
215
     */
216
    public function parse(): void
217
    {
218
        $this->template->assign('page_title', BL::getLabel($this->url->getModule()));
219
        $this->cssFiles->parse($this->template, 'cssFiles');
220
        $this->jsFiles->parse($this->template, 'jsFiles');
221
222
        $this->jsData->add('site', 'domain', SITE_DOMAIN);
223
        $this->jsData->add('editor', 'language', $this->getCKEditorLanguage());
224
        $this->jsData->add('Core', 'session_timeout', $this->getFirstPossibleSessionTimeout());
225
226
        if (!empty($this->get('fork.settings')->get('Core', 'theme'))) {
227
            $this->jsData->add('theme', 'theme', $this->get('fork.settings')->get('Core', 'theme'));
228
            $themePath = FRONTEND_PATH . '/Themes/' . $this->get('fork.settings')->get('Core', 'theme');
229
            $this->jsData->add('theme', 'path', $themePath);
230
            $this->jsData->add('theme', 'has_css', is_file($themePath . '/Core/Layout/Css/screen.css'));
231
            $this->jsData->add('theme', 'has_editor_css', is_file($themePath . '/Core/Layout/Css/editor_content.css'));
232
        }
233
        $this->template->assign('jsData', $this->jsData);
234
    }
235
236
    private function getFirstPossibleSessionTimeout(): int
237
    {
238
        $garbageCollectionMaxLifeTime = (int) ini_get('session.gc_maxlifetime');
239
        $cookieLifetime = (int) ini_get('session.cookie_lifetime');
240
241
        if ($cookieLifetime === 0 || $cookieLifetime < $garbageCollectionMaxLifeTime) {
242
            return $garbageCollectionMaxLifeTime;
243
        }
244
245
        return $cookieLifetime;
246
    }
247
248
    /**
249
     * @return string
250
     */
251
    private function getInterfaceLanguage(): string
252
    {
253
        if (Authentication::getUser()->isAuthenticated()) {
254
            return (string) Authentication::getUser()->getSetting('interface_language');
255
        }
256
257
        return BL::getInterfaceLanguage();
258
    }
259
260
    /**
261
     * @return string
262
     */
263
    private function getCKEditorLanguage(): string
264
    {
265
        $language = $this->getInterfaceLanguage();
266
267
        // CKeditor has support for simplified Chinese, but the language is called zh-cn instead of zn
268
        if ($language === 'zh') {
269
            return 'zh-cn';
270
        }
271
272
        return $language;
273
    }
274
275
    public function appendDetailToBreadcrumbs(string $stringToAppend): void
276
    {
277
        $this->template->assignGlobal('breadcrumbDetail', $stringToAppend);
278
    }
279
}
280