Issues (1519)

system/modules/View/View.php (10 issues)

1
<?php
2
3
namespace Inji;
4
5
use Inji\View\Page;
6
use Inji\View\Template;
7
8
/**
9
 * View module
10
 *
11
 * Rendering pages, contents and widgets
12
 *
13
 * @author Alexey Krupskiy <[email protected]>
14
 * @link http://inji.ru/
15
 * @copyright 2015 Alexey Krupskiy
16
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
17
 */
18
class View extends Module {
19
    public $name = 'View';
20
    public $title = 'No title';
21
22
    /**
23
     * @var View\Template
24
     */
25
    public $template = null;
26
    public $libAssets = ['css' => [], 'js' => []];
27
    public $dynAssets = ['css' => [], 'js' => []];
28
    public $dynMetas = [];
29
    public $viewedContent = '';
30
    public $contentData = [];
31
    public $templatesPath = '';
32
    public $loadedCss = [];
33
    public $loadedJs = [];
34
35
    public function init() {
36
        if (!empty($this->app->config['site']['name'])) {
37
            $this->title = $this->app->config['site']['name'];
38
        }
39
        //$this->resolveTemplate();
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
40
    }
41
42
    public function templatesPath() {
43
        return $this->app->path . "/templates";
44
    }
45
46
47
    public function page($params = []) {
48
        return new Page($params, $this->app);
49
    }
50
51
    public function content($params = []) {
52
53
        $this->paramsParse($params);
0 ignored issues
show
The method paramsParse() does not exist on Inji\View. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

53
        $this->/** @scrutinizer ignore-call */ 
54
               paramsParse($params);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
54
55
        if (empty($this->template->config['noSysMsgAutoShow'])) {
56
            Msg::show();
57
        }
58
        if (!file_exists($this->template->contentPath)) {
59
            echo 'Content not found';
60
        } else {
61
            extract($this->contentData);
62
            include $this->template->contentPath;
63
        }
64
    }
65
66
    public function parentContent($contentName = '') {
67
        if (!$contentName) {
68
            $contentName = $this->template->content;
69
        }
70
71
        $paths = $this->template->getContentPaths($contentName);
72
73
        $data = [];
74
        $exist = false;
75
        foreach ($paths as $type => $path) {
0 ignored issues
show
The expression $paths of type string is not traversable.
Loading history...
76
            if (substr($path, 0, strrpos($path, '/')) == substr($this->template->contentPath, 0, strrpos($this->template->contentPath, '/'))) {
77
                $exist = true;
78
                continue;
79
            }
80
            if (file_exists($path) && $exist) {
81
                $data['contentPath'] = $path;
82
                $data['content'] = $contentName;
83
                break;
84
            }
85
        }
86
        if (!$data) {
87
            echo 'Content not found';
88
        } else {
89
            extract($this->contentData);
90
            include $data['contentPath'];
91
        }
92
    }
93
94
95
    public function getHref($type, $params) {
96
        $href = '';
97
        if (is_string($params)) {
98
            $href = $params;
99
        } elseif (empty($params['template']) && !empty($params['file'])) {
100
            $href = ($this->app->type != 'app' ? '/' . $this->app->name : '') . $params['file'];
101
        } elseif (!empty($params['template']) && !empty($params['file'])) {
102
            $href = $this->app->templatesPath . "/{$this->template->name}/{$type}/{$params['file']}";
103
        }
104
        return $href;
105
    }
106
107
    public function checkNeedLibs() {
108
        if (!empty($this->template->config['libs'])) {
109
            foreach ($this->template->config['libs'] as $libName => $libOptions) {
110
                if (!is_array($libOptions)) {
111
                    $libName = $libOptions;
112
                    $libOptions = [];
113
                }
114
                $this->app->libs->loadLib($libName, $libOptions);
0 ignored issues
show
The method loadLib() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

114
                $this->app->libs->/** @scrutinizer ignore-call */ 
115
                                  loadLib($libName, $libOptions);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
The method loadLib() does not exist on Inji\Module. It seems like you code against a sub-type of Inji\Module such as Inji\Libs or Inji\Db. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

114
                $this->app->libs->/** @scrutinizer ignore-call */ 
115
                                  loadLib($libName, $libOptions);
Loading history...
Bug Best Practice introduced by
The property libs does not exist on Inji\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
115
            }
116
        }
117
        foreach ($this->dynAssets['js'] as $asset) {
118
            if (is_array($asset) && !empty($asset['libs'])) {
119
                foreach ($asset['libs'] as $libName) {
120
                    $this->app->libs->loadLib($libName);
121
                }
122
            }
123
        }
124
        foreach ($this->libAssets['js'] as $asset) {
125
            if (is_array($asset) && !empty($asset['libs'])) {
126
                foreach ($asset['libs'] as $libName) {
127
                    $this->app->libs->loadLib($libName);
128
                }
129
            }
130
        }
131
    }
132
133
134
135
    public function parseCss() {
136
        $css = $this->getCss();
137
        $urls = [];
138
        $timeStr = '';
139
        $cssAll = '';
140
        $exclude = ['^http:', '^https:', '^//'];
141
        foreach ($css as $href) {
142
            if (!empty($this->loadedCss[$href])) {
143
                continue;
144
            }
145
            foreach ($exclude as $item) {
146
                if (preg_match("!{$item}!", $href)) {
147
                    echo "\n        <link href='{$href}' rel='stylesheet' type='text/css' />";
148
                    continue;
149
                }
150
            }
151
            $path = $this->app->staticLoader->parsePath($href);
0 ignored issues
show
The method parsePath() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

151
            /** @scrutinizer ignore-call */ 
152
            $path = $this->app->staticLoader->parsePath($href);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug Best Practice introduced by
The property staticLoader does not exist on Inji\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
The method parsePath() does not exist on Inji\Module. It seems like you code against a sub-type of Inji\Module such as Inji\StaticLoader or Inji\Db. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

151
            /** @scrutinizer ignore-call */ 
152
            $path = $this->app->staticLoader->parsePath($href);
Loading history...
152
            if (file_exists($path)) {
153
                $this->loadedCss[$href] = $href;
154
                $urls[$href] = $path;
155
                $timeStr .= filemtime($path);
156
            } else {
157
                echo "\n        <link href='{$href}' rel='stylesheet' type='text/css' />";
158
            }
159
        }
160
        if (!$urls) {
161
            return;
162
        }
163
        $timeMd5 = md5($timeStr);
164
        $cacheDir = Cache::getDir('static');
165
        if (!file_exists($cacheDir . 'all' . $timeMd5 . '.css')) {
166
            foreach ($urls as $primaryUrl => $url) {
167
                $source = file_get_contents($url);
168
                $rootPath = substr($primaryUrl, 0, strrpos($primaryUrl, '/'));
169
                $levelUpPath = substr($rootPath, 0, strrpos($rootPath, '/'));
170
                $source = preg_replace('!url\((\'?"?)[\.]{2}!isU', 'url($1' . $levelUpPath, $source);
171
                $source = preg_replace('!url\((\'?"?)[\.]{1}!isU', 'url($1' . $rootPath, $source);
172
                $source = preg_replace('#url\(([\'"]){1}(?!http|https|/|data\:)([^/])#isU', 'url($1' . $rootPath . '/$2', $source);
173
                $source = preg_replace('#url\((?!http|https|/|data\:|\'|")([^/])#isU', 'url(' . $rootPath . '/$1$2', $source);
174
                $cssAll .= $source . "\n";
175
            }
176
            file_put_contents($cacheDir . 'all' . $timeMd5 . '.css', $cssAll);
177
        }
178
        $id = 'css' . Tools::randomString();
179
        echo "\n        <link id='{$id}' href='/{$cacheDir}all{$timeMd5}.css' rel='stylesheet' type='text/css' />";
180
        if (!empty($this->template->config['staticUpdater'])) {
181
            $hash = json_encode(array_keys($urls));
182
            if (!empty($this->template->config['staticUpdaterSalt'])) {
183
                $hash .= $this->template->config['staticUpdaterSalt'];
184
            }
185
            $hash = md5($hash);
186
            ?>
187
            <script>
188
                setInterval(function () {
189
                    var hash = '<?=$hash;?>';
190
                    var files = '<?=http_build_query(['files' => array_keys($urls)]);?>';
191
                    var timeHash = '<?=$timeMd5?>';
192
                    var id = '<?=$id;?>';
193
                    // 1. Создаём новый объект XMLHttpRequest
194
                    var xhr = new XMLHttpRequest();
195
196
                    // 2. Конфигурируем его: GET-запрос на URL 'phones.json'
197
                    xhr.open('GET', '/view/checkStaticUpdates/' + hash + '/' + timeHash + '?' + files, false);
198
199
                    // 3. Отсылаем запрос
200
                    xhr.send();
201
202
                    // 4. Если код ответа сервера не 200, то это ошибка
203
                    if (xhr.status != 200) {
204
                        // обработать ошибку
205
                        //alert(xhr.status + ': ' + xhr.statusText); // пример вывода: 404: Not Found
206
                    } else {
207
                        if (xhr.responseText.length > 0) {
208
                            var result = JSON.parse(xhr.responseText);
209
                            document.getElementById(id).href = result.path;
210
                            timeHash = result.timeHash;
211
                        }
212
                        // вывести результат
213
                        //alert(xhr.responseText); // responseText -- текст ответа.
214
                    }
215
                }, 2000);
216
            </script>
217
            <?php
218
        }
219
220
    }
221
222
    public function getCss() {
223
        $css = [];
224
        if (!empty($this->libAssets['css'])) {
225
            $this->ResolveCssHref($this->libAssets['css'], 'libs', $css);
226
        }
227
        if (!empty($this->template->config['css'])) {
228
            $this->ResolveCssHref($this->template->config['css'], 'template', $css);
229
        }
230
        if (!empty($this->dynAssets['css'])) {
231
            $this->ResolveCssHref($this->dynAssets['css'], 'custom', $css);
232
        }
233
        return $css;
234
    }
235
236
    public function ResolveCssHref($cssArray, $type = 'custom', &$hrefs) {
237
        switch ($type) {
238
            case 'libs':
239
                foreach ($cssArray as $css) {
240
                    if (is_array($css)) {
241
                        $this->ResolveCssHref($css, $type, $hrefs);
242
                        continue;
243
                    }
244
                    $hrefs[$css] = $css;
245
                }
246
                break;
247
            case 'template':
248
                foreach ($cssArray as $css) {
249
                    if (is_array($css)) {
250
                        $this->ResolveCssHref($css, $type, $hrefs);
251
                        continue;
252
                    }
253
                    if (strpos($css, '://') !== false) {
254
                        $href = $css;
255
                    } else {
256
                        $href = $this->app->templatesPath . "/{$this->template->name}/css/{$css}";
257
                    }
258
                    $hrefs[$href] = $href;
259
                }
260
                break;
261
            case 'custom':
262
                foreach ($cssArray as $css) {
263
                    if (is_array($css)) {
264
                        $this->ResolveCssHref($css, $type, $hrefs);
265
                        continue;
266
                    }
267
                    if (strpos($css, '//') !== false) {
268
                        $href = $css;
269
                    } else {
270
                        $href = ($this->app->type != 'app' ? '/' . $this->app->name : '') . $css;
271
                    }
272
                    $hrefs[$href] = $href;
273
                }
274
                break;
275
        }
276
    }
277
278
279
    public function addMetaTag($meta) {
280
        if (!empty($meta['name'])) {
281
            $this->dynMetas['metaName:' . $meta['name']] = $meta;
282
        } elseif (!empty($meta['property'])) {
283
            $this->dynMetas['metaProperty:' . $meta['property']] = $meta;
284
        }
285
    }
286
287
    public function bodyEnd() {
288
        $this->checkNeedLibs();
289
        $this->parseCss();
290
        $scripts = $this->getScripts();
291
        $onLoadModules = [];
292
        $scriptAll = '';
293
        $urls = [];
294
        $nativeUrl = [];
295
        $timeStr = '';
296
        $noParsedScripts = [];
297
        foreach ($scripts as $script) {
298
            if (is_string($script)) {
299
                if (!empty($urls[$script])) {
300
                    continue;
301
                }
302
303
                $path = $this->app->staticLoader->parsePath($script);
0 ignored issues
show
Bug Best Practice introduced by
The property staticLoader does not exist on Inji\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
304
                if (file_exists($path)) {
305
                    $nativeUrl[$script] = $script;
306
                    $urls[$script] = $path;
307
                    $timeStr .= filemtime($path);
308
                } else {
309
                    $noParsedScripts[$script] = $script;
310
                }
311
            } elseif (!empty($script['file'])) {
312
                if (!empty($urls[$script['file']])) {
313
                    continue;
314
                }
315
316
                $path = $this->app->staticLoader->parsePath($script['file']);
317
                if (file_exists($path)) {
318
                    $nativeUrl[$script['file']] = $script['file'];
319
                    $urls[$script['file']] = $path;
320
                    if (!empty($script['name'])) {
321
                        $onLoadModules[$script['name']] = $script['name'];
322
                    }
323
                    $timeStr .= filemtime($path);
324
                } else {
325
                    $noParsedScripts[$script['file']] = $script['file'];
326
                }
327
            }
328
        }
329
330
        $timeMd5 = md5($timeStr);
331
        $cacheDir = Cache::getDir('static');
332
        if (!file_exists($cacheDir . 'all' . $timeMd5 . '.js')) {
333
            foreach ($urls as $url) {
334
                $scriptAll .= ";\n" . file_get_contents($url);
335
            }
336
            file_put_contents($cacheDir . 'all' . $timeMd5 . '.js', $scriptAll);
337
        }
338
        $options = [
339
            'scripts' => array_values($noParsedScripts),
340
            'compresedScripts' => $nativeUrl,
341
            'styles' => [],
342
            'appRoot' => $this->app->type == 'app' ? '/' : '/' . $this->app->name . '/',
343
            'onLoadModules' => $onLoadModules
344
        ];
345
        $options['scripts'][] = '/' . $cacheDir . 'all' . $timeMd5 . '.js';
346
        $this->widget('View\bodyEnd', compact('options'));
347
    }
348
349
    public function getScripts() {
350
        $scripts = [];
351
        if (!empty($this->libAssets['js'])) {
352
            $this->genScriptArray($this->libAssets['js'], 'libs', $scripts);
353
        }
354
        if (!empty($this->dynAssets['js'])) {
355
            $this->genScriptArray($this->dynAssets['js'], 'custom', $scripts);
356
        }
357
        if (!empty($this->template->config['js'])) {
358
            $this->genScriptArray($this->template->config['js'], 'template', $scripts);
359
        }
360
        return $scripts;
361
    }
362
363
    public function genScriptArray($jsArray, $type = 'custom', &$resultArray) {
364
        switch ($type) {
365
            case 'libs':
366
                foreach ($jsArray as $js) {
367
                    if (is_array($js)) {
368
                        $this->genScriptArray($js, $type, $resultArray);
369
                        continue;
370
                    }
371
                    if (strpos($js, '//') !== false) {
372
                        $href = $js;
373
                    } else {
374
                        $href = $this->getHref('js', $js);
375
                    }
376
                    if (!$href) {
377
                        continue;
378
                    }
379
380
                    $resultArray[] = $href;
381
                }
382
                break;
383
            case 'template':
384
                foreach ($jsArray as $js) {
385
                    if (is_array($js)) {
386
                        $this->genScriptArray($js, $type, $resultArray);
387
                        continue;
388
                    }
389
                    if (strpos($js, '//') !== false) {
390
                        $href = $js;
391
                    } else {
392
                        $href = $this->app->templatesPath . "/{$this->template->name}/js/{$js}";
393
                    }
394
                    $resultArray[] = $href;
395
                }
396
                break;
397
            case 'custom':
398
                foreach ($jsArray as $js) {
399
                    if (is_array($js)) {
400
                        if (!empty($js[0]) && is_array($js[0])) {
401
                            $this->genScriptArray($js, $type, $resultArray);
402
                            continue;
403
                        }
404
                        $asset = $js;
405
                    } else {
406
                        $asset = [];
407
                    }
408
                    $asset['file'] = $this->getHref('js', $js);
409
                    if (!$asset['file']) {
410
                        continue;
411
                    }
412
                    $resultArray[] = $asset;
413
                }
414
                break;
415
        }
416
    }
417
418
419
420
    public function widget($_widgetName, $_params = [], $lineParams = null) {
421
        $_paths = $this->getWidgetPaths($_widgetName);
422
        $find = false;
423
        foreach ($_paths as $_path) {
424
            if (file_exists($_path)) {
425
                $find = true;
426
                break;
427
            }
428
        }
429
        if ($lineParams === null) {
430
            $lineParams = '';
431
            if ($_params) {
432
                $paramArray = false;
433
                foreach ($_params as $param) {
434
                    if (is_array($param) || is_object($param)) {
435
                        $paramArray = true;
436
                    }
437
                }
438
                if (!$paramArray) {
439
                    $lineParams = ':' . implode(':', $_params);
440
                }
441
            }
442
        }
443
        echo "<!--start:{WIDGET:{$_widgetName}{$lineParams}}-->\n";
444
        if ($find) {
445
            if ($_params && is_array($_params)) {
446
                extract($_params);
447
            }
448
            include $_path;
449
        }
450
        echo "<!--end:{WIDGET:{$_widgetName}{$lineParams}}-->\n";
451
    }
452
453
    public function getWidgetPaths($widgetName) {
454
        $paths = [];
455
        if (strpos($widgetName, '\\')) {
456
            $widgetName = explode('\\', $widgetName);
457
458
            $paths['templatePath_widgetDir'] = $this->templatesPath . '/' . $this->template->name . '/widgets/' . $widgetName[0] . '/' . $widgetName[1] . '/' . $widgetName[1] . '.php';
459
            $paths['templatePath'] = $this->templatesPath . '/' . $this->template->name . '/widgets/' . $widgetName[0] . '/' . $widgetName[1] . '.php';
460
            $modulePaths = Module::getModulePaths(ucfirst($widgetName[0]));
461
            foreach ($modulePaths as $pathName => $path) {
462
                $paths[$pathName . '_widgetDir'] = $path . '/widgets/' . $widgetName[1] . '/' . $widgetName[1] . '.php';
463
                $paths[$pathName] = $path . '/widgets/' . $widgetName[1] . '.php';
464
            }
465
            return $paths;
466
        } else {
467
            $paths['templatePath_widgetDir'] = $this->templatesPath . '/' . $this->template->name . '/widgets/' . $widgetName . '/' . $widgetName . '.php';
468
            $paths['templatePath'] = $this->templatesPath . '/' . $this->template->name . '/widgets/' . $widgetName . '.php';
469
470
            $paths['curAppPath_widgetDir'] = $this->app->path . '/widgets/' . $widgetName . '/' . $widgetName . '.php';
471
            $paths['curAppPath'] = $this->app->path . '/widgets/' . $widgetName . '.php';
472
473
            $paths['systemPath_widgetDir'] = INJI_SYSTEM_DIR . '/widgets/' . $widgetName . '/' . $widgetName . '.php';
474
            $paths['systemPath'] = INJI_SYSTEM_DIR . '/widgets/' . $widgetName . '.php';
475
        }
476
        return $paths;
477
    }
478
}