Passed
Pull Request — 1.2 (#521)
by
unknown
05:26
created

HandleBlocks   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 295
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 137
c 4
b 0
f 0
dl 0
loc 295
rs 9.6
wmc 35

8 Methods

Rating   Name   Duplication   Size   Complexity  
A hydrateHandleBlocks() 0 40 4
A afterSaveHandleBlocks() 0 11 2
A buildBlock() 0 6 1
A getChildBlocks() 0 16 3
A getBlockBrowsers() 0 30 5
C getFormFieldsHandleBlocks() 0 103 15
A getBlocks() 0 15 4
A createBlock() 0 11 1
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 Illuminate\Support\Collection;
8
use Schema;
9
10
trait HandleBlocks
11
{
12
    /**
13
     * @param \A17\Twill\Models\Model $object
14
     * @param array $fields
15
     * @return \A17\Twill\Models\Model|void
16
     */
17
    public function hydrateHandleBlocks($object, $fields)
18
    {
19
        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

19
        if ($this->/** @scrutinizer ignore-call */ shouldIgnoreFieldBeforeSave('blocks')) {
Loading history...
20
            return;
21
        }
22
23
        $blocksCollection = Collection::make();
24
        $blocksFromFields = $this->getBlocks($object, $fields);
25
        $blockRepository = app(BlockRepository::class);
26
27
        $fakeBlockId = 1;
28
29
        foreach ($blocksFromFields as $block) {
30
            $newBlock = $blockRepository->createForPreview($block);
31
32
            $newBlock->id = $fakeBlockId;
33
            $fakeBlockId++;
34
35
            $childBlocksCollection = Collection::make();
36
37
            foreach ($block['blocks'] as $childBlock) {
38
                $childBlock['parent_id'] = $newBlock->id;
39
40
                $newChildBlock = $blockRepository->createForPreview($childBlock);
41
42
                $newChildBlock->id = $fakeBlockId;
43
                $fakeBlockId++;
44
45
                $blocksCollection->push($newChildBlock);
46
                $childBlocksCollection->push($newChildBlock);
47
            }
48
49
            $newBlock->setRelation('children', $childBlocksCollection);
50
51
            $blocksCollection->push($newBlock);
52
        }
53
54
        $object->setRelation('blocks', $blocksCollection);
55
56
        return $object;
57
    }
58
59
    /**
60
     * @param \A17\Twill\Models\Model $object
61
     * @param array $fields
62
     * @return void
63
     */
64
    public function afterSaveHandleBlocks($object, $fields)
65
    {
66
        if ($this->shouldIgnoreFieldBeforeSave('blocks')) {
67
            return;
68
        }
69
70
        $blockRepository = app(BlockRepository::class);
71
72
        $blockRepository->bulkDelete($object->blocks()->pluck('id')->toArray());
73
        $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...
74
            $this->createBlock($blockRepository, $block);
75
        });
76
    }
77
78
    /**
79
     * Create a block from formFields, and recursively create it's child blocks
80
     *
81
     * @param  \A17\Twill\Repositories\BlockRepository $blockRepository
82
     * @param  array $blockFields
83
     *
84
     * @return \A17\Twill\Models\Block $blockCreated
85
     */
86
    private function createBlock(BlockRepository $blockRepository, $blockFields)
87
    {
88
        $blockCreated = $blockRepository->create($blockFields);
89
90
        // Handle child blocks
91
        $blockFields['blocks']->each(function ($childBlock) use ($blockCreated, $blockRepository) {
92
            $childBlock['parent_id'] = $blockCreated->id;
93
            $this->createBlock($blockRepository, $childBlock);
94
        });
95
96
        return $blockCreated;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $blockCreated returns the type A17\Twill\Models\Model which is incompatible with the documented return type A17\Twill\Models\Block.
Loading history...
97
    }
98
99
    /**
100
     * @param \A17\Twill\Models\Model $object
101
     * @param array $fields
102
     * @return \Illuminate\Support\Collection
103
     */
104
    private function getBlocks($object, $fields)
105
    {
106
        $blocks = Collection::make();
107
        if (isset($fields['blocks']) && is_array($fields['blocks'])) {
108
109
            foreach ($fields['blocks'] as $index => $block) {
110
                $block = $this->buildBlock($block, $object);
111
                $block['position'] = $index + 1;
112
                $block['blocks'] = $this->getChildBlocks($object, $block);
113
114
                $blocks->push($block);
115
            }
116
        }
117
118
        return $blocks;
119
    }
120
121
    /**
122
     * Recursively generate child blocks from the fields of a block
123
     *
124
     * @param  \A17\Twill\Models\Model $object
125
     * @param  array $parentBlockFields
126
     *
127
     * @return \Illuminate\Support\Collection
128
     */
129
    private function getChildBlocks($object, $parentBlockFields)
130
    {
131
        $childBlocksList = Collection::make();
132
133
        foreach ($parentBlockFields['blocks'] as $childKey => $childBlocks) {
134
            foreach ($childBlocks as $index => $childBlock) {
135
                $childBlock = $this->buildBlock($childBlock, $object, true);
136
                $childBlock['child_key'] = $childKey;
137
                $childBlock['position'] = $index + 1;
138
                $childBlock['blocks'] = $this->getChildBlocks($object, $childBlock);
139
140
                $childBlocksList->push($childBlock);
141
            }
142
        }
143
144
        return $childBlocksList;
145
    }
146
147
    /**
148
     * @param array $block
149
     * @param \A17\Twill\Models\Model $object
150
     * @param bool $repeater
151
     * @return array
152
     */
153
    private function buildBlock($block, $object, $repeater = false)
154
    {
155
        $block['blockable_id'] = $object->id;
156
        $block['blockable_type'] = $object->getMorphClass();
157
158
        return app(BlockRepository::class)->buildFromCmsArray($block, $repeater);
159
    }
160
161
    /**
162
     * @param \A17\Twill\Models\Model $object
163
     * @param array $fields
164
     * @return array
165
     */
166
    public function getFormFieldsHandleBlocks($object, $fields)
167
    {
168
        $fields['blocks'] = null;
169
170
        if ($object->has('blocks')) {
171
172
            $blocksConfig = config('twill.block_editor');
173
174
            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...
175
176
                $isInRepeater = isset($block->parent_id);
177
                $configKey = $isInRepeater ? 'repeaters' : 'blocks';
178
                $blockTypeConfig = $blocksConfig[$configKey][$block->type] ?? null;
179
180
                if (is_null($blockTypeConfig)) {
181
                    continue;
182
                }
183
184
                $blockItem = [
185
                    'id' => $block->id,
186
                    'type' => $blockTypeConfig['component'],
187
                    'title' => $blockTypeConfig['title'],
188
                    'attributes' => $blockTypeConfig['attributes'] ?? [],
189
                ];
190
191
                if ($isInRepeater) {
192
                    $fields['blocksRepeaters']["blocks-{$block->parent_id}_{$block->child_key}"][] = $blockItem + [
193
                        'trigger' => $blockTypeConfig['trigger'],
194
                    ] + (isset($blockTypeConfig['max']) ? [
195
                        'max' => $blockTypeConfig['max'],
196
                    ] : []);
197
                } else {
198
                    $fields['blocks'][] = $blockItem + [
199
                        'icon' => $blockTypeConfig['icon'],
200
                    ];
201
                }
202
203
                $fields['blocksFields'][] = Collection::make($block['content'])->filter(function ($value, $key) {
204
                    return $key !== "browsers";
205
                })->map(function ($value, $key) use ($block) {
206
                    return [
207
                        'name' => "blocks[$block->id][$key]",
208
                        'value' => $value,
209
                    ];
210
                })->filter()->values()->toArray();
211
212
                $blockFormFields = app(BlockRepository::class)->getFormFields($block);
213
214
                $medias = $blockFormFields['medias'];
215
216
                if ($medias) {
217
                    if (config('twill.media_library.translated_form_fields', false)) {
218
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($mediasByLocale, $locale) use ($block) {
219
                            return Collection::make($mediasByLocale)->mapWithKeys(function ($value, $key) use ($block, $locale) {
220
                                return [
221
                                    "blocks[$block->id][$key][$locale]" => $value,
222
                                ];
223
                            });
224
                        })->filter()->toArray();
225
                    } else {
226
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($value, $key) use ($block) {
227
                            return [
228
                                "blocks[$block->id][$key]" => $value,
229
                            ];
230
                        })->filter()->toArray();
231
                    }
232
                }
233
234
                $files = $blockFormFields['files'];
235
236
                if ($files) {
237
                    Collection::make($files)->each(function ($rolesWithFiles, $locale) use (&$fields, $block) {
238
                        $fields['blocksFiles'][] = Collection::make($rolesWithFiles)->mapWithKeys(function ($files, $role) use ($locale, $block) {
239
                            return [
240
                                "blocks[$block->id][$role][$locale]" => $files,
241
                            ];
242
                        })->toArray();
243
                    });
244
                }
245
246
                if (isset($block['content']['browsers'])) {
247
                    $fields['blocksBrowsers'][] = $this->getBlockBrowsers($block);
248
                }
249
            }
250
251
            if ($fields['blocksFields'] ?? false) {
252
                $fields['blocksFields'] = call_user_func_array('array_merge', $fields['blocksFields'] ?? []);
253
            }
254
255
            if ($fields['blocksMedias'] ?? false) {
256
                $fields['blocksMedias'] = call_user_func_array('array_merge', $fields['blocksMedias'] ?? []);
257
            }
258
259
            if ($fields['blocksFiles'] ?? false) {
260
                $fields['blocksFiles'] = call_user_func_array('array_merge', $fields['blocksFiles'] ?? []);
261
            }
262
263
            if ($fields['blocksBrowsers'] ?? false) {
264
                $fields['blocksBrowsers'] = call_user_func_array('array_merge', $fields['blocksBrowsers'] ?? []);
265
            }
266
        }
267
268
        return $fields;
269
    }
270
271
    /**
272
     * @param \A17\Twill\Models\Block $block
273
     * @return array
274
     */
275
    protected function getBlockBrowsers($block)
276
    {
277
        return Collection::make($block['content']['browsers'])->mapWithKeys(function ($ids, $relation) use ($block) {
278
            if (Schema::hasTable(config('twill.related_table', 'related')) && $block->getRelated($relation)->isNotEmpty()) {
279
                $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

279
                /** @scrutinizer ignore-call */ 
280
                $items = $this->getFormFieldsForRelatedBrowser($block, $relation);;
Loading history...
280
            } else {
281
                $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

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