Passed
Push — master ( 662d52...2a8232 )
by eXeCUT
03:58
created

components/parser/ModelsFinder.php (2 issues)

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: execut
5
 * Date: 10/4/16
6
 * Time: 4:14 PM
7
 */
8
9
namespace execut\import\components\parser;
10
11
12
use execut\import\components\parser\exception\MoreThanOne;
13
use execut\import\components\parser\exception\NotFoundRecord;
14
use execut\import\Query;
15
use yii\base\Component;
16
use yii\helpers\Json;
17
18
class ModelsFinder extends Component
19
{
20
    public $isCreateAlways = false;
21
    public $isUpdateAlways = false;
22
    public $isCreateNotExisted = false;
23
    public $attributes = null;
24
    static $cache = [];
25
    public $query = null;
26
    public $prepareQuery = null;
27
    public $advancedSearch = null;
28
    public $asArray = false;
29
    /**
30
     * @var Stack
31
     */
32
    public $stack = null;
33
34
    protected function findModelFromCache() {
35
        if ($model = $this->getCache()) {
36
            return $model;
37
        } else {
38
            $model = new $this->query->modelClass;
39
            $this->setCache($model);
40
        }
41
42
        return $model;
43
    }
44
45
    public function getCache() {
46
        $key = $this->getCacheKey(false);
47
        $subKey = $this->getCacheKey();
48
        if (isset(self::$cache[$key]) && isset(self::$cache[$key][$subKey])) {
49
            return self::$cache[$key][$subKey];
50
        }
51
    }
52
53
    public function setCache($model, $subKey = null) {
54
        $key = $this->getCacheKey(false);
55
        if ($subKey === null) {
56
            $subKey = $this->getCacheKey();
57
        }
58
59
        if (!isset(self::$cache[$key])) {
60
            self::$cache[$key] = [];
61
        }
62
63
        self::$cache[$key][$subKey] = $model;
64
    }
65
66
    public function findModelNew() {
67
        if (!isset(self::$cache[$this->getCacheKey(false)])) {
68
            $this->initCache();
69
        }
70
71
        $result = new Result();
72
        $model = $this->findModelFromCache();
73
        $model->attributes = $this->getAttributesValues();
74
        $result->addModel($model);
75
76
        return $result;
77
    }
78
79 6
    public function findModel() {
80 6
        $cacheKey = $this->getCacheKey();
81 6
        if (isset(self::$cache[$cacheKey])) {
82
            return self::$cache[$cacheKey];
83
        }
84
85 6
        if (count(self::$cache) > 10000) {
86
            echo 'clean(' . count(self::$cache) . ')';
87
            self::$cache = array_splice(self::$cache, -3000);
88
        }
89
90 6
        $q = $this->query;
91 6
        $q = clone $q;
92 6
        $modelClass = $q->modelClass;
93 6
        $result = new Result();
94 6
        $attributesValues = $this->getAttributesValues();
95 6
        if ($this->isCreateAlways) {
96 2
            $model = new $modelClass;
97 2
            $result->addModel($model);
98
        } else {
99 4
            $attributeForSearch = $this->getAttributesForSearch();
100 4
            if ($q instanceof Query) {
101 4
                $q->byImportAttributes($attributeForSearch);
102
            } else {
103
                $q->andWhere($attributeForSearch);
104
            }
105
106 4
            if ($this->prepareQuery !== null) {
107 1
                $callback = $this->prepareQuery;
108 1
                $q = $callback($q, $result, $this->stack);
109
            }
110
111 4
            if ($this->advancedSearch !== null) {
112
                $callback = $this->advancedSearch;
113
                $models = $callback($q, $result, $this->stack);
114
            } else {
115 4
                $models = $q->all();
116
            }
117
118 4
            if (count($models) > 1) {
119 1
                $exception = new MoreThanOne();
120 1
                $exception->modelClass = $modelClass;
121 1
                $exception->attributes = $attributesValues;
122
123 1
                throw $exception;
124
            }
125
126 3
            if (count($models) == 1) {
127 2
                $model = current($models);
128 2
                if ($this->isUpdateAlways) {
129
                    $model->attributes = $attributesValues;
130
                }
131
132 2
                $result->addModel($model);
133
134 2
                return self::$cache[$cacheKey] = $result;
135 1
            } else if ($this->isCreateNotExisted) {
136
                $model = new $modelClass;
137
                $result->addModel($model);
138
            } else {
139 1
                $exception = new NotFoundRecord();
140 1
                $exception->modelClass = $modelClass;
141 1
                $exception->attributes = $attributesValues;
142
143 1
                throw $exception;
144
            }
145
        }
146
147 2
        $model->attributes = $attributesValues;
148
149 2
        return self::$cache[$cacheKey] = $result;
150
    }
151
152
    /**
153
     * @return array
154
     */
155 6
    protected function getAttributesForSearch(): array
156
    {
157 6
        $attributes = $this->getAttributes();
158 6
        $attributeForSearch = [];
159 6
        foreach ($attributes as $attribute) {
160 6
            if ($attribute->isForSearchQuery) {
161 6
                $attributeForSearch[$attribute->key] = $attribute->value;
162
            }
163
        }
164 6
        return $attributeForSearch;
165
    }
166
167
    /**
168
     * @return array
169
     */
170 6
    protected function getAttributesValues(): array
171
    {
172 6
        $attributesValues = [];
173 6
        $attributes = $this->getAttributes();
174 6
        foreach ($attributes as $attribute) {
175 6
            $attributesValues[$attribute->key] = $attribute->value;
176
        }
177 6
        return $attributesValues;
178
    }
179
180
    /**
181
     * @param $row
182
     * @return array
183
     */
184 6
    protected function getAttributes(): array
185
    {
186 6
        return $this->attributes;
187
    }
188
189
    protected function initCache(): void
190
    {
191
        $attributesNames = $this->getSearchAttributesNames();
192
193
        $stack = $this->stack;
194
        $rows = $stack->rows;
0 ignored issues
show
Bug Best Practice introduced by eXeCUT
The property rows does not exist on execut\import\components\parser\Stack. Since you implemented __get, consider adding a @property annotation.
Loading history...
195
        $findPairs = [];
196
        foreach ($rows as $rowNbr => $row) {
197
            $attributes = $this->getAttributesFromRow($rowNbr);
0 ignored issues
show
The method getAttributesFromRow() does not exist on execut\import\components\parser\ModelsFinder. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

197
            /** @scrutinizer ignore-call */ 
198
            $attributes = $this->getAttributesFromRow($rowNbr);
Loading history...
198
            $attributesValues = [];
199
            foreach ($attributes as $attribute) {
200
                if (!$attribute->isValid()) {
201
                    continue 2;
202
                }
203
204
                if (!$attribute->isForSearchQuery) {
205
                    continue;
206
                }
207
208
                $attributesValues[$attribute->key] = $attribute->value;
209
            }
210
            $findPairs[] = $attributesValues;
211
        }
212
213
        $q = clone $this->query;
214
        $q->andWhere([
215
            'IN',
216
            $attributesNames,
217
            $findPairs
218
        ]);
219
220
        $models = $q->all();
221
        foreach ($models as $model) {
222
            $attributeForSearch = [];
223
            foreach ($attributesNames as $attributesName) {
224
                $attributeForSearch[$attributesName] = $model->$attributesName;
225
            }
226
227
            $cacheKey = $q->modelClass . ' ' . Json::encode($attributeForSearch);
228
            $this->setCache($model, $cacheKey);
229
        }
230
    }
231
232
    /**
233
     * @return string
234
     */
235 6
    protected function getCacheKey($isWithAttributes = true): string
236
    {
237 6
        $attributeForSearch = $this->getAttributesForSearch();
238 6
        $cacheKey = $this->query->modelClass;
239 6
        if ($isWithAttributes) {
240 6
            $cacheKey .= ' ' . Json::encode($attributeForSearch);
241
        }
242
243 6
        return $cacheKey;
244
    }
245
246
    /**
247
     * @return array
248
     */
249
    protected function getSearchAttributesNames(): array
250
    {
251
        $attributesNames = [];
252
        $attributes = $this->getAttributesFromRow();
253
        foreach ($attributes as $attribute) {
254
            if (!$attribute->isForSearchQuery) {
255
                continue;
256
            }
257
258
            $attributesNames[] = $attribute->key;
259
        }
260
        return $attributesNames;
261
    }
262
}