Completed
Push — develop ( e47b53...a63fce )
by Nate
08:38
created

Fields   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 432
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 55
lcom 1
cbo 12
dl 0
loc 432
ccs 0
cts 261
cp 0
rs 6.8
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A tableAlias() 0 4 1
A ensureField() 0 10 2
A getQuery() 0 14 1
A serializeValue() 0 19 2
C normalizeQueryInputValues() 0 63 9
B getExistingValues() 0 28 6
A beforeElementDelete() 0 19 3
F afterElementSave() 0 87 14
D applyFieldTranslationSetting() 0 88 16
A normalizeQueryInputValue() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like Fields 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 Fields, and based on these observations, apply Extract Interface, too.

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\base\FieldInterface;
15
use craft\elements\db\ElementQueryInterface;
16
use craft\fields\BaseRelationField;
17
use flipbox\craft\sortable\associations\db\SortableAssociationQueryInterface;
18
use flipbox\craft\sortable\associations\records\SortableAssociationInterface;
19
use flipbox\craft\sortable\associations\services\SortableFields;
20
use flipbox\meta\db\MetaQuery;
21
use flipbox\meta\elements\Meta as MetaElement;
22
use flipbox\meta\fields\Meta;
23
use flipbox\meta\fields\Meta as MetaField;
24
use flipbox\meta\Meta as MetaPlugin;
25
use flipbox\meta\records\Meta as MetaRecord;
26
use yii\base\Exception;
27
28
/**
29
 * @author Flipbox Factory <[email protected]>
30
 * @since 1.0.0
31
 *
32
 * @method MetaQuery find()
33
 */
34
class Fields extends SortableFields
35
{
36
    /**
37
     * @inheritdoc
38
     */
39
    const SOURCE_ATTRIBUTE = MetaRecord::SOURCE_ATTRIBUTE;
40
41
    /**
42
     * @inheritdoc
43
     */
44
    const TARGET_ATTRIBUTE = MetaRecord::TARGET_ATTRIBUTE;
45
46
    /**
47
     * @inheritdoc
48
     */
49
    protected static function tableAlias(): string
50
    {
51
        return MetaRecord::tableAlias();
52
    }
53
54
    /**
55
     * @param FieldInterface $field
56
     * @throws Exception
57
     */
58
    private function ensureField(FieldInterface $field)
59
    {
60
        if (!$field instanceof MetaField) {
61
            throw new Exception(sprintf(
62
                "The field must be an instance of '%s', '%s' given.",
63
                (string)MetaField::class,
64
                (string)get_class($field)
65
            ));
66
        }
67
    }
68
69
    /**
70
     * @inheritdoc
71
     */
72
    public function getQuery(
73
        FieldInterface $field,
74
        ElementInterface $element = null
75
    ): SortableAssociationQueryInterface {
76
        /** @var MetaField $field */
77
        $this->ensureField($field);
78
79
        $query = MetaPlugin::getInstance()->getElements()->getQuery();
80
81
        $query->siteId = $this->targetSiteId($element);
82
        $query->fieldId = $field->id;
83
84
        return $query;
85
    }
86
87
88
    /*******************************************
89
     * NORMALIZE VALUE
90
     *******************************************/
91
92
    /**
93
     * @param FieldInterface $field
94
     * @param $value
95
     * @param ElementInterface|null $element
96
     * @return array
97
     */
98
    public function serializeValue(
99
        FieldInterface $field,
100
        $value,
101
        ElementInterface $element = null
102
    ): array {
103
        /** @var MetaQuery $value */
104
        $serialized = [];
105
        $new = 0;
106
107
        foreach ($value->all() as $meta) {
108
            $metaId = $meta->id ?? 'new' . ++$new;
109
            $serialized[$metaId] = [
110
                'enabled' => $meta->enabled,
111
                'fields' => $meta->getSerializedFieldValues(),
112
            ];
113
        }
114
115
        return $serialized;
116
    }
117
118
    /*******************************************
119
     * NORMALIZE VALUE
120
     *******************************************/
121
122
    /**
123
     * Accepts input data and converts it into an array of associated Meta elements
124
     *
125
     * @param FieldInterface $field
126
     * @param SortableAssociationQueryInterface $query
127
     * @param array $value
128
     * @param ElementInterface|null $element
129
     */
130
    protected function normalizeQueryInputValues(
131
        FieldInterface $field,
132
        SortableAssociationQueryInterface $query,
133
        array $value,
134
        ElementInterface $element = null
135
    ) {
136
        /** @var MetaField $field */
137
138
        $models = [];
139
        $sortOrder = 1;
140
        $prevElement = null;
141
        /** @var MetaElement|null $prevElement */
142
143
        // Get existing values
144
        $existingValues = $element === null ? [] : $this->getExistingValues($field, $value, $element);
145
        $ownerId = $element->id ?? null;
1 ignored issue
show
Bug introduced by
Accessing id on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
146
147
        foreach ($value as $metaId => $metaData) {
148
            // Is this new? (Or has it been deleted?)
149
            if (strpos($metaId, 'new') === 0 || !isset($existingValues[$metaId])) {
150
                $meta = MetaPlugin::getInstance()->getElements()->create([
151
                    'fieldId' => $field->id,
152
                    'ownerId' => $ownerId,
153
                    'siteId' => $this->targetSiteId($element)
154
                ]);
155
            } else {
156
                $meta = $existingValues[$metaId];
157
            }
158
159
            /** @var MetaElement $meta */
160
161
            $meta->enabled = (bool)$metaData['enabled'] ?? true;
162
            $meta->setOwnerId($ownerId);
163
164
            // Set the content post location on the element if we can
165
            $fieldNamespace = $element->getFieldParamNamespace();
166
167
            if ($fieldNamespace !== null) {
168
                $metaFieldNamespace = ($fieldNamespace ? $fieldNamespace . '.' : '') .
169
                    '.' . $field->handle .
170
                    '.' . $metaId .
171
                    '.fields';
172
                $meta->setFieldParamNamespace($metaFieldNamespace);
173
            }
174
175
            if (isset($metaData['fields'])) {
176
                $meta->setFieldValues($metaData['fields']);
177
            }
178
179
            $sortOrder++;
180
            $meta->sortOrder = $sortOrder;
181
182
            // Set the prev/next elements
183
            if ($prevElement) {
184
                $prevElement->setNext($meta);
185
                $meta->setPrev($prevElement);
186
            }
187
            $prevElement = $meta;
188
189
            $models[] = $meta;
190
        }
191
        $query->setCachedResult($models);
192
    }
193
194
    /**
195
     * @param array $values
196
     * @param ElementInterface $element
197
     * @return array
198
     */
199
    protected function getExistingValues(MetaField $field, array $values, ElementInterface $element): array
200
    {
201
        /** @var Element $element */
202
        if (!empty($element->id)) {
203
            $ids = [];
204
205
            foreach ($values as $metaId => $meta) {
206
                if (is_numeric($metaId) && $metaId !== 0) {
207
                    $ids[] = $metaId;
208
                }
209
            }
210
211
            if (!empty($ids)) {
212
                $oldMetaQuery = MetaPlugin::getInstance()->getElements()->getQuery();
213
                $oldMetaQuery->fieldId($field->id);
214
                $oldMetaQuery->ownerId($element->id);
215
                $oldMetaQuery->id($ids);
216
                $oldMetaQuery->limit(null);
217
                $oldMetaQuery->status(null);
218
                $oldMetaQuery->enabledForSite(false);
219
                $oldMetaQuery->siteId($element->siteId);
220
                $oldMetaQuery->indexBy('id');
221
                return $oldMetaQuery->all();
222
            }
223
        }
224
225
        return [];
226
    }
227
228
229
    /*******************************************
230
     * ELEMENT EVENTS
231
     *******************************************/
232
233
    /**
234
     * @param MetaField $field
235
     * @param ElementInterface $element
236
     * @return bool
237
     * @throws \Throwable
238
     */
239
    public function beforeElementDelete(MetaField $field, ElementInterface $element): bool
240
    {
241
        // Delete any meta elements that belong to this element(s)
242
        foreach (Craft::$app->getSites()->getAllSiteIds() as $siteId) {
243
            $query = MetaElement::find();
244
            $query->status(null);
245
            $query->enabledForSite(false);
246
            $query->fieldId($field->id);
247
            $query->siteId($siteId);
248
            $query->owner($element);
249
250
            /** @var MetaElement $meta */
251
            foreach ($query->all() as $meta) {
252
                Craft::$app->getElements()->deleteElement($meta);
253
            }
254
        }
255
256
        return true;
257
    }
258
259
    /**
260
     * @param Meta $field
261
     * @param ElementInterface $owner
262
     * @throws \Exception
263
     * @throws \Throwable
264
     * @throws \yii\db\Exception
265
     */
266
    public function afterElementSave(MetaField $field, ElementInterface $owner)
267
    {
268
        /** @var Element $owner */
269
270
        /** @var MetaQuery $query */
271
        $query = $owner->getFieldValue($field->handle);
272
273
        // Skip if the query's site ID is different than the element's
274
        // (Indicates that the value as copied from another site for element propagation)
275
        if ($query->siteId != $owner->siteId) {
1 ignored issue
show
Bug introduced by
Accessing siteId on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
276
            return;
277
        }
278
279
        if (null === ($elements = $query->getCachedResult())) {
280
            $query = clone $query;
281
            $query->status = null;
282
            $query->enabledForSite = false;
283
            $elements = $query->all(); // existing meta
284
        }
285
286
287
        $transaction = Craft::$app->getDb()->beginTransaction();
288
        try {
289
            // If this is a preexisting element, make sure that the blocks for this field/owner respect the field's translation setting
290
            if ($query->ownerId) {
291
                $this->applyFieldTranslationSetting($query->ownerId, $query->siteId, $field);
292
            }
293
294
            // If the query is set to fetch blocks of a different owner, we're probably duplicating an element
295
            if ($query->ownerId && $query->ownerId != $owner->id) {
1 ignored issue
show
Bug introduced by
Accessing id on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
296
                // Make sure this owner doesn't already have meta
297
                $newQuery = clone $query;
298
                $newQuery->ownerId = $owner->id;
1 ignored issue
show
Bug introduced by
Accessing id on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
299
                if (!$newQuery->exists()) {
300
                    // Duplicate the blocks for the new owner
301
                    $elementsService = Craft::$app->getElements();
302
                    foreach ($elements as $element) {
303
                        $elementsService->duplicateElement($element, [
304
                            'ownerId' => $owner->id,
1 ignored issue
show
Bug introduced by
Accessing id on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
305
                            'ownerSiteId' => $field->localize ? $owner->siteId : null
1 ignored issue
show
Bug introduced by
Accessing siteId on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
306
                        ]);
307
                    }
308
                }
309
            } else {
310
                $elementIds = [];
311
312
                // Only propagate the blocks if the owner isn't being propagated
313
                $propagate = !$owner->propagating;
0 ignored issues
show
Bug introduced by
Accessing propagating on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
314
315
                /** @var MetaElement $element */
316
                foreach ($elements as $element) {
317
                    $element->setOwnerId($owner->id);
1 ignored issue
show
Bug introduced by
Accessing id on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
318
                    $element->ownerSiteId = ($field->localize ? $owner->siteId : null);
1 ignored issue
show
Bug introduced by
Accessing siteId on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
319
                    $element->propagating = $owner->propagating;
0 ignored issues
show
Bug introduced by
Accessing propagating on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
320
321
                    Craft::$app->getElements()->saveElement($element, false, $propagate);
322
323
                    $elementIds[] = $element->id;
324
                }
325
326
                // Delete any elements that shouldn't be there anymore
327
                $deleteElementsQuery = MetaElement::find()
328
                    ->status(null)
329
                    ->enabledForSite(false)
330
                    ->ownerId($owner->id)
1 ignored issue
show
Bug introduced by
Accessing id on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
331
                    ->fieldId($field->id)
332
                    ->where(['not', ['elements.id' => $elementIds]]);
333
334
                if ($field->localize) {
335
                    $deleteElementsQuery->ownerSiteId($owner->siteId);
1 ignored issue
show
Bug introduced by
Accessing siteId on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
336
                } else {
337
                    $deleteElementsQuery->siteId($owner->siteId);
1 ignored issue
show
Bug introduced by
Accessing siteId on the interface craft\base\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
338
                }
339
340
                foreach ($deleteElementsQuery->all() as $deleteElement) {
341
                    Craft::$app->getElements()->deleteElement($deleteElement);
342
                }
343
            }
344
345
            $transaction->commit();
346
        } catch (\Exception $e) {
347
            $transaction->rollback();
348
            throw $e;
349
        }
350
351
        return;
352
    }
353
354
    /**
355
     * Applies the field's translation setting to a set of blocks.
356
     *
357
     * @param int $ownerId
358
     * @param int $ownerSiteId
359
     * @param Meta $field
360
     * @throws Exception
361
     * @throws \Throwable
362
     * @throws \craft\errors\ElementNotFoundException
363
     */
364
    private function applyFieldTranslationSetting(int $ownerId, int $ownerSiteId, MetaField $field)
365
    {
366
        // If the field is translatable, see if there are any global blocks that should be localized
367
        if ($field->localize) {
368
            $elementQuery = MetaElement::find()
0 ignored issues
show
Bug introduced by
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.

Loading history...
369
                ->fieldId($field->id)
370
                ->ownerId($ownerId)
371
                ->status(null)
372
                ->enabledForSite(false)
373
                ->limit(null)
374
                ->siteId($ownerSiteId)
375
                ->ownerSiteId(':empty:');
376
377
            $elements = $elementQuery->all();
378
379
            if (!empty($elements)) {
380
                // Find any relational fields on these blocks
381
                $relationFields = [];
382
383
                /** @var MetaElement $element */
384
                foreach ($elements as $element) {
385
                    foreach ($element->getFieldLayout()->getFields() as $field) {
386
                        if ($field instanceof BaseRelationField) {
387
                            $relationFields[] = $field->handle;
388
                        }
389
                    }
390
                    break;
391
                }
392
393
                // Prefetch the blocks in all the other sites, in case they have
394
                // any localized content
395
                $otherSiteBlocks = [];
396
                $allSiteIds = Craft::$app->getSites()->getAllSiteIds();
397
                foreach ($allSiteIds as $siteId) {
398
                    if ($siteId != $ownerSiteId) {
399
                        /** @var MetaElement[] $siteElements */
400
                        $siteElements = $otherSiteBlocks[$siteId] = $elementQuery->siteId($siteId)->all();
401
402
                        // Hard-set the relation IDs
403
                        foreach ($siteElements as $element) {
404
                            foreach ($relationFields as $handle) {
405
                                /** @var ElementQueryInterface $relationQuery */
406
                                $relationQuery = $element->getFieldValue($handle);
407
                                $element->setFieldValue($handle, $relationQuery->ids());
408
                            }
409
                        }
410
                    }
411
                }
412
413
                // Explicitly assign the current site's blocks to the current site
414
                foreach ($elements as $element) {
415
                    $element->ownerSiteId = $ownerSiteId;
416
                    Craft::$app->getElements()->saveElement($element, false);
417
                }
418
419
                // Now save the other sites' blocks as new site-specific blocks
420
                foreach ($otherSiteBlocks as $siteId => $siteElements) {
421
                    foreach ($siteElements as $element) {
422
                        $element->id = null;
423
                        $element->contentId = null;
424
                        $element->siteId = (int)$siteId;
425
                        $element->ownerSiteId = (int)$siteId;
426
                        Craft::$app->getElements()->saveElement($element, false);
427
                    }
428
                }
429
            }
430
        } else {
431
432
            // Otherwise, see if the field has any localized blocks that should be deleted
433
            foreach (Craft::$app->getSites()->getAllSiteIds() as $siteId) {
434
                if ($siteId != $ownerSiteId) {
435
                    $elements = MetaElement::find()
0 ignored issues
show
Bug introduced by
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.

Loading history...
436
                        ->fieldId($field->id)
437
                        ->ownerId($ownerId)
438
                        ->status(null)
439
                        ->enabledForSite(false)
440
                        ->limit(null)
441
                        ->siteId($siteId)
442
                        ->ownerSiteId($siteId)
443
                        ->all();
444
445
                    foreach ($elements as $element) {
446
                        Craft::$app->getElements()->deleteElement($element);
447
                    }
448
                }
449
            }
450
        }
451
    }
452
453
    /**
454
     * @inheritdoc
455
     */
456
    protected function normalizeQueryInputValue(
457
        FieldInterface $field,
458
        $value,
459
        int &$sortOrder,
460
        ElementInterface $element = null
461
    ): SortableAssociationInterface {
462
463
        throw new Exception(__METHOD__ . ' is not implemented');
464
    }
465
}
466