This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @copyright Copyright (c) Flipbox Digital Limited |
||
5 | * @license https://flipboxfactory.com/software/meta/license |
||
6 | * @link https://www.flipboxfactory.com/software/meta/ |
||
7 | */ |
||
8 | |||
9 | namespace flipbox\meta\services; |
||
10 | |||
11 | use Craft; |
||
12 | use craft\base\Element; |
||
13 | use craft\base\ElementInterface; |
||
14 | use craft\db\Query; |
||
15 | use craft\helpers\StringHelper; |
||
16 | use flipbox\meta\elements\db\Meta as MetaQuery; |
||
17 | use flipbox\meta\elements\Meta as MetaElement; |
||
18 | use flipbox\meta\fields\Meta as MetaField; |
||
19 | use flipbox\meta\helpers\Field as FieldHelper; |
||
20 | use yii\base\Component; |
||
21 | |||
22 | /** |
||
23 | * @author Flipbox Factory <[email protected]> |
||
24 | * @since 1.0.0 |
||
25 | * |
||
26 | * @method MetaQuery find() |
||
27 | */ |
||
28 | class Field extends Component |
||
29 | { |
||
30 | |||
31 | /** |
||
32 | * @param MetaField $field |
||
33 | * @param ElementInterface $element |
||
34 | * @return bool |
||
35 | */ |
||
36 | public function beforeElementDelete(MetaField $field, ElementInterface $element): bool |
||
37 | { |
||
38 | |||
39 | // Delete any meta elements that belong to this element(s) |
||
40 | foreach (Craft::$app->getSites()->getAllSiteIds() as $siteId) { |
||
41 | $query = MetaElement::find(); |
||
42 | $query->status(null); |
||
43 | $query->enabledForSite(false); |
||
44 | $query->fieldId($field->id); |
||
45 | $query->siteId($siteId); |
||
46 | $query->owner($element); |
||
47 | |||
48 | /** @var MetaElement $meta */ |
||
49 | foreach ($query->all() as $meta) { |
||
50 | Craft::$app->getElements()->deleteElement($meta); |
||
51 | } |
||
52 | } |
||
53 | |||
54 | return true; |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * @param MetaField $field |
||
59 | * @param ElementInterface $owner |
||
60 | * @return bool |
||
61 | * @throws \Exception |
||
62 | * @throws \yii\db\Exception |
||
63 | */ |
||
64 | public function afterElementSave(MetaField $field, ElementInterface $owner) |
||
65 | { |
||
66 | |||
67 | /** @var Element $owner */ |
||
68 | |||
69 | /** @var MetaQuery $query */ |
||
70 | $query = $owner->getFieldValue($field->handle); |
||
71 | |||
72 | $transaction = Craft::$app->getDb()->beginTransaction(); |
||
73 | try { |
||
74 | // Do localization |
||
75 | $this->applyFieldLocalizationSetting($owner, $field, $query); |
||
76 | |||
77 | $metaIds = []; |
||
78 | |||
79 | /** @var Meta $element */ |
||
80 | foreach ($query->all() as $meta) { |
||
81 | // Set owner based attributes |
||
82 | $meta->ownerId = $owner->id; |
||
83 | $meta->ownerSiteId = ($field->localize ? $owner->siteId : null); |
||
84 | |||
85 | // Save |
||
86 | Craft::$app->getElements()->saveElement($meta, false); |
||
87 | |||
88 | $metaIds[] = $meta->id; |
||
89 | } |
||
90 | |||
91 | // Delete any elements that shouldn't be there anymore |
||
92 | $deleteElementsQuery = MetaElement::find() |
||
93 | ->ownerId($owner->getId()) |
||
94 | ->fieldId($field->id) |
||
95 | ->andWhere(['not', ['elements.id' => $metaIds]]); |
||
96 | |||
97 | if ($field->localize) { |
||
98 | $deleteElementsQuery->ownerSiteId = $owner->siteId; |
||
99 | } else { |
||
100 | $deleteElementsQuery->siteId = $owner->siteId; |
||
101 | } |
||
102 | |||
103 | foreach ($deleteElementsQuery->all() as $deleteElement) { |
||
104 | Craft::$app->getElements()->deleteElement($deleteElement); |
||
105 | } |
||
106 | |||
107 | // Success |
||
108 | $transaction->commit(); |
||
109 | } catch (\Exception $e) { |
||
110 | // Revert |
||
111 | $transaction->rollback(); |
||
112 | |||
113 | throw $e; |
||
114 | } |
||
115 | |||
116 | return true; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Applies the field's translation setting to a set of elements. |
||
121 | * |
||
122 | * @param ElementInterface $owner |
||
123 | * @param MetaField $field |
||
124 | * @param MetaQuery $query |
||
125 | * |
||
126 | * @return void |
||
127 | */ |
||
128 | private function applyFieldLocalizationSetting(ElementInterface $owner, MetaField $field, MetaQuery $query) |
||
129 | { |
||
130 | |||
131 | /** @var Element $owner */ |
||
132 | |||
133 | // Does it look like any work is needed here? |
||
134 | $applyNewLocalizationSetting = false; |
||
135 | |||
136 | foreach ($query->all() as $meta) { |
||
137 | if ($meta->id && ( |
||
138 | ($field->localize && !$meta->ownerSiteId) || |
||
139 | (!$field->localize && $meta->ownerSiteId) |
||
140 | ) |
||
141 | ) { |
||
142 | $applyNewLocalizationSetting = true; |
||
143 | break; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | if (!$applyNewLocalizationSetting) { |
||
148 | // All good |
||
149 | return; |
||
150 | } |
||
151 | |||
152 | // Get all of the elements for this field/owner that use the other locales, whose ownerLocale attribute is set |
||
153 | // incorrectly |
||
154 | $elementsInOtherSites = []; |
||
155 | |||
156 | $query = MetaElement::find() |
||
157 | ->fieldId($field->id) |
||
158 | ->ownerId($owner->getId()) |
||
159 | ->status(null) |
||
160 | ->enabledForSite(false) |
||
161 | ->limit(null); |
||
162 | |||
163 | if ($field->localize) { |
||
164 | $query->ownerSiteId(':empty:'); |
||
0 ignored issues
–
show
|
|||
165 | } |
||
166 | |||
167 | foreach (Craft::$app->getI18n()->getSiteLocaleIds() as $siteId) { |
||
168 | if ($siteId === $owner->siteId) { |
||
169 | continue; |
||
170 | } |
||
171 | |||
172 | $query->siteId($siteId); |
||
173 | |||
174 | if (!$field->localize) { |
||
175 | $query->ownerSiteId($siteId); |
||
0 ignored issues
–
show
The method
ownerSiteId() does not exist on craft\elements\db\ElementQuery . Did you maybe mean siteId() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
176 | } |
||
177 | |||
178 | $elementsInOtherSite = $query->all(); |
||
179 | |||
180 | if (!empty($elementsInOtherSite)) { |
||
181 | $elementsInOtherSites[$siteId] = $elementsInOtherSite; |
||
182 | } |
||
183 | } |
||
184 | |||
185 | if (empty($elementsInOtherSites)) { |
||
186 | return; |
||
187 | } |
||
188 | |||
189 | if ($field->localize) { |
||
190 | $newElementIds = []; |
||
191 | |||
192 | // Duplicate the other-site elements so each site has their own unique set of elements |
||
193 | foreach ($elementsInOtherSites as $siteId => $elementsInOtherSite) { |
||
194 | foreach ($elementsInOtherSite as $elementInOtherSite) { |
||
195 | /** @var MetaElement $elementInOtherSite */ |
||
196 | $originalElementId = $elementInOtherSite->id; |
||
197 | |||
198 | $elementInOtherSite->id = null; |
||
199 | $elementInOtherSite->contentId = null; |
||
200 | $elementInOtherSite->ownerSiteId = (int)$siteId; |
||
201 | Craft::$app->getElements()->saveElement($elementInOtherSite, false); |
||
202 | |||
203 | $newElementIds[$originalElementId][$siteId] = $elementInOtherSite->id; |
||
204 | } |
||
205 | } |
||
206 | |||
207 | // Duplicate the relations, too. First by getting all of the existing relations for the original |
||
208 | // elements |
||
209 | $relations = (new Query()) |
||
210 | ->select([ |
||
211 | 'fieldId', |
||
212 | 'sourceId', |
||
213 | 'sourceSiteId', |
||
214 | 'targetId', |
||
215 | 'sortOrder' |
||
216 | ]) |
||
217 | ->from(['{{%relations}}']) |
||
218 | ->where(['sourceId' => array_keys($newElementIds)]) |
||
219 | ->all(); |
||
220 | |||
221 | if (!empty($relations)) { |
||
222 | // Now duplicate each one for the other sites' new elements |
||
223 | $rows = []; |
||
224 | |||
225 | foreach ($relations as $relation) { |
||
226 | $originalElementId = $relation['sourceId']; |
||
227 | |||
228 | // Just to be safe... |
||
229 | if (isset($newElementIds[$originalElementId])) { |
||
230 | foreach ($newElementIds[$originalElementId] as $siteId => $newElementId) { |
||
231 | $rows[] = [ |
||
232 | $relation['fieldId'], |
||
233 | $newElementId, |
||
234 | $relation['sourceSiteId'], |
||
235 | $relation['targetId'], |
||
236 | $relation['sortOrder'] |
||
237 | ]; |
||
238 | } |
||
239 | } |
||
240 | } |
||
241 | |||
242 | Craft::$app->getDb()->createCommand() |
||
243 | ->batchInsert( |
||
244 | 'relations', |
||
245 | [ |
||
246 | 'fieldId', |
||
247 | 'sourceId', |
||
248 | 'sourceSiteId', |
||
249 | 'targetId', |
||
250 | 'sortOrder' |
||
251 | ], |
||
252 | $rows |
||
253 | ) |
||
254 | ->execute(); |
||
255 | } |
||
256 | } else { |
||
257 | // Delete all of these elements |
||
258 | $deletedElementIds = []; |
||
259 | |||
260 | foreach ($elementsInOtherSites as $elementsInOtherSite) { |
||
261 | foreach ($elementsInOtherSite as $elementInOtherSite) { |
||
262 | // Have we already deleted this element? |
||
263 | if (in_array($elementInOtherSite->id, $deletedElementIds, false)) { |
||
264 | continue; |
||
265 | } |
||
266 | |||
267 | Craft::$app->getElements()->deleteElement($elementInOtherSite); |
||
268 | $deletedElementIds[] = $elementInOtherSite->id; |
||
269 | } |
||
270 | } |
||
271 | } |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * Returns the content table name for a given Meta field. |
||
276 | * |
||
277 | * @param MetaField $metaField |
||
278 | * @return string |
||
279 | */ |
||
280 | public function getContentTableName(MetaField $metaField): string |
||
281 | { |
||
282 | return FieldHelper::getContentTableName($metaField->id); |
||
283 | } |
||
284 | } |
||
285 |
This check marks calls to methods that do not seem to exist on an object.
This is most likely the result of a method being renamed without all references to it being renamed likewise.