Skip to content

Commit fe5ba31

Browse files
authored
Merge pull request whitecube#291 from marshmallow-packages/289-depended-layout
Use depended fields
2 parents 9434d04 + 6af748a commit fe5ba31

File tree

3 files changed

+214
-1
lines changed

3 files changed

+214
-1
lines changed

src/Concerns/HasFlexible.php

+151-1
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,42 @@
22

33
namespace Marshmallow\Nova\Flexible\Concerns;
44

5+
use Illuminate\Support\Facades\Cache;
56
use Laravel\Nova\NovaServiceProvider;
7+
use Illuminate\Database\Eloquent\Model;
68
use Marshmallow\Nova\Flexible\Facades\Flex;
79
use Marshmallow\Nova\Flexible\Layouts\Layout;
810
use Marshmallow\Nova\Flexible\Layouts\Collection;
911
use Marshmallow\Nova\Flexible\Value\FlexibleCast;
12+
use Illuminate\Contracts\Database\Eloquent\Builder;
1013
use Illuminate\Support\Collection as BaseCollection;
14+
use Marshmallow\Nova\Flexible\Layouts\DependedLayout;
1115

1216
trait HasFlexible
1317
{
18+
protected static function bootHasFlexible()
19+
{
20+
static::created(function (Model $model) {
21+
$model->clearCachedFlexibleData();
22+
});
23+
24+
static::updated(function (Model $model) {
25+
$model->clearCachedFlexibleData();
26+
});
27+
28+
static::deleted(function (Model $model) {
29+
$model->clearCachedFlexibleData();
30+
});
31+
}
32+
33+
public function clearCachedFlexibleData()
34+
{
35+
$cache_tag = self::getCacheTagForDependedLayoutSelect();
36+
if ($cache_tag) {
37+
Cache::tags($cache_tag)->flush();
38+
}
39+
}
40+
1441
/**
1542
* Parse a Flexible Content attribute
1643
*
@@ -69,9 +96,26 @@ public function toFlexible($value, $layoutMapping = [], $with = [])
6996
return new Collection();
7097
}
7198

72-
return new Collection(
99+
$flexible_layouts = new Collection(
73100
array_filter($this->getMappedFlexibleLayouts($flexible, $layoutMapping, $with))
74101
);
102+
103+
/** Add the cloned / mirrowed depended layouts */
104+
$flexible_layouts->each(function ($layout, $layout_array_key) use (&$flexible_layouts) {
105+
if ($layout instanceof DependedLayout) {
106+
[$page_id, $column, $layout_key] = explode('___', $layout->layout);
107+
$model_class = get_class($this);
108+
$depended_page = $model_class::find($page_id);
109+
$depended_page_layouts = $depended_page->flex($column);
110+
$depended_page_layouts->each(function ($layout) use ($layout_key, $layout_array_key, &$flexible_layouts) {
111+
if ($layout->key == $layout_key) {
112+
$flexible_layouts[$layout_array_key] = $layout;
113+
}
114+
});
115+
}
116+
});
117+
118+
return $flexible_layouts;
75119
}
76120

77121
/**
@@ -194,4 +238,110 @@ protected function createMappedLayout($name, $key, $attributes, array $layoutMap
194238
$layout->setRawAttributes($attributes);
195239
return $layout;
196240
}
241+
242+
public static function getOptionsQueryBuilderForDependedLayoutSelect(): Builder
243+
{
244+
return self::query();
245+
}
246+
247+
public static function getCacheTagForDependedLayoutSelect(): ?string
248+
{
249+
return 'depended-select-options';
250+
}
251+
252+
public static function getCacheTtlForDependedLayoutSelect(): int
253+
{
254+
return 60 * 60 * 24;
255+
}
256+
257+
public static function getCacheKeyForDependedLayoutSelect(): string
258+
{
259+
return 'options-for-depended-layout-select';
260+
}
261+
262+
public static function getDependedLayoutSelectColumns(): array
263+
{
264+
return [
265+
'layout',
266+
];
267+
}
268+
269+
public function getDependedLayoutGroup(): string
270+
{
271+
if ($this->name) {
272+
return $this->name;
273+
}
274+
$unknown_name = (new \ReflectionClass($this))->getShortName();
275+
return "{$unknown_name}: #{$this->id}";
276+
}
277+
278+
public static function getDependedLayoutLabel($layout): string
279+
{
280+
if (isset($layout->attributes->title)) {
281+
return $layout->attributes->title;
282+
}
283+
284+
if (isset($layout->attributes->name)) {
285+
return $layout->attributes->name;
286+
}
287+
288+
if (isset($layout->attributes->title)) {
289+
return $layout->attributes->title;
290+
}
291+
292+
return __('Unknown');
293+
}
294+
295+
public static function getLayoutsToIgnoreFromDependendLayout(): array
296+
{
297+
return [
298+
//
299+
];
300+
}
301+
302+
public static function getOptionsForDependedLayoutSelect(): array
303+
{
304+
$callable = function () {
305+
$options = [];
306+
$columns = self::getDependedLayoutSelectColumns();
307+
$ignore_layouts = array_merge(self::getLayoutsToIgnoreFromDependendLayout(), [
308+
'depended-layout'
309+
]);
310+
311+
self::getOptionsQueryBuilderForDependedLayoutSelect()
312+
->get()
313+
->each(function ($model) use (&$options, $columns, $ignore_layouts) {
314+
foreach ($columns as $column) {
315+
$layouts = json_decode($model->{$column});
316+
foreach ($layouts as $key => $layout) {
317+
try {
318+
if (in_array($layout->layout, $ignore_layouts)) {
319+
continue;
320+
}
321+
322+
$key = "{$model->id}___{$column}___{$layout->key}";
323+
324+
$label = self::getDependedLayoutLabel($layout);
325+
$group = $model->getDependedLayoutGroup($layout);
326+
$options[$key] = ['label' => $label, 'group' => $group];
327+
} catch (ErrorException $e) {
328+
//
329+
}
330+
}
331+
}
332+
});
333+
334+
return $options;
335+
};
336+
337+
$cache_tag = self::getCacheTagForDependedLayoutSelect();
338+
$cache_ttl = self::getCacheTtlForDependedLayoutSelect();
339+
$cache_key = self::getCacheKeyForDependedLayoutSelect();
340+
341+
if ($cache_tag) {
342+
return Cache::tags($cache_tag)->remember($cache_key, $cache_ttl, $callable);
343+
}
344+
345+
return $callable();
346+
}
197347
}

src/Flex.php

+2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
use Illuminate\Support\Facades\Cache;
1212
use Marshmallow\Nova\Flexible\Layouts\MarshmallowLayout;
1313
use Marshmallow\Nova\Flexible\Layouts\Defaults\WysiwygLayout;
14+
use Marshmallow\Nova\Flexible\Layouts\DependedLayout;
1415

1516
class Flex
1617
{
1718
protected $loaded_layouts;
1819

1920
protected $default_layouts = [
2021
'wysiwyg' => WysiwygLayout::class,
22+
'depended-layout' => DependedLayout::class,
2123
];
2224

2325
public function getLayouts()

src/Layouts/DependedLayout.php

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace Marshmallow\Nova\Flexible\Layouts;
4+
5+
use Laravel\Nova\Fields\Select;
6+
use Laravel\Nova\Http\Requests\NovaRequest;
7+
8+
class DependedLayout extends MarshmallowLayout
9+
{
10+
/**
11+
* The layout's unique identifier
12+
*
13+
* @var string
14+
*/
15+
protected $name = 'depended-layout';
16+
17+
/**
18+
* The displayed title
19+
*
20+
* @var string
21+
*/
22+
protected $title = 'Mirror another layout';
23+
24+
/**
25+
* Description as shown in the layout selector.
26+
*
27+
* @var string
28+
*/
29+
protected $description = 'Copy any layout from another resource and mirror it here.';
30+
31+
/**
32+
* Image use in the layout selector
33+
*
34+
* @var string
35+
*/
36+
protected $image = 'https://marshmallow.dev/cdn/flex/layout/dividers.png';
37+
38+
/**
39+
* Add this layout to these tags.
40+
*
41+
* @var array
42+
*/
43+
protected $tags = ["Specials"];
44+
45+
/**
46+
* Get the fields displayed by the layout.
47+
*
48+
* @return array
49+
*/
50+
public function fields()
51+
{
52+
$resource_model = NovaRequest::createFrom(request())
53+
->model();
54+
55+
return [
56+
Select::make(__('Depended Layout'), 'layout')->options(
57+
$resource_model::getOptionsForDependedLayoutSelect(),
58+
)->displayUsingLabels()->searchable(),
59+
];
60+
}
61+
}

0 commit comments

Comments
 (0)