GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — filters-dev ( b8c330...c59b06 )
by Ivan
11:21
created

ContentBlockHelper   C

Complexity

Total Complexity 71

Size/Duplication

Total Lines 536
Duplicated Lines 15.86 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 8
Bugs 2 Features 0
Metric Value
wmc 71
c 8
b 2
f 0
lcom 1
cbo 4
dl 85
loc 536
rs 5.5904

11 Methods

Rating   Name   Duplication   Size   Complexity  
A replaceForms() 0 21 4
A compileContentString() 0 7 1
C processData() 28 69 15
C renderUrl() 33 45 8
B sanitizeChunk() 6 24 6
B compileChunk() 0 28 5
A applyFormatter() 0 13 4
A fetchChunkByKey() 0 18 2
A preloadChunks() 0 18 2
A getChunk() 0 19 4
F renderProducts() 18 153 20

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ContentBlockHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ContentBlockHelper, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace app\modules\core\helpers;
3
4
use app;
5
use app\models\Property;
6
use app\models\PropertyStaticValues;
7
use app\modules\core\models\ContentBlock;
8
use app\modules\page\models\Page;
9
use app\modules\shop\models\Category;
10
use app\modules\shop\models\Product;
11
use devgroup\TagDependencyHelper\ActiveRecordHelper;
12
use yii\caching\TagDependency;
13
use yii\helpers\ArrayHelper;
14
use yii\helpers\Url;
15
use yii;
16
17
/**
18
 * Class ContentBlockHelper
19
 * Main public static method compileContentString() uses submethods to extract chunk calls from model content field,
20
 * fetch chunks from data base table, then compile it and replace chunk calls with compiled chunks data
21
 * Example chunk call in model content field should be like: [[$chunk param='value'|'default value' param2=42]].
22
 * Chunk declaration should be like : <p>String: [[+param]]</p> <p>Float: [[+param2:format, param1, param2]]</p>
23
 * All supported formats you can find at Yii::$app->formatter
24
 *
25
 * @package app\modules\core\helpers
26
 */
27
class ContentBlockHelper
28
{
29
    private static $chunksByKey = [];
30
31
    /**
32
     * Compiles content string by injecting chunks into content
33
     * Preloads chunks which have preload = 1
34
     *
35
     * @param  string $content Original content with chunk calls
36
     * @param  string $content_key Key for caching compiled content version
37
     * @param  yii\caching\Dependency $dependency Cache dependency
38
     * @return string Compiled content with injected chunks
39
     */
40
    public static function compileContentString($content, $content_key, $dependency)
41
    {
42
        self::preloadChunks();
43
        $output = self::processData($content, $content_key, $dependency);
44
        $output = self::processData($output, $content_key, $dependency, '', false);
45
        return $output;
46
    }
47
48
    /**
49
     * Finding chunk calls with regexp
50
     * Iterate matches
51
     * While iterating:
52
     * Extracts single chunk data with sanitizeChunk() method
53
     * Fetches chunk by key using fetchChunkByKey(), who returns chunk value by key from static array if exists, otherwise from db
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
54
     * Compiles single chunk using compileChunk() method
55
     * Replaces single chunk call with compiled chunk data in the model content
56
     *
57
     * @param  string $content_key Key for caching compiled content version
58
     * @param  yii\caching\Dependency $dependency Cache dependency
59
     * @param  bool $preprocess flag to separate rendering non cacheable chunks such as Form
60
     * @param  string $content
61
     * @param  string $chunk_key ContentBlock key string to prevent endless recursion
62
     * @return string
63
     */
64
    private static function processData($content, $content_key, $dependency, $chunk_key = '', $preprocess = true)
65
    {
66
        $matches = [];
67
        $replacement = '';
68
        preg_match_all('%\[\[([^\]\[]+)\]\]%ui', $content, $matches);
69
        if (!empty($matches[0])) {
70
            foreach ($matches[0] as $k => $rawChunk) {
71
                $chunkData = self::sanitizeChunk($rawChunk);
72
                if ($chunkData['key'] == $chunk_key) {
73
                    $content = str_replace($matches[0][$k], '', $content);
74
                    continue;
75
                }
76
                $cacheKey = $content_key . $chunkData['key'] . serialize($chunkData);
77
                switch ($chunkData['token']) {
78
                    case '$':
79
                        if ($preprocess === false) break;
80
                        $chunk = self::fetchChunkByKey($chunkData['key']);
81
                        $replacement = Yii::$app->cache->get($cacheKey);
82
                        if ($replacement === false) {
83
                            $replacement = static::compileChunk($chunk, $chunkData, $chunkData['key'], $content_key, $dependency);
0 ignored issues
show
Bug introduced by
Since compileChunk() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of compileChunk() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
84
                            Yii::$app->cache->set(
85
                                $cacheKey,
86
                                $replacement,
87
                                84600,
88
                                $dependency
89
                            );
90
                        }
91
                        break;
92
                    case '%':
93
                        if ($preprocess === true) {
94
                            $replacement = $rawChunk;
95
                            break;
96
                        }
97
                        $replacement = static::replaceForms($chunkData);
0 ignored issues
show
Bug introduced by
Since replaceForms() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of replaceForms() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
98
                        break;
99 View Code Duplication
                    case '~' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
100
                        if ($preprocess === false) break;
101
                        $replacement = Yii::$app->cache->get($cacheKey);
102
                        if ($replacement === false) {
103
                            $replacement = static::renderUrl($chunkData, $dependency);
0 ignored issues
show
Bug introduced by
Since renderUrl() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of renderUrl() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
104
                            Yii::$app->cache->set(
105
                                $cacheKey,
106
                                $replacement,
107
                                84600,
108
                                $dependency
109
                            );
110
                        }
111
                        break;
112 View Code Duplication
                    case '*':
113
                        if ($preprocess === false) {
114
                            break;
115
                        }
116
                        $replacement = Yii::$app->cache->get($cacheKey);
117
                        if ($replacement === false) {
118
                            $replacement = static::renderProducts($chunkData, $dependency);
0 ignored issues
show
Bug introduced by
Since renderProducts() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of renderProducts() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
119
                            Yii::$app->cache->set(
120
                                $cacheKey,
121
                                $replacement,
122
                                84600,
123
                                $dependency
124
                            );
125
                        }
126
                        break;
127
                }
128
                $content = str_replace($matches[0][$k], $replacement, $content);
129
            }
130
        }
131
        return $content;
132
    }
133
134
    /**
135
     * @param array $chunkData
136
     * @return mixed
137
     */
138
    private static function replaceForms($chunkData)
139
    {
140
        $regexp = '/^(?P<formId>\d+)(#(?P<id>[\w\d\-_]+))?(;(?P<isModal>isModal))?$/Usi';
141
        return preg_replace_callback(
142
            $regexp,
143
            function ($matches) {
144
                if (isset($matches['formId'])) {
145
                    $params = ['formId' => intval($matches['formId'])];
146
                    if (isset($matches['id'])) {
147
                        $params['id'] = $matches['id'];
148
                    }
149
                    if (isset($matches['isModal'])) {
150
                        $params['isModal'] = true;
151
                    }
152
                    return app\widgets\form\Form::widget($params);
153
                }
154
                return '';
155
            },
156
            $chunkData['key']
157
        );
158
    }
159
160
    /**
161
     * renders url according to given data
162
     * @param $chunkData
163
     * @param TagDependency $dependency
164
     * @return string
165
     */
166
    private static function renderUrl($chunkData, &$dependency)
167
    {
168
        $expression = '%(?P<objectName>[^#]+?)#(?P<objectId>[\d]+?)$%';
169
        $output = '';
170
        preg_match($expression, $chunkData['key'], $m);
171
        if (true === isset($m['objectName'], $m['objectId'])) {
172
            $id = (int)$m['objectId'];
173
            switch (strtolower($m['objectName'])) {
174 View Code Duplication
                case "page" :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
175
                    if (null !== $model = Page::findById($id)) {
176
                        $dependency->tags [] = ActiveRecordHelper::getCommonTag(Page::className());
177
                        $dependency->tags [] = $model->objectTag();
178
                        $output = Url::to(['@article', 'id' => $id]);
179
                    }
180
                    break;
181 View Code Duplication
                case "category" :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
182
                    if (null !== $model = Category::findById($id)) {
183
                        $dependency->tags [] = ActiveRecordHelper::getCommonTag(Category::className());
184
                        $dependency->tags [] = $model->objectTag();
185
                        $output = Url::to(
186
                            [
187
                                '@category',
188
                                'last_category_id' => $id,
189
                                'category_group_id' => $model->category_group_id
190
                            ]
191
                        );
192
                    }
193
                    break;
194 View Code Duplication
                case "product" :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
195
                    if (null !== $model = app\modules\shop\models\Product::findById($id)) {
196
                        $dependency->tags [] = ActiveRecordHelper::getCommonTag(Product::className());
197
                        $dependency->tags [] = $model->objectTag();
198
                        $output = Url::to(
199
                            [
200
                                '@product',
201
                                'model' => $model,
202
                                'category_group_id' => $model->getMainCategory()->category_group_id
203
                            ]
204
                        );
205
                    }
206
                    break;
207
            }
208
        }
209
        return $output;
210
    }
211
212
    /**
213
     * Extracts chunk data from chunk call
214
     * uses regexp to extract param data from placeholder
215
     * [[$chunk <paramName>='<escapedValue>'|'<escapedDefault>' <paramName>=<unescapedValue>|<unescapedDefault>]]
216
     * iterate matches.
217
     * While iterating converts escapedValue and escapedDefault into string, unescapedValue and unescapedDefault - into float
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 125 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
218
     * Returns chunk data array like:
219
     *  [
220
     *      'key' => 'chunkKey',
221
     *      'firstParam'=> 'string value',
222
     *      'firstParam-default'=> 'default string value',
223
     *      'secondParam'=> float value,
224
     *      'secondParam-default'=> default float value,
225
     *  ]
226
     *
227
     * @param string $rawChunk
228
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<*,string|double>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
229
     */
230
    private static function sanitizeChunk($rawChunk)
231
    {
232
        $chunk = [];
233
        preg_match('%(?P<chunkToken>[^\w\[]?)([^\s\]\[]+)[\s\]]%', $rawChunk, $keyMatches);
234
        $chunk['token'] = $keyMatches['chunkToken'];
235
        $chunk['key'] = $keyMatches[2];
236
        $expression = "#\s*(?P<paramName>[\\w\\d]*)=(('(?P<escapedValue>.*[^\\\\])')|(?P<unescapedValue>.*))(\\|(('(?P<escapedDefault>.*[^\\\\])')|(?P<unescapedDefault>.*)))?[\\]\\s]#uUi";
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 188 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
237
        preg_match_all($expression, $rawChunk, $matches);
238
        foreach ($matches['paramName'] as $key => $paramName) {
239
            if (!empty($matches['escapedValue'][$key])) {
240
                $chunk[$paramName] = strval($matches['escapedValue'][$key]);
241
            }
242
            if (!empty($matches['unescapedValue'][$key])) {
243
                $chunk[$paramName] = floatval($matches['unescapedValue'][$key]);
244
            }
245 View Code Duplication
            if (!empty($matches['escapedDefault'][$key])) {
246
                $chunk[$paramName . '-default'] = strval($matches['escapedDefault'][$key]);
247
            }
248 View Code Duplication
            if (!empty($matches['unescapedDefault'][$key])) {
249
                $chunk[$paramName . '-default'] = floatval($matches['unescapedDefault'][$key]);
250
            }
251
        }
252
        return $chunk;
253
    }
254
255
    /**
256
     * Compiles single chunk
257
     * uses regexp to find placeholders and extract it's data from chunk value field
258
     * [[<token><paramName>:<format><params>]]
259
     * token switch is for future functionality increase
260
     * now method only recognizes + token and replaces following param with according $arguments array data
261
     * applies formatter according previously defined param values type if needed
262
     * if param name from placeholder was not found in arguments array, placeholder in the compiled chunk will be replaced with empty string
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 140 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
263
     * returns compiled chunk
264
     *
265
     * @param  string $content_key Key for caching compiled content version
266
     * @param  yii\caching\Dependency $dependency Cache dependency
267
     * @param  string $chunk ContentBlock instance
268
     * @param  array $arguments Arguments for this chunk from original content
269
     * @param  string $key ContentBlock key string to prevent endless recursion
270
     * @return string Result string ready for replacing
271
     */
272
    private static function compileChunk($chunk, $arguments, $key, $content_key, $dependency)
273
    {
274
        $matches = [];
275
        preg_match_all('%\[\[(?P<token>[\+\*])(?P<paramName>[^\s\:\]]+)\:?(?P<format>[^\,\]]+)?\,?(?P<params>[^\]]+)?\]\]%ui', $chunk, $matches);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 145 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
276
        foreach ($matches[0] as $k => $rawParam) {
277
            $token = $matches['token'][$k];
278
            $paramName = trim($matches['paramName'][$k]);
279
            $format = trim($matches['format'][$k]);
280
            $params = preg_replace('%[\s]%', '', $matches['params'][$k]);
281
            $params = explode(',', $params);
282
            switch ($token) {
283
                case '+':
284
                    if (array_key_exists($paramName, $arguments)) {
285
                        $replacement = static::applyFormatter($arguments[$paramName], $format, $params);
0 ignored issues
show
Bug introduced by
Since applyFormatter() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of applyFormatter() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
286
                        $chunk = str_replace($matches[0][$k], $replacement, $chunk);
287
                    } else if (array_key_exists($paramName . '-default', $arguments)) {
288
                        $replacement = static::applyFormatter($arguments[$paramName . '-default'], $format, $params);
0 ignored issues
show
Bug introduced by
Since applyFormatter() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of applyFormatter() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
289
                        $chunk = str_replace($matches[0][$k], $replacement, $chunk);
290
                    } else {
291
                        $chunk = str_replace($matches[0][$k], '', $chunk);
292
                    }
293
                    break;
294
                default:
295
                    $chunk = str_replace($matches[0][$k], '', $chunk);
296
            }
297
        }
298
        return self::processData($chunk, $content_key, $dependency, $key);
299
    }
300
301
    /**
302
     * Find formatter declarations in chunk placeholders. if find trying to apply
303
     * yii\i18n\Formatter formats see yii\i18n\Formatter for details
304
     *
305
     * @param string $value single placeholder declaration from chunk
306
     * @param string $format
307
     * @param array $params
308
     * @return string|array
309
     */
310
    private static function applyFormatter($value, $format, $params)
311
    {
312
        if (false === method_exists(Yii::$app->formatter, $format) || empty($format)) {
313
            return $value;
314
        }
315
        array_unshift($params, $value);
316
        try {
317
            $formattedValue = call_user_func_array([Yii::$app->formatter, $format], $params);
318
        } catch (\Exception $e) {
319
            $formattedValue = $value;
320
        }
321
        return $formattedValue;
322
    }
323
324
    /**
325
     * Fetches single chunk by key from static var
326
     * if is no there - get it from db and push to static array
327
     *
328
     * @param $key string Chunk key field
329
     * @return string Chunk value field
330
     */
331
    private static function fetchChunkByKey($key)
332
    {
333
        if (!array_key_exists($key, static::$chunksByKey)) {
334
            $dependency = new TagDependency([
335
                'tags' => [
336
                    ActiveRecordHelper::getCommonTag(ContentBlock::className()),
337
                ]
338
            ]);
339
            static::$chunksByKey[$key] = ContentBlock::getDb()->cache(function ($db) use ($key) {
0 ignored issues
show
Unused Code introduced by
The parameter $db is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
340
                $chunk = ContentBlock::find()
341
                    ->where(['key' => $key])
342
                    ->asArray()
343
                    ->one();
344
                return static::$chunksByKey[$key] = $chunk['value'];
345
            }, 86400, $dependency);
346
        }
347
        return static::$chunksByKey[$key];
348
    }
349
350
    /**
351
     * preloads chunks with option preload  = 1
352
     * and push it to static array
353
     *
354
     * @return array|void
355
     */
356
    private static function preloadChunks()
357
    {
358
        if (is_null(static::$chunksByKey)) {
359
            $dependency = new TagDependency([
360
                'tags' => [
361
                    ActiveRecordHelper::getCommonTag(ContentBlock::className()),
362
                ]
363
            ]);
364
            static::$chunksByKey = ContentBlock::getDb()->cache(function ($db) {
0 ignored issues
show
Unused Code introduced by
The parameter $db is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
365
                $chunks = ContentBlock::find()
366
                    ->where(['preload' => 1])
367
                    ->asArray()
368
                    ->all();
369
                return ArrayHelper::map($chunks, 'key', 'value');
370
            }, 86400, $dependency);
371
        }
372
        return static::$chunksByKey;
373
    }
374
375
    /**
376
     * renders chunks in template files
377
     * @param string $key ContentBlock key
378
     * @param array $params . Array of params to be replaced while render
379
     * @param yii\base\Model $model . Caller model instance to use in caching
0 ignored issues
show
Documentation introduced by
Should the type for parameter $model not be null|yii\base\Model?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
380
     * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
381
     */
382
    public static function getChunk($key, $params = [], yii\base\Model $model = null)
383
    {
384
        if (null === $rawChunk = self::fetchChunkByKey($key)) {
385
            return '';
386
        }
387
        $tags = [
388
            ActiveRecordHelper::getCommonTag(app\modules\core\models\ContentBlock::className()),
389
        ];
390
        $content_key = 'templateChunkRender' . $key;
391
        if (null !== $model) {
392
            $content_key .= $model->id;
393
            $tags[] = ActiveRecordHelper::getObjectTag(get_class($model), $model->id);
394
        }
395
        $dependency = new TagDependency(['tags' => $tags]);
396
        if (false === empty($params)) {
397
            $rawChunk = self::compileChunk($rawChunk, $params, $key, $content_key, $dependency);
398
        }
399
        return self::compileContentString($rawChunk, $content_key, $dependency);
400
    }
401
402
    /**
403
     * renders product item and list.
404
     * possible can render all objects, but need for few logic change
405
     * @param array $chunkData params for select and render
406
     * @param TagDependency $dependency
407
     * @return mixed
408
     */
409
    private static function renderProducts($chunkData, &$dependency)
410
    {
411
        $params = [
412
            'itemView' => Yii::$app->getModule('shop')->itemView,
413
            'type' => 'show',
414
            'object' => 'product',
415
            'where' => [],
416
            'limit' => 0,
417
            'listView' => Yii::$app->getModule('shop')->listView,
418
        ];
419
        switch ($chunkData['key']) {
420
            case 'product':
421
                if (ArrayHelper::keyExists('sku', $chunkData)) {
422
                    $params['where'] = ['sku' => $chunkData['sku']];
423
                }
424
                break;
425
            case 'productList':
426
                $params['type'] = 'list';
427
                break;
428
            default:
429
                $expression = '%(?P<objectName>[^#]+?)#(?P<objectId>[\d]+?)$%';
430
                if (preg_match($expression, $chunkData['key'], $matches)) {
431
                    $params['where']['id'] = $matches['objectId'];
432
                }
433
                break;
434
        }
435
        switch ($params['object']) {
436
            case 'product':
437
                $dependency->tags[] = ActiveRecordHelper::getCommonTag(Product::className());
438
                $query = Product::find();
439
                if (!empty($chunkData['categoryId'])) {
440
                    $query->leftJoin(
441
                        '{{%product_category}}',
442
                        Product::tableName() . '.id = {{%product_category}}.object_model_id'
443
                    )->andWhere(['{{%product_category}}.category_id' => $chunkData['categoryId']]);
444
                    $dependency->tags[] = ActiveRecordHelper::getCommonTag(Category::className());
445
                    $dependency->tags[] = ActiveRecordHelper::getObjectTag(
446
                        Category::className(),
447
                        $chunkData['categoryId']
448
                    );
449
                }
450
                if (!empty($chunkData['property'])) {
451
                    $expression = '%(?P<propertyKey>[^:]+?):(?P<propertyValue>.+?)$%';
452
                    if (preg_match($expression, $chunkData['property'], $matches)) {
453
                        $property = Property::findOne(['key' => $matches['propertyKey']]);
454
                        if (!is_null($property)) {
455
                            /** @var Property $property */
456
                            $dependency->tags[] = ActiveRecordHelper::getCommonTag(Property::className());
457
                            $dependency->tags[] = $property->objectTag();
458
                            if ($property->is_eav == 1) {
459
                                $query->leftJoin(
460
                                    '{{%product_eav}}',
461
                                    Product::tableName() . '.id = {{%product_eav}}.object_model_id'
462
                                )->andWhere(
463
                                    [
464
                                        '{{%product_eav}}.key' => $matches['propertyKey'],
465
                                        '{{%product_eav}}.value' => $matches['propertyValue']
466
                                    ]
467
                                );
468
                            } elseif ($property->has_static_values == 1) {
469
                                $psv = PropertyStaticValues::findOne(
470
                                    [
471
                                        'property_id' => $property->id,
472
                                        'value' => $matches['propertyValue']
473
                                    ]
474
                                );
475
                                if (!is_null($psv)) {
476
                                    $dependency->tags[] = ActiveRecordHelper::getCommonTag(
477
                                        PropertyStaticValues::className()
478
                                    );
479
                                    $dependency->tags[] = $psv->objectTag();
480
                                    $query->leftJoin(
481
                                        '{{%object_static_values}}',
482
                                        Product::tableName() . '.id = {{%object_static_values}}.object_model_id'
483
                                    )->andWhere(
484
                                        [
485
                                            'object_id' => 3,
486
                                            '{{%object_static_values}}.property_static_value_id' => $psv->id,
487
                                        ]
488
                                    );
489
                                } else {
490
                                    return '';
491
                                }
492
                            }
493
                            /** @todo add column_stored */
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
494
                        } else {
495
                            return '';
496
                        }
497
                    }
498
                }
499
                break;
500
            default:
501
                $query = Product::find();
502
                break;
503
        }
504
        $params = ArrayHelper::merge($params, array_intersect_key($chunkData, $params));
505
        if (!empty($params['where'])) {
506
            $query->andWhere($params['where']);
507
        }
508
        if (!empty($params['limit'])) {
509
            $query->limit($params['limit']);
510
        }
511
512
        if ($params['type'] === 'list') {
513
            $view = $params['listView'];
514
            $objects = $query->all();
515
            foreach ($objects as $object) {
516
                $dependency->tags[] = $object->objectTag();
517
            }
518
            switch ($params['object']) {
519
                case 'product':
520
                    $viewParams = ['products' => $objects];
521
                    break;
522
                default:
523
                    $viewParams = ['products' => $objects];
524
                    break;
525
            }
526
        } else {
527
            $view = $params['itemView'];
528
            $object = $query->one();
529
            if (is_null($object)) {
530
                return '';
531
            }
532
            $dependency->tags[] = $object->objectTag();
533
            switch ($params['object']) {
534 View Code Duplication
                case 'product':
535
                    $viewParams = [
536
                        'product' => $object,
537
                        'url' => Url::to(
538
                            [
539
                                '@product',
540
                                'model' => $object,
541
                                'category_group_id' => $object->getMainCategory()->category_group_id,
542
                            ]
543
                        )
544
                    ];
545
                    break;
546 View Code Duplication
                default:
547
                    $viewParams = [
548
                        'product' => $object,
549
                        'url' => Url::to(
550
                            [
551
                                '@product',
552
                                'model' => $object,
553
                                'category_group_id' => $object->getMainCategory()->category_group_id,
554
                            ]
555
                        )
556
                    ];
557
                    break;
558
            }
559
        }
560
        return Yii::$app->view->render($view, $viewParams);
561
    }
562
}
563