Passed
Push — develop ( f23408...b9e9fb )
by Andrew
09:01
created

MetaScriptContainer   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 19
eloc 85
dl 0
loc 171
ccs 0
cts 80
cp 0
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A normalizeContainerData() 0 7 2
C includeMetaData() 0 101 13
A dataLayerHash() 0 8 2
A render() 0 11 2
1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful,
6
 * and flexible
7
 *
8
 * @link      https://nystudio107.com
9
 * @copyright Copyright (c) 2017 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\models;
13
14
use Craft;
15
use nystudio107\seomatic\base\NonceContainer;
16
use nystudio107\seomatic\helpers\ImageTransform as ImageTransformHelper;
17
use nystudio107\seomatic\Seomatic;
18
use yii\caching\TagDependency;
19
use yii\web\View;
20
21
/**
22
 * @author    nystudio107
23
 * @package   Seomatic
24
 * @since     3.0.0
25
 */
26
class MetaScriptContainer extends NonceContainer
27
{
28
    // Constants
29
    // =========================================================================
30
31
    const CONTAINER_TYPE = 'MetaScriptContainer';
32
33
    // Public Properties
34
    // =========================================================================
35
36
    /**
37
     * The data in this container
38
     *
39
     * @var MetaScript[] $data
40
     */
41
    public $data = [];
42
43
    /**
44
     * @var int
45
     */
46
    public $position = View::POS_HEAD;
47
48
    // Public Methods
49
    // =========================================================================
50
51
    /**
52
     * @inheritdoc
53
     */
54
    public function includeMetaData($dependency)
55
    {
56
        Craft::beginProfile('MetaScriptContainer::includeMetaData', __METHOD__);
57
        $uniqueKey = $this->handle . $dependency->tags[3] . $this->dataLayerHash();
58
        $cache = Craft::$app->getCache();
59
        if ($this->clearCache) {
60
            TagDependency::invalidate($cache, $dependency->tags[3]);
61
        }
62
        $tagData = $cache->getOrSet(
63
            self::CONTAINER_TYPE . $uniqueKey,
64
            function () use ($uniqueKey) {
65
                Craft::info(
66
                    self::CONTAINER_TYPE . ' cache miss: ' . $uniqueKey,
67
                    __METHOD__
68
                );
69
                $tagData = [];
70
                if ($this->prepForInclusion()) {
71
                    /** @var $metaScriptModel MetaScript */
72
                    foreach ($this->data as $metaScriptModel) {
73
                        if ($metaScriptModel->include) {
74
                            // The regular script JS
75
                            $js = $metaScriptModel->render();
76
                            if (!empty($js)) {
77
                                $scenario = $this->scenario;
78
                                $metaScriptModel->setScenario('render');
79
                                $options = $metaScriptModel->tagAttributes();
80
                                $metaScriptModel->setScenario($scenario);
81
                                $tagData[] = [
82
                                    'js' => $js,
83
                                    'position' => $metaScriptModel->position ?? $this->position,
84
                                    'nonce' => $metaScriptModel->nonce ?? null,
85
                                    'tagAttrs' => $options,
86
                                    'bodyJs' => false,
87
                                ];
88
                                // If `devMode` is enabled, validate the Meta Script and output any model errors
89
                                if (Seomatic::$devMode) {
90
                                    $metaScriptModel->debugMetaItem(
91
                                        'Script attribute: '
92
                                    );
93
                                }
94
                            }
95
                            // The body script JS (has no wrapping <script></script> tags, as it can be arbitrary HTML)
96
                            $bodyJs = $metaScriptModel->renderBodyHtml();
97
                            if (!empty($bodyJs)) {
98
                                $scenario = $this->scenario;
99
                                $metaScriptModel->setScenario('render');
100
                                $options = $metaScriptModel->tagAttributes();
101
                                $metaScriptModel->setScenario($scenario);
102
                                $tagData[] = [
103
                                    'js' => $bodyJs,
104
                                    'position' => $metaScriptModel->bodyPosition ?? $this->position,
105
                                    'nonce' => $metaScriptModel->nonce ?? null,
106
                                    'tagAttrs' => $options,
107
                                    'bodyJs' => true,
108
                                ];
109
                                // If `devMode` is enabled, validate the Meta Script and output any model errors
110
                                if (Seomatic::$devMode) {
111
                                    $metaScriptModel->debugMetaItem(
112
                                        'Script attribute: '
113
                                    );
114
                                }
115
                            }
116
                        }
117
                    }
118
                }
119
120
                return $tagData;
121
            },
122
            Seomatic::$cacheDuration,
123
            $dependency
124
        );
125
        // Invalidate the cache we just created if there were pending image transforms in it
126
        if (ImageTransformHelper::$pendingImageTransforms) {
127
            TagDependency::invalidate($cache, $dependency->tags[3]);
128
        }
129
        // Register the tags
130
        foreach ($tagData as $config) {
131
            // Register the tags
132
            $attrs = $config['tagAttrs'] ?? [];
133
            if (!empty($config['nonce'])) {
134
                /** @noinspection SlowArrayOperationsInLoopInspection */
135
                $attrs = array_merge($attrs, [
136
                    'nonce' => $config['nonce'],
137
                ]);
138
            }
139
            $bodyJs = $config['bodyJs'] ?? false;
140
            if ($bodyJs) {
141
                Seomatic::$view->registerHtml(
142
                    $config['js'],
143
                    $config['position'],
144
                );
145
            } else {
146
                Seomatic::$view->registerScript(
147
                    $config['js'],
148
                    $config['position'],
149
                    $attrs
150
                );
151
            }
152
        }
153
154
        Craft::endProfile('MetaScriptContainer::includeMetaData', __METHOD__);
155
    }
156
157
    /**
158
     * @inheritdoc
159
     */
160
    public function render(array $params = []): string
161
    {
162
        $html = parent::render($params);
163
        if ($params['renderScriptTags']) {
164
            $html =
165
                '<script>'
166
                . $html
167
                . '</script>';
168
        }
169
170
        return $html;
171
    }
172
173
    /**
174
     * @inheritdoc
175
     */
176
    public function normalizeContainerData()
177
    {
178
        parent::normalizeContainerData();
179
180
        foreach ($this->data as $key => $config) {
181
            $config['key'] = $key;
182
            $this->data[$key] = MetaScript::create($config);
0 ignored issues
show
Bug introduced by
$config of type nystudio107\seomatic\models\MetaScript is incompatible with the type array expected by parameter $config of nystudio107\seomatic\models\MetaScript::create(). ( Ignorable by Annotation )

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

182
            $this->data[$key] = MetaScript::create(/** @scrutinizer ignore-type */ $config);
Loading history...
183
        }
184
    }
185
186
    // Protected Methods
187
    // =========================================================================
188
189
    protected function dataLayerHash(): string
190
    {
191
        $data = '';
192
        foreach ($this->data as $metaScriptModel) {
193
            $data .= serialize($metaScriptModel->dataLayer);
194
        }
195
196
        return md5($data);
197
    }
198
}
199