1 | <?php |
||||
2 | |||||
3 | namespace NovaFlexibleContent\Layouts; |
||||
4 | |||||
5 | use Illuminate\Database\Eloquent\Concerns\HidesAttributes; |
||||
6 | use Illuminate\Support\Collection; |
||||
7 | use Laravel\Nova\Fields\Field; |
||||
8 | use Laravel\Nova\Fields\FieldCollection; |
||||
9 | use Laravel\Nova\Support\Fluent; |
||||
10 | use NovaFlexibleContent\Concerns\HasFlexible; |
||||
11 | use NovaFlexibleContent\Http\ScopedRequest; |
||||
12 | use NovaFlexibleContent\Layouts\LayoutTraits\Collapsable; |
||||
13 | use NovaFlexibleContent\Layouts\LayoutTraits\HasFieldsCollection; |
||||
14 | use NovaFlexibleContent\Layouts\LayoutTraits\HasFieldsRules; |
||||
15 | use NovaFlexibleContent\Layouts\LayoutTraits\HasFlexibleFieldInLayout; |
||||
16 | use NovaFlexibleContent\Layouts\LayoutTraits\HasGroupDescription; |
||||
17 | use NovaFlexibleContent\Layouts\LayoutTraits\HasLayoutKey; |
||||
18 | use NovaFlexibleContent\Layouts\LayoutTraits\HasLimitPerLayout; |
||||
19 | use NovaFlexibleContent\Layouts\LayoutTraits\HasModel; |
||||
20 | use NovaFlexibleContent\Layouts\LayoutTraits\HasNameAndTitle; |
||||
21 | use NovaFlexibleContent\Layouts\LayoutTraits\HasRemoveCallback; |
||||
22 | use NovaFlexibleContent\Layouts\LayoutTraits\ModelEmulates; |
||||
23 | |||||
24 | /** |
||||
25 | * @extends Fluent<string, mixed> |
||||
26 | */ |
||||
27 | class Layout extends Fluent |
||||
28 | { |
||||
29 | use HidesAttributes; |
||||
30 | use HasFlexible; |
||||
31 | use Collapsable; |
||||
32 | use ModelEmulates; |
||||
0 ignored issues
–
show
introduced
by
![]() |
|||||
33 | use HasNameAndTitle; |
||||
34 | use HasLayoutKey; |
||||
35 | use HasFieldsCollection; |
||||
36 | use HasGroupDescription; |
||||
37 | use HasLimitPerLayout; |
||||
38 | use HasRemoveCallback; |
||||
0 ignored issues
–
show
|
|||||
39 | use HasFlexibleFieldInLayout; |
||||
40 | use HasFieldsRules; |
||||
0 ignored issues
–
show
|
|||||
41 | use HasModel; |
||||
0 ignored issues
–
show
The trait
NovaFlexibleContent\Layouts\LayoutTraits\HasModel has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This trait has been deprecated. The supplier of the trait has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the trait will be removed and what other trait to use instead. ![]() |
|||||
42 | |||||
43 | 37 | public function __construct( |
|||
44 | ?string $title = null, |
||||
45 | ?string $name = null, |
||||
46 | Collection|array|null $fields = null, |
||||
47 | ?string $key = null, |
||||
48 | array $attributes = [], |
||||
49 | ?\Closure $removeCallbackMethod = null |
||||
50 | ) { |
||||
51 | // Override properties or set default provided by developer |
||||
52 | 37 | $this->title = $title ?? $this->title; |
|||
53 | 37 | $this->name = $name ?? $this->name; |
|||
54 | 37 | $this->fields = FieldCollection::make($fields); |
|||
0 ignored issues
–
show
It seems like
$fields can also be of type array ; however, parameter $items of Illuminate\Support\Collection::make() does only seem to accept Illuminate\Contracts\Support\Arrayable , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
55 | 37 | $this->removeCallbackMethod = $removeCallbackMethod; |
|||
56 | |||||
57 | 37 | $this->key = is_null($key) ? null : $this->generateValidLayoutKey($key); |
|||
58 | 37 | $this->setRawAttributes($this->setEmptyValuesToNull($attributes)); |
|||
59 | } |
||||
60 | |||||
61 | /** |
||||
62 | * Resolve and return the result |
||||
63 | * |
||||
64 | * @return array |
||||
65 | */ |
||||
66 | 4 | public function getResolved(): array |
|||
67 | { |
||||
68 | 4 | $this->resolve(); |
|||
69 | |||||
70 | 4 | return $this->getResolvedValue(); |
|||
71 | } |
||||
72 | |||||
73 | /** |
||||
74 | * Resolve the field for display and return the result. |
||||
75 | * |
||||
76 | * @return array |
||||
77 | */ |
||||
78 | 4 | public function getResolvedForDisplay() |
|||
79 | { |
||||
80 | 4 | return $this->resolveForDisplay($this->getAttributes()); |
|||
81 | } |
||||
82 | |||||
83 | /** |
||||
84 | * @inerhitDoc |
||||
85 | */ |
||||
86 | 12 | public function duplicate(?string $key, array $attributes = []): static |
|||
87 | { |
||||
88 | 12 | $fields = $this->fieldsCollection()->map(function ($field) { |
|||
89 | 12 | return $this->cloneField($field); |
|||
90 | 12 | }); |
|||
91 | |||||
92 | 12 | $clone = new static( |
|||
93 | 12 | $this->title(), |
|||
94 | 12 | $this->name(), |
|||
95 | 12 | $fields, |
|||
96 | 12 | $key, |
|||
97 | 12 | $attributes, |
|||
98 | 12 | $this->removeCallbackMethod, |
|||
99 | 12 | ); |
|||
100 | 12 | $clone->useLimit($this->limit()); |
|||
101 | 12 | $clone->setModel($this->model); |
|||
0 ignored issues
–
show
The function
NovaFlexibleContent\Layouts\Layout::setModel() has been deprecated: I have no Idea where this used, and why we should keep it?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
102 | |||||
103 | 12 | return $clone; |
|||
104 | } |
||||
105 | |||||
106 | /** |
||||
107 | * Create a working field clone instance |
||||
108 | * |
||||
109 | * @param \Laravel\Nova\Fields\Field $original |
||||
110 | * @return \Laravel\Nova\Fields\Field |
||||
111 | */ |
||||
112 | 12 | protected function cloneField(Field $original) |
|||
113 | { |
||||
114 | 12 | $field = clone $original; |
|||
115 | |||||
116 | 12 | $callables = ['displayCallback', 'resolveCallback', 'fillCallback', 'requiredCallback']; |
|||
117 | |||||
118 | 12 | foreach ($callables as $callable) { |
|||
119 | 12 | if (!is_a($field->$callable ?? null, \Closure::class)) { |
|||
120 | 12 | continue; |
|||
121 | } |
||||
122 | 4 | $field->$callable = $field->$callable->bindTo($field); |
|||
123 | } |
||||
124 | |||||
125 | 12 | return $field; |
|||
126 | } |
||||
127 | |||||
128 | /** |
||||
129 | * Resolve fields using given attributes. |
||||
130 | * |
||||
131 | * @param bool $empty |
||||
132 | * @return static |
||||
133 | */ |
||||
134 | 6 | public function resolve(bool $empty = false): static |
|||
135 | { |
||||
136 | 6 | $this->fieldsCollection()->each(function ($field) use ($empty) { |
|||
137 | 4 | $field->resolve($empty ? $this->duplicate($this->inUseKey()) : $this); |
|||
138 | 6 | }); |
|||
139 | |||||
140 | 6 | return $this; |
|||
141 | } |
||||
142 | |||||
143 | /** |
||||
144 | * Resolve fields for display using given attributes. |
||||
145 | */ |
||||
146 | 4 | public function resolveForDisplay(array $attributes = []): array |
|||
147 | { |
||||
148 | 4 | $this->fieldsCollection()->each(function ($field) use ($attributes) { |
|||
149 | 4 | $field->resolveForDisplay($attributes); |
|||
150 | 4 | }); |
|||
151 | |||||
152 | 4 | return $this->getResolvedValue(); |
|||
153 | } |
||||
154 | |||||
155 | /** |
||||
156 | * Get the layout's resolved representation. Best used |
||||
157 | * after a resolve() call |
||||
158 | */ |
||||
159 | 7 | public function getResolvedValue(): array |
|||
160 | { |
||||
161 | 7 | return [ |
|||
162 | 7 | 'layout' => $this->name(), |
|||
163 | |||||
164 | 7 | 'collapsed' => $this->isCollapsed(), |
|||
165 | |||||
166 | // The (old) temporary key is preferred to the new one during |
||||
167 | // field resolving because we need to keep track of the current |
||||
168 | // attributes during the next fill request that will override |
||||
169 | // the key with a new, stronger & definitive one. |
||||
170 | 7 | 'key' => $this->inUseKey(), |
|||
171 | |||||
172 | // The layout's fields now temporarily contain the resolved |
||||
173 | // values from the current group's attributes. If multiple |
||||
174 | // groups use the same layout, the current values will be lost |
||||
175 | // since each group uses the same fields by reference. That's |
||||
176 | // why we need to serialize the field's current state. |
||||
177 | 7 | 'attributes' => $this->fieldsCollection()->jsonSerialize(), |
|||
178 | 7 | ]; |
|||
179 | } |
||||
180 | |||||
181 | /** |
||||
182 | * Fill attributes using underlaying fields and incoming request. |
||||
183 | */ |
||||
184 | 4 | public function fillFromRequest(ScopedRequest $request): array |
|||
185 | { |
||||
186 | 4 | return $this->fieldsCollection()->map(fn (Field $field) => $field->fill($request, $this)) |
|||
187 | 4 | ->filter(fn ($callback) => is_callable($callback)) |
|||
188 | 4 | ->values() |
|||
189 | 4 | ->all(); |
|||
190 | } |
||||
191 | |||||
192 | /** |
||||
193 | * Transform empty attribute values to null. |
||||
194 | */ |
||||
195 | 37 | protected function setEmptyValuesToNull(array $dataArray = []): array |
|||
196 | { |
||||
197 | 37 | foreach ($dataArray as $key => $value) { |
|||
198 | 10 | if (!is_string($value) || strlen($value) > 0) { |
|||
199 | 10 | continue; |
|||
200 | } |
||||
201 | 2 | $dataArray[$key] = null; |
|||
202 | } |
||||
203 | |||||
204 | 37 | return $dataArray; |
|||
205 | } |
||||
206 | |||||
207 | /** |
||||
208 | * Transform layout for serialization. |
||||
209 | * |
||||
210 | * @return array |
||||
211 | */ |
||||
212 | 2 | public function jsonSerialize(): array |
|||
213 | { |
||||
214 | // Calling an empty "resolve" first in order to empty all fields |
||||
215 | 2 | $this->resolve(true); |
|||
216 | |||||
217 | 2 | return [ |
|||
218 | 2 | 'name' => $this->name(), |
|||
219 | 2 | 'title' => $this->title(), |
|||
220 | 2 | 'fields' => $this->fieldsCollection()->jsonSerialize(), |
|||
221 | 2 | 'limit' => $this->limit(), |
|||
222 | 2 | 'configs' => [ |
|||
223 | 2 | 'fieldUsedForDescription' => $this->fieldUsedForDescription(), |
|||
224 | 2 | ], |
|||
225 | 2 | ]; |
|||
226 | } |
||||
227 | } |
||||
228 |