Passed
Push — master ( de9f16...6836c0 )
by Aleksandr
02:35
created

TestingClass::testPropertyIsSet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 0
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
4
namespace carono\exchange1c\models;
5
6
7
use carono\exchange1c\helpers\ClassHelper;
8
use carono\exchange1c\helpers\ModuleHelper;
9
use yii\db\ActiveRecord;
10
use yii\helpers\ArrayHelper;
11
use yii\helpers\StringHelper;
12
use Zenwalker\CommerceML\CommerceML;
13
14
/**
15
 * Class TestingClass
16
 *
17
 * @package carono\exchange1c\models
18
 * @property mixed $result
19
 */
20
abstract class TestingClass extends Testing
21
{
22
    public $caption;
23
    protected static $property;
24
    protected static $required = false;
25
    public $expect;
26
27
    /**
28
     * [['name'], 'return' => 'array|string|interface']
29
     * [['name'], 'return' => 'interface', 'value'=>'']
30
     *
31
     *
32
     * @return array
33
     */
34
    protected static function methodRules()
35
    {
36
        return [];
37
    }
38
39
    /**
40
     * @param $result
41
     * @return mixed
42
     */
43
    protected function saveResult($result)
44
    {
45
        if (\Yii::$app->cache) {
46
            \Yii::$app->cache->set([$this->method, self::getPropertyClass()], $result);
47
        }
48
        return $result;
49
    }
50
51
    /**
52
     * @return mixed|null
53
     */
54
    protected function getSavedResult()
55
    {
56
        if (\Yii::$app->cache) {
57
            return \Yii::$app->cache->get([$this->method, self::getPropertyClass()]);
58
        }
59
        return null;
60
    }
61
62
    /**
63
     * @param $params
64
     * @return array
65
     */
66
    protected static function getParams($params)
67
    {
68
        $values = [];
69
        foreach ($params as $param) {
70
            $value = null;
71
            $cml = new CommerceML();
72
            $cml->loadImportXml(\Yii::getAlias('@vendor/carono/yii2-1c-exchange/files/xml/import.xml'));
73
            $cml->loadOffersXml(\Yii::getAlias('@vendor/carono/yii2-1c-exchange/files/xml/offers.xml'));
74
            if ($param instanceof \Closure) {
75
                $values[] = call_user_func($param);
76
            } elseif (StringHelper::startsWith($param, 'cml.')) {
77
                $value = ArrayHelper::getValue($cml, substr($param, 4));
78
            } else {
79
                $value = $param;
80
            }
81
            $values[] = $value;
82
        }
83
        return $values;
84
    }
85
86
    /**
87
     * @return ActiveRecord
88
     */
89
    protected static function getPropertyClass()
90
    {
91
        return self::module()->{static::$property};
92
    }
93
94
    /**
95
     * @param $method
96
     * @param $params
97
     * @return mixed|null
98
     */
99
    protected static function getMethodResult($method, $params)
100
    {
101
        $class = self::getPropertyClass();
102
        $methodResult = null;
103
        if (method_exists($class, $method)) {
104
            $reflectionMethod = new \ReflectionMethod($class, $method);
105
            $params = self::getParams($params);
106
            try {
107
                if ($reflectionMethod->isStatic()) {
108
                    $methodResult = call_user_func_array("$class::$method", $params);
109
                } elseif (!$context = static::getContext()) {
110
                    return null;
111
                } else {
112
                    $methodResult = call_user_func_array([$context, $method], $params);
113
                }
114
            } catch (\Exception $e) {
115
                return null;
116
            }
117
        }
118
        return $methodResult;
119
    }
120
121
    /**
122
     * @param Testing $test
123
     * @param $method
124
     * @param $rule
125
     */
126
    private static function validateMethodRule($test, $method, $rule)
127
    {
128
129
    }
130
131
    public static function findAll()
132
    {
133
        $result = parent::findAll();
134
        foreach (static::methodRules() as $method => $rule) {
135
            $test = new static();
136
            $test->name = "Результат '$method'";
137
            $test->method = $method;
138
            $test->expect = ArrayHelper::getValue($rule, 'return', false) ?: 'VOID';
139
            $result[] = $test;
140
        }
141
        return $result;
142
    }
143
144
    protected static function getContext()
145
    {
146
        $class = \Yii::$app->controller->module->{static::$property};
147
        return InterfaceTest::findByClass($class)->getModel();
148
    }
149
150
    public static function testPropertyIsSet()
151
    {
152
        $property = static::$property;
153
        $test = new static();
154
        $test->name = ModuleHelper::getModuleNameByClass() . "->{$property}";
155
        if (!self::module()->{$property}) {
156
            $test->result = false;
157
            $test->comment = "Необходимо прописать '$property' в модуле '" . ModuleHelper::getModuleNameByClass() . "'";
158
        }
159
        return $test;
160
    }
161
162
    public function hasResult()
163
    {
164
        return $this->_result;
165
    }
166
167
    public function getResult($force = false)
168
    {
169
        if (!$force && ($cache = self::getSavedResult())) {
0 ignored issues
show
Bug Best Practice introduced by
The method carono\exchange1c\models...Class::getSavedResult() is not static, but was called statically. ( Ignorable by Annotation )

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

169
        if (!$force && ($cache = self::/** @scrutinizer ignore-call */ getSavedResult())) {
Loading history...
170
            return $cache;
171
        }
172
        try {
173
            return $this->saveResult($this->prepareResult());
174
        } catch (\Exception $e) {
175
            return $e->getMessage();
176
        }
177
    }
178
179
    public function prepareResult()
180
    {
181
        if ($method = $this->method) {
182
            $methodName = "getResult" . ucfirst($method);
183
            if (method_exists($this, $methodName)) {
184
                $result = call_user_func([$this, $methodName]);
185
                return $this->_result = $result;
186
            } else {
187
                $params = ArrayHelper::getValue(self::methodRules(), $methodName . '.params', []);
188
                return $this->_result = self::getMethodResult($method, $params);
189
            }
190
        } else {
191
            return null;
192
        }
193
    }
194
195
    public static function testImplementsClass()
196
    {
197
        $property = static::$property;
198
        $test = new static();
199
        $test->name = "Реализация интерфейсов $property (" . self::module()->{$property} . ")";
200
        $implements = ClassHelper::getImplementedMethods(self::module()->{$property}, ModuleHelper::getPhpDocInterfaceProperty($property));
201
        $implements = array_filter($implements, function ($data) {
202
            return !$data;
203
        });
204
        if ($implements) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $implements of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
introduced by
The condition $implements can never be true.
Loading history...
205
            $comment = [];
206
            foreach ($implements as $class => $value) {
207
                $comment[] = $class;
208
                $test->addError('', 'Need implement: ' . $class);
209
            }
210
            $test->comment = "Не реализованы:<br>" . join("<br>", $comment);
211
        }
212
        return $test;
213
    }
214
215
    public static function getMethodRule($method)
216
    {
217
        return ArrayHelper::getValue(static::methodRules(), $method, []);
218
    }
219
220
    public function isAutoTest()
221
    {
222
        return ArrayHelper::getValue(self::getMethodRule($this->method), 'auto') == true;
223
    }
224
225
    public function validateMethod()
226
    {
227
//        $class = self::getPropertyClass();
0 ignored issues
show
Unused Code Comprehensibility introduced by
49% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
228
//        if (method_exists($class, $method)) {
229
//            $reflectionMethod = new \ReflectionMethod($class, $method);
230
//            if ($params = ArrayHelper::getValue($rule, 'params', [])) {
231
//                $params = self::getParams($params);
232
//            }
233
//            try {
234
//                if ($reflectionMethod->isStatic()) {
235
//                    $methodResult = call_user_func_array("$class::$method", $params);
236
//                } elseif (!$context = static::getContext()) {
237
//                    $test->result = false;
238
//                    $test->comment = 'Не найдена модель для проверки';
239
//                    return;
240
//                } else {
241
//                    $methodResult = call_user_func_array([$context, $method], $params);
242
//                }
243
//            } catch (\Exception $e) {
244
//                $test->result = false;
245
//                $test->comment = $e->getMessage();
246
//                return;
247
//            }
248
//            switch (ArrayHelper::getValue($rule, 'return')) {
249
//                case "array":
250
//                    if (!is_array($methodResult)) {
251
//                        $test->result = false;
252
//                        $test->comment = 'Значение должно быть массивом';
253
//                    }
254
//                    break;
255
//                case "string":
256
//                    if (!is_string($methodResult)) {
257
//                        $test->result = false;
258
//                        $test->comment = 'Значение должно быть строкой';
259
//                    }
260
//                    break;
261
//                case "interface":
262
//                    if ($methodResult) {
263
//                        if (is_object($methodResult)) {
264
//                            $reflection = new \ReflectionClass(get_class($methodResult));
265
//                            if (!$reflection->implementsInterface(ltrim($rule['value'], '\\'))) {
266
//                                $test->result = false;
267
//                                $test->comment = "Результат должен имплементировать {$rule['value']}";
268
//                            }
269
//                        } else {
270
//                            $test->result = false;
271
//                            $test->comment = "Результат должен быль объектом и имплементировать {$rule['value']}";
272
//                        }
273
//                    } else {
274
//                        $test->result = null;
275
//                        $test->comment = 'Нет результата';
276
//                    }
277
//                    break;
278
//                case false:
279
//                    $test->result = null;
280
//                    $test->comment = 'VOID';
281
//                    break;
282
//                default:
283
//                    $test->comment = 'FAIL';
284
//                    $test->result = false;
285
//            }
286
//        } else {
287
//            $test->result = false;
288
//            $test->comment = 'Метод не реализован';
289
//        }
290
    }
291
292
    public function testing()
293
    {
294
        if (!$rule = self::getMethodRule($this->method)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $rule is dead and can be removed.
Loading history...
295
            return parent::testing();
296
        }
297
        if ($this->isAutoTest()) {
298
            if ($this->validateMethod()) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->validateMethod() targeting carono\exchange1c\models...Class::validateMethod() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
299
                return $this->result ?: true;
300
            } else {
301
                return false;
302
            }
303
        } else {
304
            return null;
305
        }
306
    }
307
}