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.

ContentBlockHelper   F
last analyzed

Complexity

Total Complexity 71

Size/Duplication

Total Lines 538
Duplicated Lines 13.38 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 71
lcom 1
cbo 14
dl 72
loc 538
rs 2.7199
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A compileContentString() 0 7 1
C processData() 28 69 15
A replaceForms() 0 21 4
B renderUrl() 20 46 8
B sanitizeChunk() 6 24 6
A 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 154 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
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...
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 '~' :
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...
Compatibility introduced by
$dependency of type object<yii\caching\Dependency> is not a sub-type of object<yii\caching\TagDependency>. It seems like you assume a child class of the class yii\caching\Dependency to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

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...
Compatibility introduced by
$dependency of type object<yii\caching\Dependency> is not a sub-type of object<yii\caching\TagDependency>. It seems like you assume a child class of the class yii\caching\Dependency to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

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" :
175
                    if (null !== $model = Page::findById($id)) {
176
                        $dependency->tags [] = ActiveRecordHelper::getCommonTag(Page::className());
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
177
                        $dependency->tags [] = $model->objectTag();
178
                        $output = Url::to(['@article', 'id' => $id]);
179
                    }
180
                    break;
181 View Code Duplication
                case "category" :
182
                    if (null !== $model = Category::findById($id)) {
183
                        $dependency->tags [] = ActiveRecordHelper::getCommonTag(Category::className());
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
184
                        $dependency->tags [] = $model->objectTag();
0 ignored issues
show
Documentation Bug introduced by
The method objectTag does not exist on object<app\modules\shop\models\Category>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
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
                case "product" :
195
                    $product = Yii::$container->get(Product::class);
196
                    if (null !== $model = $product::findById($id)) {
197
                        $dependency->tags [] = ActiveRecordHelper::getCommonTag(get_class($product));
198
                        $dependency->tags [] = $model->objectTag();
199
                        $output = Url::to(
200
                            [
201
                                '@product',
202
                                'model' => $model,
203
                                'category_group_id' => $model->getMainCategory()->category_group_id
204
                            ]
205
                        );
206
                    }
207
                    break;
208
            }
209
        }
210
        return $output;
211
    }
212
213
    /**
214
     * Extracts chunk data from chunk call
215
     * uses regexp to extract param data from placeholder
216
     * [[$chunk <paramName>='<escapedValue>'|'<escapedDefault>' <paramName>=<unescapedValue>|<unescapedDefault>]]
217
     * iterate matches.
218
     * While iterating converts escapedValue and escapedDefault into string, unescapedValue and unescapedDefault - into float
219
     * Returns chunk data array like:
220
     *  [
221
     *      'key' => 'chunkKey',
222
     *      'firstParam'=> 'string value',
223
     *      'firstParam-default'=> 'default string value',
224
     *      'secondParam'=> float value,
225
     *      'secondParam-default'=> default float value,
226
     *  ]
227
     *
228
     * @param string $rawChunk
229
     * @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...
230
     */
231
    private static function sanitizeChunk($rawChunk)
232
    {
233
        $chunk = [];
234
        preg_match('%(?P<chunkToken>[^\w\[]?)([^\s\]\[]+)[\s\]]%', $rawChunk, $keyMatches);
235
        $chunk['token'] = $keyMatches['chunkToken'];
236
        $chunk['key'] = $keyMatches[2];
237
        $expression = "#\s*(?P<paramName>[\\w\\d]*)=(('(?P<escapedValue>.*[^\\\\])')|(?P<unescapedValue>.*))(\\|(('(?P<escapedDefault>.*[^\\\\])')|(?P<unescapedDefault>.*)))?[\\]\\s]#uUi";
238
        preg_match_all($expression, $rawChunk, $matches);
239
        foreach ($matches['paramName'] as $key => $paramName) {
240
            if (!empty($matches['escapedValue'][$key])) {
241
                $chunk[$paramName] = strval($matches['escapedValue'][$key]);
242
            }
243
            if (!empty($matches['unescapedValue'][$key])) {
244
                $chunk[$paramName] = floatval($matches['unescapedValue'][$key]);
245
            }
246 View Code Duplication
            if (!empty($matches['escapedDefault'][$key])) {
247
                $chunk[$paramName . '-default'] = strval($matches['escapedDefault'][$key]);
248
            }
249 View Code Duplication
            if (!empty($matches['unescapedDefault'][$key])) {
250
                $chunk[$paramName . '-default'] = floatval($matches['unescapedDefault'][$key]);
251
            }
252
        }
253
        return $chunk;
254
    }
255
256
    /**
257
     * Compiles single chunk
258
     * uses regexp to find placeholders and extract it's data from chunk value field
259
     * [[<token><paramName>:<format><params>]]
260
     * token switch is for future functionality increase
261
     * now method only recognizes + token and replaces following param with according $arguments array data
262
     * applies formatter according previously defined param values type if needed
263
     * if param name from placeholder was not found in arguments array, placeholder in the compiled chunk will be replaced with empty string
264
     * returns compiled chunk
265
     *
266
     * @param  string $content_key Key for caching compiled content version
267
     * @param  yii\caching\Dependency $dependency Cache dependency
268
     * @param  string $chunk ContentBlock instance
269
     * @param  array $arguments Arguments for this chunk from original content
270
     * @param  string $key ContentBlock key string to prevent endless recursion
271
     * @return string Result string ready for replacing
272
     */
273
    private static function compileChunk($chunk, $arguments, $key, $content_key, $dependency)
274
    {
275
        $matches = [];
276
        preg_match_all('%\[\[(?P<token>[\+\*])(?P<paramName>[^\s\:\]]+)\:?(?P<format>[^\,\]]+)?\,?(?P<params>[^\]]+)?\]\]%ui', $chunk, $matches);
277
        foreach ($matches[0] as $k => $rawParam) {
278
            $token = $matches['token'][$k];
279
            $paramName = trim($matches['paramName'][$k]);
280
            $format = trim($matches['format'][$k]);
281
            $params = preg_replace('%[\s]%', '', $matches['params'][$k]);
282
            $params = explode(',', $params);
283
            switch ($token) {
284
                case '+':
285
                    if (array_key_exists($paramName, $arguments)) {
286
                        $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...
287
                        $chunk = str_replace($matches[0][$k], $replacement, $chunk);
288
                    } else if (array_key_exists($paramName . '-default', $arguments)) {
289
                        $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...
290
                        $chunk = str_replace($matches[0][$k], $replacement, $chunk);
291
                    } else {
292
                        $chunk = str_replace($matches[0][$k], '', $chunk);
293
                    }
294
                    break;
295
                default:
296
                    $chunk = str_replace($matches[0][$k], '', $chunk);
297
            }
298
        }
299
        return self::processData($chunk, $content_key, $dependency, $key);
300
    }
301
302
    /**
303
     * Find formatter declarations in chunk placeholders. if find trying to apply
304
     * yii\i18n\Formatter formats see yii\i18n\Formatter for details
305
     *
306
     * @param string $value single placeholder declaration from chunk
307
     * @param string $format
308
     * @param array $params
309
     * @return string|array
310
     */
311
    private static function applyFormatter($value, $format, $params)
312
    {
313
        if (false === method_exists(Yii::$app->formatter, $format) || empty($format)) {
314
            return $value;
315
        }
316
        array_unshift($params, $value);
317
        try {
318
            $formattedValue = call_user_func_array([Yii::$app->formatter, $format], $params);
319
        } catch (\Exception $e) {
320
            $formattedValue = $value;
321
        }
322
        return $formattedValue;
323
    }
324
325
    /**
326
     * Fetches single chunk by key from static var
327
     * if is no there - get it from db and push to static array
328
     *
329
     * @param $key string Chunk key field
330
     * @return string Chunk value field
331
     */
332
    private static function fetchChunkByKey($key)
333
    {
334
        if (!array_key_exists($key, static::$chunksByKey)) {
335
            $dependency = new TagDependency([
336
                'tags' => [
337
                    ActiveRecordHelper::getCommonTag(ContentBlock::className()),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
338
                ]
339
            ]);
340
            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...
341
                $chunk = ContentBlock::find()
342
                    ->where(['key' => $key])
343
                    ->asArray()
344
                    ->one();
345
                return static::$chunksByKey[$key] = $chunk['value'];
346
            }, 86400, $dependency);
347
        }
348
        return static::$chunksByKey[$key];
349
    }
350
351
    /**
352
     * preloads chunks with option preload  = 1
353
     * and push it to static array
354
     *
355
     * @return array|void
356
     */
357
    private static function preloadChunks()
358
    {
359
        if (is_null(static::$chunksByKey)) {
360
            $dependency = new TagDependency([
361
                'tags' => [
362
                    ActiveRecordHelper::getCommonTag(ContentBlock::className()),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
363
                ]
364
            ]);
365
            static::$chunksByKey = ContentBlock::getDb()->cache(function ($db) {
0 ignored issues
show
Documentation Bug introduced by
It seems like \app\modules\core\models... }, 86400, $dependency) of type * is incompatible with the declared type array of property $chunksByKey.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
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...
366
                $chunks = ContentBlock::find()
367
                    ->where(['preload' => 1])
368
                    ->asArray()
369
                    ->all();
370
                return ArrayHelper::map($chunks, 'key', 'value');
371
            }, 86400, $dependency);
372
        }
373
        return static::$chunksByKey;
374
    }
375
376
    /**
377
     * renders chunks in template files
378
     * @param string $key ContentBlock key
379
     * @param array $params . Array of params to be replaced while render
380
     * @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...
381
     * @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...
382
     */
383
    public static function getChunk($key, $params = [], yii\base\Model $model = null)
384
    {
385
        if (null === $rawChunk = self::fetchChunkByKey($key)) {
386
            return '';
387
        }
388
        $tags = [
389
            ActiveRecordHelper::getCommonTag(app\modules\core\models\ContentBlock::className()),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
390
        ];
391
        $content_key = 'templateChunkRender' . $key;
392
        if (null !== $model) {
393
            $content_key .= $model->id;
394
            $tags[] = ActiveRecordHelper::getObjectTag(get_class($model), $model->id);
395
        }
396
        $dependency = new TagDependency(['tags' => $tags]);
397
        if (false === empty($params)) {
398
            $rawChunk = self::compileChunk($rawChunk, $params, $key, $content_key, $dependency);
399
        }
400
        return self::compileContentString($rawChunk, $content_key, $dependency);
401
    }
402
403
    /**
404
     * renders product item and list.
405
     * possible can render all objects, but need for few logic change
406
     * @param array $chunkData params for select and render
407
     * @param TagDependency $dependency
408
     * @return mixed
409
     */
410
    private static function renderProducts($chunkData, &$dependency)
411
    {
412
        $product = Yii::$container->get(Product::class);
413
        $params = [
414
            'itemView' => Yii::$app->getModule('shop')->itemView,
415
            'type' => 'show',
416
            'object' => 'product',
417
            'where' => [],
418
            'limit' => 0,
419
            'listView' => Yii::$app->getModule('shop')->listView,
420
        ];
421
        switch ($chunkData['key']) {
422
            case 'product':
423
                if (ArrayHelper::keyExists('sku', $chunkData)) {
424
                    $params['where'] = ['sku' => $chunkData['sku']];
425
                }
426
                break;
427
            case 'productList':
428
                $params['type'] = 'list';
429
                break;
430
            default:
431
                $expression = '%(?P<objectName>[^#]+?)#(?P<objectId>[\d]+?)$%';
432
                if (preg_match($expression, $chunkData['key'], $matches)) {
433
                    $params['where']['id'] = $matches['objectId'];
434
                }
435
                break;
436
        }
437
        switch ($params['object']) {
438
            case 'product':
439
                $dependency->tags[] = ActiveRecordHelper::getCommonTag(get_class($product));
440
                $query = $product::find();
441
                if (!empty($chunkData['categoryId'])) {
442
                    $query->leftJoin(
443
                        '{{%product_category}}',
444
                        $product::tableName() . '.id = {{%product_category}}.object_model_id'
445
                    )->andWhere(['{{%product_category}}.category_id' => $chunkData['categoryId']]);
446
                    $dependency->tags[] = ActiveRecordHelper::getCommonTag(Category::className());
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
447
                    $dependency->tags[] = ActiveRecordHelper::getObjectTag(
448
                        Category::className(),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
449
                        $chunkData['categoryId']
450
                    );
451
                }
452
                if (!empty($chunkData['property'])) {
453
                    $expression = '%(?P<propertyKey>[^:]+?):(?P<propertyValue>.+?)$%';
454
                    if (preg_match($expression, $chunkData['property'], $matches)) {
455
                        $property = Property::findOne(['key' => $matches['propertyKey']]);
456
                        if (!is_null($property)) {
457
                            /** @var Property $property */
458
                            $dependency->tags[] = ActiveRecordHelper::getCommonTag(Property::className());
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
459
                            $dependency->tags[] = $property->objectTag();
0 ignored issues
show
Documentation Bug introduced by
The method objectTag does not exist on object<app\models\Property>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
460
                            if ($property->is_eav == 1) {
461
                                $query->leftJoin(
462
                                    '{{%product_eav}}',
463
                                    $product::tableName() . '.id = {{%product_eav}}.object_model_id'
464
                                )->andWhere(
465
                                    [
466
                                        '{{%product_eav}}.key' => $matches['propertyKey'],
467
                                        '{{%product_eav}}.value' => $matches['propertyValue']
468
                                    ]
469
                                );
470
                            } elseif ($property->has_static_values == 1) {
471
                                $psv = PropertyStaticValues::findOne(
472
                                    [
473
                                        'property_id' => $property->id,
474
                                        'value' => $matches['propertyValue']
475
                                    ]
476
                                );
477
                                if (!is_null($psv)) {
478
                                    $dependency->tags[] = ActiveRecordHelper::getCommonTag(
479
                                        PropertyStaticValues::className()
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
480
                                    );
481
                                    $dependency->tags[] = $psv->objectTag();
0 ignored issues
show
Bug introduced by
The method objectTag() does not seem to exist on object<yii\db\ActiveRecordInterface>.

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...
482
                                    $query->leftJoin(
483
                                        '{{%object_static_values}}',
484
                                        $product::tableName() . '.id = {{%object_static_values}}.object_model_id'
485
                                    )->andWhere(
486
                                        [
487
                                            'object_id' => 3,
488
                                            '{{%object_static_values}}.property_static_value_id' => $psv->id,
489
                                        ]
490
                                    );
491
                                } else {
492
                                    return '';
493
                                }
494
                            }
495
                            /** @todo add column_stored */
496
                        } else {
497
                            return '';
498
                        }
499
                    }
500
                }
501
                break;
502
            default:
503
                $query = $product::find();
504
                break;
505
        }
506
        $params = ArrayHelper::merge($params, array_intersect_key($chunkData, $params));
507
        if (!empty($params['where'])) {
508
            $query->andWhere($params['where']);
509
        }
510
        if (!empty($params['limit'])) {
511
            $query->limit($params['limit']);
512
        }
513
514
        if ($params['type'] === 'list') {
515
            $view = $params['listView'];
516
            $objects = $query->all();
517
            foreach ($objects as $object) {
518
                $dependency->tags[] = $object->objectTag();
519
            }
520
            switch ($params['object']) {
521
                case 'product':
522
                    $viewParams = ['products' => $objects];
523
                    break;
524
                default:
525
                    $viewParams = ['products' => $objects];
526
                    break;
527
            }
528
        } else {
529
            $view = $params['itemView'];
530
            $object = $query->one();
531
            if (is_null($object)) {
532
                return '';
533
            }
534
            $dependency->tags[] = $object->objectTag();
535
            switch ($params['object']) {
536 View Code Duplication
                case 'product':
537
                    $viewParams = [
538
                        'product' => $object,
539
                        'url' => Url::to(
540
                            [
541
                                '@product',
542
                                'model' => $object,
543
                                'category_group_id' => $object->getMainCategory()->category_group_id,
544
                            ]
545
                        )
546
                    ];
547
                    break;
548 View Code Duplication
                default:
549
                    $viewParams = [
550
                        'product' => $object,
551
                        'url' => Url::to(
552
                            [
553
                                '@product',
554
                                'model' => $object,
555
                                'category_group_id' => $object->getMainCategory()->category_group_id,
556
                            ]
557
                        )
558
                    ];
559
                    break;
560
            }
561
        }
562
        return Yii::$app->view->render($view, $viewParams);
563
    }
564
}
565