1 | <?php |
||
40 | class ScopeService extends BaseService implements ScopeServiceInterface |
||
41 | { |
||
42 | |||
43 | /** |
||
44 | * @param string $sid scope ID |
||
45 | * @return string scope Key |
||
46 | * @since 1.0.0 |
||
47 | */ |
||
48 | 18 | protected function getScopeKey($sid) |
|
52 | |||
53 | /** |
||
54 | * @return string key of all scopes list |
||
55 | * @since 1.0.0 |
||
56 | */ |
||
57 | 18 | protected function getScopeListKey() |
|
61 | |||
62 | /** |
||
63 | * @return string key of default scopes list |
||
64 | * @since 1.0.0 |
||
65 | */ |
||
66 | 25 | protected function getScopeDefaultListKey() |
|
70 | |||
71 | /** |
||
72 | * @inheritdoc |
||
73 | */ |
||
74 | 18 | public function save(ScopeModelInterface $scope, $attributes) |
|
75 | { |
||
76 | 18 | if ($scope->getIsNewRecord()) { |
|
77 | 18 | $result = $this->insert($scope, $attributes); |
|
78 | 18 | } else { |
|
79 | 1 | $result = $this->update($scope, $attributes); |
|
80 | } |
||
81 | 18 | return $result; |
|
82 | } |
||
83 | |||
84 | /** |
||
85 | * Save Scope |
||
86 | * @param ScopeModelInterface $scope |
||
87 | * @param null|array $attributes attributes to save |
||
88 | * @return bool |
||
89 | * @throws DatabaseException |
||
90 | * @throws DuplicateIndexException |
||
91 | * @throws DuplicateKeyException |
||
92 | * @since 1.0.0 |
||
93 | */ |
||
94 | 18 | protected function insert(ScopeModelInterface $scope, $attributes) |
|
95 | { |
||
96 | 18 | $result = false; |
|
97 | 18 | if (!$scope->beforeSave(true)) { |
|
98 | return $result; |
||
99 | } |
||
100 | 18 | $scopeKey = $this->getScopeKey($scope->getKey()); |
|
101 | 18 | $scopeListKey = $this->getScopeListKey(); |
|
102 | 18 | $scopeDefaultListKey = $this->getScopeDefaultListKey(); |
|
103 | //check if record exists |
||
104 | 18 | $entityStatus = (int)$this->db->executeCommand('EXISTS', [$scopeKey]); |
|
105 | 18 | if ($entityStatus === 1) { |
|
106 | 1 | throw new DuplicateKeyException('Duplicate key "'.$scopeKey.'"'); |
|
107 | } |
||
108 | |||
109 | 18 | $values = $scope->getDirtyAttributes($attributes); |
|
|
|||
110 | 18 | $redisParameters = [$scopeKey]; |
|
111 | 18 | $this->setAttributesDefinitions($scope->attributesDefinition()); |
|
112 | 18 | foreach ($values as $key => $value) |
|
113 | { |
||
114 | 18 | if ($value !== null) { |
|
115 | 18 | $redisParameters[] = $key; |
|
116 | 18 | $redisParameters[] = $this->convertToDatabase($key, $value); |
|
117 | 18 | } |
|
118 | 18 | } |
|
119 | //TODO: use EXEC/MULTI to avoid errors |
||
120 | 18 | $transaction = $this->db->executeCommand('MULTI'); |
|
121 | 18 | if ($transaction === true) { |
|
122 | try { |
||
123 | 18 | $this->db->executeCommand('HMSET', $redisParameters); |
|
124 | 18 | $this->db->executeCommand('SADD', [$scopeListKey, $scope->getKey()]); |
|
125 | 18 | if ($scope->isDefault === true) { |
|
126 | 17 | $this->db->executeCommand('SADD', [$scopeDefaultListKey, $scope->getKey()]); |
|
127 | 17 | } |
|
128 | 18 | $this->db->executeCommand('EXEC'); |
|
129 | 18 | } catch (DatabaseException $e) { |
|
130 | // @codeCoverageIgnoreStart |
||
131 | // we have a REDIS exception, we should not discard |
||
132 | Yii::debug('Error while inserting entity', __METHOD__); |
||
133 | throw $e; |
||
134 | // @codeCoverageIgnoreEnd |
||
135 | } |
||
136 | 18 | } |
|
137 | 18 | $changedAttributes = array_fill_keys(array_keys($values), null); |
|
138 | 18 | $scope->setOldAttributes($values); |
|
139 | 18 | $scope->afterSave(true, $changedAttributes); |
|
140 | 18 | $result = true; |
|
141 | 18 | return $result; |
|
142 | } |
||
143 | |||
144 | |||
145 | /** |
||
146 | * Update ScopeModelInterface |
||
147 | * @param Scope $scope |
||
148 | * @param null|array $attributes attributes to save |
||
149 | * @return bool |
||
150 | * @throws DatabaseException |
||
151 | * @throws DuplicateIndexException |
||
152 | * @throws DuplicateKeyException |
||
153 | */ |
||
154 | 1 | protected function update(ScopeModelInterface $scope, $attributes) |
|
155 | { |
||
156 | 1 | if (!$scope->beforeSave(false)) { |
|
157 | return false; |
||
158 | } |
||
159 | |||
160 | 1 | $values = $scope->getDirtyAttributes($attributes); |
|
161 | 1 | $modelKey = $scope->key(); |
|
162 | 1 | $scopeId = isset($values[$modelKey]) ? $values[$modelKey] : $scope->getKey(); |
|
163 | 1 | $scopeKey = $this->getScopeKey($scopeId); |
|
164 | 1 | $scopeListKey = $this->getScopeListKey(); |
|
165 | 1 | $scopeDefaultListKey = $this->getScopeDefaultListKey(); |
|
166 | |||
167 | |||
168 | 1 | if (isset($values[$modelKey]) === true) { |
|
169 | 1 | $newScopeKey = $this->getScopeKey($values[$modelKey]); |
|
170 | 1 | $entityStatus = (int)$this->db->executeCommand('EXISTS', [$newScopeKey]); |
|
171 | 1 | if ($entityStatus === 1) { |
|
172 | 1 | throw new DuplicateKeyException('Duplicate key "'.$newScopeKey.'"'); |
|
173 | } |
||
174 | 1 | } |
|
175 | |||
176 | 1 | $this->db->executeCommand('MULTI'); |
|
177 | try { |
||
178 | 1 | $reAddKeyInList = false; |
|
179 | 1 | if (array_key_exists($modelKey, $values) === true) { |
|
180 | 1 | $oldId = $scope->getOldKey(); |
|
181 | 1 | $oldScopeKey = $this->getScopeKey($oldId); |
|
182 | |||
183 | 1 | $this->db->executeCommand('RENAMENX', [$oldScopeKey, $scopeKey]); |
|
184 | 1 | $this->db->executeCommand('SREM', [$scopeListKey, $oldScopeKey]); |
|
185 | 1 | $this->db->executeCommand('SREM', [$scopeDefaultListKey, $oldScopeKey]); |
|
186 | 1 | $reAddKeyInList = true; |
|
187 | 1 | } |
|
188 | |||
189 | 1 | $redisUpdateParameters = [$scopeKey]; |
|
190 | 1 | $redisDeleteParameters = [$scopeKey]; |
|
191 | 1 | $this->setAttributesDefinitions($scope->attributesDefinition()); |
|
192 | 1 | foreach ($values as $key => $value) |
|
193 | { |
||
194 | 1 | if ($value === null) { |
|
195 | 1 | $redisDeleteParameters[] = $key; |
|
196 | 1 | } else { |
|
197 | 1 | $redisUpdateParameters[] = $key; |
|
198 | 1 | $redisUpdateParameters[] = $this->convertToDatabase($key, $value); |
|
199 | } |
||
200 | 1 | } |
|
201 | 1 | if (count($redisDeleteParameters) > 1) { |
|
202 | 1 | $this->db->executeCommand('HDEL', $redisDeleteParameters); |
|
203 | 1 | } |
|
204 | 1 | if (count($redisUpdateParameters) > 1) { |
|
205 | 1 | $this->db->executeCommand('HMSET', $redisUpdateParameters); |
|
206 | 1 | } |
|
207 | |||
208 | 1 | if ($reAddKeyInList === true) { |
|
209 | 1 | $this->db->executeCommand('SADD', [$scopeListKey, $scopeId]); |
|
210 | 1 | } |
|
211 | 1 | if ($scope->isDefault === true) { |
|
212 | 1 | $this->db->executeCommand('SADD', [$scopeDefaultListKey, $scopeId]); |
|
213 | 1 | } else { |
|
214 | 1 | $this->db->executeCommand('SREM', [$scopeDefaultListKey, $scopeId]); |
|
215 | } |
||
216 | |||
217 | 1 | $this->db->executeCommand('EXEC'); |
|
218 | 1 | } catch (DatabaseException $e) { |
|
219 | // @codeCoverageIgnoreStart |
||
220 | // we have a REDIS exception, we should not discard |
||
221 | Yii::debug('Error while updating entity', __METHOD__); |
||
222 | throw $e; |
||
223 | // @codeCoverageIgnoreEnd |
||
224 | } |
||
225 | |||
226 | 1 | $changedAttributes = []; |
|
227 | 1 | foreach ($values as $name => $value) { |
|
228 | 1 | $oldAttributes = $scope->getOldAttributes(); |
|
229 | 1 | $changedAttributes[$name] = isset($oldAttributes[$name]) ? $oldAttributes[$name] : null; |
|
230 | 1 | $scope->setOldAttribute($name, $value); |
|
231 | 1 | } |
|
232 | 1 | $scope->afterSave(false, $changedAttributes); |
|
233 | 1 | return true; |
|
234 | } |
||
235 | |||
236 | /** |
||
237 | * @inheritdoc |
||
238 | */ |
||
239 | 2 | public function findOne($key) |
|
270 | |||
271 | /** |
||
272 | * @inheritdoc |
||
273 | */ |
||
274 | 17 | public function findAvailableScopeIds() |
|
279 | |||
280 | /** |
||
281 | * @inheritdoc |
||
282 | */ |
||
283 | 11 | public function findDefaultScopeIds($clientId = null) |
|
289 | |||
290 | /** |
||
291 | * @inheritdoc |
||
292 | */ |
||
293 | 1 | public function delete(ScopeModelInterface $scope) |
|
315 | |||
316 | } |
||
317 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.