Passed
Push — 2.x ( c00759...e3c99f )
by Quentin
07:55
created

HandleBlocks::getChildrenBlocks()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4.0058

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 5
nop 5
dl 0
loc 21
ccs 13
cts 14
cp 0.9286
crap 4.0058
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
namespace A17\Twill\Repositories\Behaviors;
4
5
use A17\Twill\Models\Behaviors\HasMedias;
6
use A17\Twill\Repositories\BlockRepository;
7
use A17\Twill\Services\Blocks\BlockCollection;
8
use Illuminate\Support\Collection;
9
use Schema;
10
11
trait HandleBlocks
12
{
13
    /**
14
     * @param \A17\Twill\Models\Model $object
15
     * @param array $fields
16
     * @return \A17\Twill\Models\Model|void
17
     */
18 2
    public function hydrateHandleBlocks($object, $fields, &$fakeBlockId = 0, $parentId = null, $blocksFromFields = null, $mainCollection = null)
19
    {
20 2
        if ($this->shouldIgnoreFieldBeforeSave('blocks')) {
0 ignored issues
show
Bug introduced by
It seems like shouldIgnoreFieldBeforeSave() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

20
        if ($this->/** @scrutinizer ignore-call */ shouldIgnoreFieldBeforeSave('blocks')) {
Loading history...
21
            return;
22
        }
23
24 2
        $firstItem = false;
25 2
        $blocksCollection = Collection::make();
0 ignored issues
show
Unused Code introduced by
The assignment to $blocksCollection is dead and can be removed.
Loading history...
26 2
        if ($mainCollection === null) {
27 2
            $firstItem = true;
28 2
            $mainCollection = Collection::make();
29
        }
30 2
        if ($blocksFromFields === null) {
31 2
            $blocksFromFields = $this->getBlocks($object, $fields);
32
        }
33
34 2
        $blockRepository = app(BlockRepository::class);
35 2
        $blocksCollection = $this->getChildrenBlocks($blocksFromFields, $blockRepository, $parentId, $fakeBlockId, $mainCollection);
36 2
        $object->setRelation('blocks', $firstItem ? $mainCollection : $blocksCollection);
37 2
        return $object;
38
    }
39
40 2
    protected function getChildrenBlocks($blocks, $blockRepository, $parentId, &$fakeBlockId, $mainCollection)
41
    {
42 2
        $childBlocksCollection = Collection::make();
43
44 2
        foreach ($blocks as $childBlock) {
45 1
            if ($parentId) {
46
                $childBlock['parent_id'] = $parentId;
47
            }
48 1
            $newChildBlock = $blockRepository->createForPreview($childBlock);
49
50 1
            $fakeBlockId++;
51 1
            $newChildBlock->id = $fakeBlockId;
52 1
            if (!empty($childBlock['blocks'])) {
53 1
                $childBlockHydrated = $this->hydrateHandleBlocks($newChildBlock, $childBlock, $fakeBlockId, $newChildBlock->id, $childBlock['blocks'], $mainCollection);
54 1
                $newChildBlock->setRelation('children', $childBlockHydrated->blocks);
0 ignored issues
show
Bug introduced by
The property blocks does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
55
            }
56
57 1
            $mainCollection->push($newChildBlock);
58 1
            $childBlocksCollection->push($newChildBlock);
59
        }
60 2
        return $childBlocksCollection;
61
    }
62
63
    /**
64
     * @param \A17\Twill\Models\Model $object
65
     * @param array $fields
66
     * @return void
67
     */
68 21
    public function afterSaveHandleBlocks($object, $fields)
69
    {
70 21
        if ($this->shouldIgnoreFieldBeforeSave('blocks')) {
71
            return;
72
        }
73
74 21
        $blockRepository = app(BlockRepository::class);
75
76 21
        $blockRepository->bulkDelete($object->blocks()->pluck('id')->toArray());
77
        $this->getBlocks($object, $fields)->each(function ($block) use ($object, $blockRepository) {
0 ignored issues
show
Unused Code introduced by
The import $object is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
78 2
            $this->createBlock($blockRepository, $block);
79 21
        });
80 21
    }
81
82
    /**
83
     * Create a block from formFields, and recursively create it's child blocks
84
     *
85
     * @param  \A17\Twill\Repositories\BlockRepository $blockRepository
86
     * @param  array $blockFields
87
     *
88
     * @return \A17\Twill\Models\Block $blockCreated
89
     */
90 2
    private function createBlock(BlockRepository $blockRepository, $blockFields)
91
    {
92 2
        $blockCreated = $blockRepository->create($blockFields);
93
94
        // Handle child blocks
95
        $blockFields['blocks']->each(function ($childBlock) use ($blockCreated, $blockRepository) {
96
            $childBlock['parent_id'] = $blockCreated->id;
97
            $this->createBlock($blockRepository, $childBlock);
98 2
        });
99
100 2
        return $blockCreated;
101
    }
102
103
    /**
104
     * @param \A17\Twill\Models\Model $object
105
     * @param array $fields
106
     * @return \Illuminate\Support\Collection
107
     */
108 21
    private function getBlocks($object, $fields)
109
    {
110 21
        $blocks = Collection::make();
111 21
        if (isset($fields['blocks']) && is_array($fields['blocks'])) {
112
113 2
            foreach ($fields['blocks'] as $index => $block) {
114 2
                $block = $this->buildBlock($block, $object);
115 2
                $block['position'] = $index + 1;
116 2
                $block['blocks'] = $this->getChildBlocks($object, $block);
117
118 2
                $blocks->push($block);
119
            }
120
        }
121 21
        return $blocks;
122
    }
123
124
    /**
125
     * Recursively generate child blocks from the fields of a block
126
     *
127
     * @param  \A17\Twill\Models\Model $object
128
     * @param  array $parentBlockFields
129
     *
130
     * @return \Illuminate\Support\Collection
131
     */
132 2
    private function getChildBlocks($object, $parentBlockFields)
133
    {
134 2
        $childBlocksList = Collection::make();
135
136 2
        foreach ($parentBlockFields['blocks'] as $childKey => $childBlocks) {
137
            foreach ($childBlocks as $index => $childBlock) {
138
                $childBlock = $this->buildBlock($childBlock, $object, true);
139
                $childBlock['child_key'] = $childKey;
140
                $childBlock['position'] = $index + 1;
141
                $childBlock['blocks'] = $this->getChildBlocks($object, $childBlock);
142
143
                $childBlocksList->push($childBlock);
144
            }
145
        }
146
147 2
        return $childBlocksList;
148
    }
149
150
    /**
151
     * @param array $block
152
     * @param \A17\Twill\Models\Model $object
153
     * @param bool $repeater
154
     * @return array
155
     */
156 2
    private function buildBlock($block, $object, $repeater = false)
157
    {
158 2
        $block['blockable_id'] = $object->id;
159 2
        $block['blockable_type'] = $object->getMorphClass();
160
161 2
        return app(BlockRepository::class)->buildFromCmsArray($block, $repeater);
162
    }
163
164
    /**
165
     * @param \A17\Twill\Models\Model $object
166
     * @param array $fields
167
     * @return array
168
     */
169 5
    public function getFormFieldsHandleBlocks($object, $fields)
170
    {
171 5
        $fields['blocks'] = null;
172
173 5
        if ($object->has('blocks')) {
174
175 5
            $blocksList = app(BlockCollection::class)->list()->keyBy('name');
176
177 5
            foreach ($object->blocks as $block) {
0 ignored issues
show
Bug introduced by
The property blocks does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
178
179 1
                $isInRepeater = isset($block->parent_id);
180 1
                $configKey = $isInRepeater ? 'repeaters' : 'blocks';
0 ignored issues
show
Unused Code introduced by
The assignment to $configKey is dead and can be removed.
Loading history...
181 1
                $blockTypeConfig = $blocksList[$block->type] ?? null;
182
183 1
                if (is_null($blockTypeConfig)) {
184
                    continue;
185
                }
186
187
                $blockItem = [
188 1
                    'id' => $block->id,
189 1
                    'type' => $blockTypeConfig['component'],
190 1
                    'title' => $blockTypeConfig['title'],
191 1
                    'attributes' => $blockTypeConfig['attributes'] ?? [],
192
                ];
193
194 1
                if ($isInRepeater) {
195
                    $fields['blocksRepeaters']["blocks-{$block->parent_id}_{$block->child_key}"][] = $blockItem + [
196
                        'trigger' => $blockTypeConfig['trigger'],
197
                    ] + (isset($blockTypeConfig['max']) ? [
198
                        'max' => $blockTypeConfig['max'],
199
                    ] : []);
200
                } else {
201 1
                    $fields['blocks'][] = $blockItem + [
202 1
                        'icon' => $blockTypeConfig['icon'],
203
                    ];
204
                }
205
206
                $fields['blocksFields'][] = Collection::make($block['content'])->filter(function ($value, $key) {
207 1
                    return $key !== "browsers";
208
                })->map(function ($value, $key) use ($block) {
209
                    return [
210 1
                        'name' => "blocks[$block->id][$key]",
211 1
                        'value' => $value,
212
                    ];
213 1
                })->filter()->values()->toArray();
214
215 1
                $blockFormFields = app(BlockRepository::class)->getFormFields($block);
216
217 1
                $medias = $blockFormFields['medias'];
218
219 1
                if ($medias) {
220
                    if (config('twill.media_library.translated_form_fields', false)) {
221
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($mediasByLocale, $locale) use ($block) {
222
                            return Collection::make($mediasByLocale)->mapWithKeys(function ($value, $key) use ($block, $locale) {
223
                                return [
224
                                    "blocks[$block->id][$key][$locale]" => $value,
225
                                ];
226
                            });
227
                        })->filter()->toArray();
228
                    } else {
229
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($value, $key) use ($block) {
230
                            return [
231
                                "blocks[$block->id][$key]" => $value,
232
                            ];
233
                        })->filter()->toArray();
234
                    }
235
                }
236
237 1
                $files = $blockFormFields['files'];
238
239 1
                if ($files) {
240
                    Collection::make($files)->each(function ($rolesWithFiles, $locale) use (&$fields, $block) {
241
                        $fields['blocksFiles'][] = Collection::make($rolesWithFiles)->mapWithKeys(function ($files, $role) use ($locale, $block) {
242
                            return [
243
                                "blocks[$block->id][$role][$locale]" => $files,
244
                            ];
245
                        })->toArray();
246
                    });
247
                }
248
249 1
                if (isset($block['content']['browsers'])) {
250
                    $fields['blocksBrowsers'][] = $this->getBlockBrowsers($block);
251
                }
252
            }
253
254 5
            if ($fields['blocksFields'] ?? false) {
255 1
                $fields['blocksFields'] = call_user_func_array('array_merge', $fields['blocksFields'] ?? []);
256
            }
257
258 5
            if ($fields['blocksMedias'] ?? false) {
259
                $fields['blocksMedias'] = call_user_func_array('array_merge', $fields['blocksMedias'] ?? []);
260
            }
261
262 5
            if ($fields['blocksFiles'] ?? false) {
263
                $fields['blocksFiles'] = call_user_func_array('array_merge', $fields['blocksFiles'] ?? []);
264
            }
265
266 5
            if ($fields['blocksBrowsers'] ?? false) {
267
                $fields['blocksBrowsers'] = call_user_func_array('array_merge', $fields['blocksBrowsers'] ?? []);
268
            }
269
        }
270
271 5
        return $fields;
272
    }
273
274
    /**
275
     * @param \A17\Twill\Models\Block $block
276
     * @return array
277
     */
278
    protected function getBlockBrowsers($block)
279
    {
280
        return Collection::make($block['content']['browsers'])->mapWithKeys(function ($ids, $relation) use ($block) {
281
            if (Schema::hasTable(config('twill.related_table', 'twill_related')) && $block->getRelated($relation)->isNotEmpty()) {
282
                $items = $this->getFormFieldsForRelatedBrowser($block, $relation);;
0 ignored issues
show
Bug introduced by
It seems like getFormFieldsForRelatedBrowser() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

282
                /** @scrutinizer ignore-call */ 
283
                $items = $this->getFormFieldsForRelatedBrowser($block, $relation);;
Loading history...
283
            } else {
284
                $relationRepository = $this->getModelRepository($relation);
0 ignored issues
show
Bug introduced by
It seems like getModelRepository() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

284
                /** @scrutinizer ignore-call */ 
285
                $relationRepository = $this->getModelRepository($relation);
Loading history...
285
                $relatedItems = $relationRepository->get([], ['id' => $ids], [], -1);
286
                $sortedRelatedItems = array_flip($ids);
287
288
                foreach ($relatedItems as $item) {
289
                    $sortedRelatedItems[$item->id] = $item;
290
                }
291
292
                $items = Collection::make(array_values($sortedRelatedItems))->filter(function ($value) {
293
                    return is_object($value);
294
                })->map(function ($relatedElement) use ($relation) {
295
                    return [
296
                        'id' => $relatedElement->id,
297
                        'name' => $relatedElement->titleInBrowser ?? $relatedElement->title,
298
                        'edit' => moduleRoute($relation, config('twill.block_editor.browser_route_prefixes.' . $relation), 'edit', $relatedElement->id),
299
                    ] + (classHasTrait($relatedElement, HasMedias::class) ? [
300
                        'thumbnail' => $relatedElement->defaultCmsImage(['w' => 100, 'h' => 100]),
301
                    ] : []);
302
                })->toArray();
303
            }
304
            return [
305
                "blocks[$block->id][$relation]" => $items,
306
            ];
307
        })->filter()->toArray();
308
    }
309
}
310