Completed
Push — master ( 4566e6...ddcddc )
by David
01:26
created

stripSlashesFromJsonEncodedSmartySyntax()   B

Complexity

Conditions 9
Paths 40

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 8.0555
c 0
b 0
f 0
cc 9
nc 40
nop 2
1
<?php
2
/**
3
 * Tag Manager
4
 * Copyright (c) Webmatch GmbH
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 */
16
17
namespace WbmTagManager\Services;
18
19
use Shopware\Components\Model\ModelRepository;
20
21
/**
22
 * Class TagManagerVariables
23
 */
24
class TagManagerVariables implements TagManagerVariablesInterface
25
{
26
    /**
27
     * @var \WbmTagManager\Models\Repository
28
     */
29
    private $propertyRepository;
30
31
    /**
32
     * @var \Enlight_Template_Manager
33
     */
34
    private $template;
35
36
    /**
37
     * @var TagManagerSmartyInterface
38
     */
39
    private $smartyPlugins;
40
41
    /**
42
     * @var string
43
     */
44
    private $module = 'frontend';
45
46
    /**
47
     * @var array
48
     */
49
    private $viewVariables = [];
50
51
    /**
52
     * @var mixed
53
     */
54
    private $variables = null;
55
56
    /**
57
     * TagManagerVariables constructor.
58
     *
59
     * @param ModelRepository           $propertyRepository
60
     * @param \Enlight_Template_Manager $template
61
     * @param TagManagerSmartyInterface $smartyPlugins
62
     */
63
    public function __construct(
64
        ModelRepository $propertyRepository,
65
        \Enlight_Template_Manager $template,
66
        TagManagerSmartyInterface $smartyPlugins
67
    ) {
68
        $this->propertyRepository = $propertyRepository;
0 ignored issues
show
Documentation Bug introduced by
$propertyRepository is of type object<Shopware\Components\Model\ModelRepository>, but the property $propertyRepository was declared to be of type object<WbmTagManager\Models\Repository>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
69
        $this->template = $template;
70
        $this->smartyPlugins = $smartyPlugins;
71
    }
72
73
    /**
74
     * @return array
75
     */
76
    public function getViewVariables()
77
    {
78
        return $this->viewVariables[$this->module];
79
    }
80
81
    /**
82
     * @param array $viewVariables
83
     */
84
    public function setViewVariables($viewVariables)
85
    {
86
        $this->viewVariables[$this->module] = $viewVariables;
87
    }
88
89
    /**
90
     * @return mixed
91
     */
92
    public function getVariables()
93
    {
94
        if (!is_array($this->variables)) {
95
            return null;
96
        }
97
98
        return @$this->variables[$this->module];
99
    }
100
101
    /**
102
     * @param mixed $variables
103
     */
104
    public function setVariables($variables)
105
    {
106
        if (!is_array($this->variables)) {
107
            $this->variables = [];
108
        }
109
110
        $this->variables[$this->module] = $variables;
111
    }
112
113
    /**
114
     * @param string $module
115
     *
116
     * @throws \Exception
117
     */
118
    public function render($module)
119
    {
120
        $dataLayer = $this->propertyRepository->getChildrenList(0, $module, true);
121
122
        if (!empty($dataLayer) && is_array($this->getViewVariables())) {
123
            $dataLayer = $this->fillValues($dataLayer);
124
125
            array_walk_recursive($dataLayer, [$this, 'castArrayValues']);
126
127
            $this->setVariables($dataLayer);
128
        }
129
    }
130
131
    /**
132
     * @param array $dataLayer
133
     *
134
     * @throws \Exception
135
     *
136
     * @return mixed
137
     */
138
    public function fillValues($dataLayer)
139
    {
140
        $dataLayer = json_encode($dataLayer);
141
142
        $search = ['{\/', ',{"endArrayOf":true}'];
143
        $replace = ['{/', '{/literal}{if !$smarty.foreach.loop.last},{/if}{/foreach}{literal}'];
144
145
        $dataLayer = str_replace($search, $replace, $dataLayer);
146
147
        while (preg_match('/({"startArrayOf":".*?"},)/i', $dataLayer, $matches)) {
148
            foreach ($matches as $match) {
149
                $foreachObj = json_decode(rtrim($match, ','));
150
                if ($foreachObj->startArrayOf) {
151
                    $arguments = explode(' as ', $foreachObj->startArrayOf);
152
                    $dataLayer = str_replace(
153
                        $match,
154
                        '{/literal}{foreach from=' . $arguments[0] . ' item=' . ltrim($arguments[1], '$') . ' name=loop}{literal}',
155
                        $dataLayer
156
                    );
157
                }
158
            }
159
        }
160
161
        $dataLayer = '{literal}' . $dataLayer . '{/literal}';
162
163
        $dataLayer = $this->compileString($dataLayer);
164
165
        return json_decode($dataLayer, true);
166
    }
167
168
    /**
169
     * @param $source
170
     * @param bool $prettyPrint
171
     *
172
     * @return string
173
     */
174
    public function prependDataLayer($source, $prettyPrint = false)
175
    {
176
        return sprintf(
177
            '%s%s%s%s',
178
            '<script>',
179
            sprintf(
180
                'window.dataLayer.push(%s);',
181
                json_encode(
182
                    $this->getVariables(),
183
                    ($prettyPrint) ? JSON_PRETTY_PRINT : null
184
                )
185
            ),
186
            '</script>',
187
            $source
188
        );
189
    }
190
191
    /**
192
     * @param string $module
193
     */
194
    public function setModule($module)
195
    {
196
        $this->module = $module;
197
    }
198
199
    /**
200
     * @param $value
201
     */
202
    private function castArrayValues(&$value)
203
    {
204
        if (preg_match('/^\"(.*)\"$/', $value)) {
205
            $value = json_decode($value);
206
207
            return;
208
        }
209
210
        switch (true) {
211
            case is_array(json_decode($value)):
212
            case is_int(json_decode($value)):
213
            case is_float(json_decode($value)):
214
                $value = json_decode($value);
215
        }
216
    }
217
218
    /**
219
     * @param string $string
220
     *
221
     * @throws \Exception
222
     *
223
     * @return string $string
224
     */
225
    private function compileString($string)
226
    {
227
        $view = new \Enlight_View_Default(
228
            $this->template
229
        );
230
231
        $this->registerSmartyPlugins($view->Engine());
232
233
        $compiler = new \Shopware_Components_StringCompiler($view->Engine());
234
235
        $compiler->setContext($this->getViewVariables());
236
237
        $string = $this->stripSlashesFromJsonEncodedSmartySyntax($string, $compiler);
238
239
        try {
240
            return $compiler->compileString($string);
241
        } catch (\Exception $exception) {
242
            return json_encode([
243
               'error' => sprintf('Error while compiling the dataLayer: %s', $exception->getMessage()),
244
            ]);
245
        }
246
    }
247
248
    /**
249
     * @param \Enlight_Template_Manager $view
250
     *
251
     * @throws \SmartyException
252
     */
253
    private function registerSmartyPlugins($view)
254
    {
255
        $plugins = $view->smarty->registered_plugins;
256
257
        if (!isset($plugins['function']['dbquery'])) {
258
            $view->registerPlugin(
259
                \Smarty::PLUGIN_FUNCTION,
260
                'dbquery',
261
                [$this->smartyPlugins, 'getDbSelect']
262
            );
263
        }
264
265
        if (!isset($plugins['function']['request_get'])) {
266
            $view->registerPlugin(
267
                \Smarty::PLUGIN_FUNCTION,
268
                'request_get',
269
                [$this->smartyPlugins, 'requestGet']
270
            );
271
        }
272
273
        if (!isset($plugins['modifier']['to_string'])) {
274
            $view->registerPlugin(
275
                \Smarty::PLUGIN_MODIFIER,
276
                'to_string',
277
                [$this->smartyPlugins, 'toString']
278
            );
279
        }
280
    }
281
282
    /**
283
     * @param string                              $string
284
     * @param \Shopware_Components_StringCompiler $compiler
285
     *
286
     * @return mixed
287
     */
288
    private function stripSlashesFromJsonEncodedSmartySyntax(
289
        $string,
290
        \Shopware_Components_StringCompiler $compiler
291
    ) {
292
        try {
293
            $lexer = new \Smarty_Internal_Templatelexer($string, $compiler->getView());
294
            $codeSnippets = [];
295
            $i = 0;
296
            $recording = false;
297
298
            while ($lexer->yylex()) {
299
                // check for key of 'RDEL'
300
                if ($lexer->token === 17 && $recording) {
301
                    $recording = false;
302
                    $i++;
303
                }
304
                if ($recording) {
305
                    $codeSnippets[$i] .= $lexer->value;
306
                }
307
                // check for key of 'LDEL', 'LDELIF', 'LDELFOR', 'LDELFOREACH'
308
                if (in_array($lexer->token, [16, 22, 24, 28]) && !$recording) {
309
                    $recording = true;
310
                }
311
            }
312
313
            foreach ($codeSnippets as $codeSnippet) {
314
                $string = str_replace($codeSnippet, stripslashes($codeSnippet), $string);
315
            }
316
317
            return $string;
318
        } catch (\Exception $exception) {
319
            return $string;
320
        }
321
    }
322
}
323