Skip to content

Commit a6c74d2

Browse files
committed
fix incompatibility with BelongsToField
1 parent 260a6e6 commit a6c74d2

File tree

4 files changed

+132
-61
lines changed

4 files changed

+132
-61
lines changed

dist/js/field.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/components/FormField.vue

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,18 +176,18 @@
176176
/**
177177
* Initialize bag with initial value
178178
*/
179-
this.setBagValue(attribute, component[watchableAttribute])
179+
this.setBagValue(component, attribute, component[watchableAttribute])
180180
181181
component.$once('hook:beforeDestroy', () => this.deleteBagAttribute(attribute))
182-
component.$watch(watchableAttribute, value => this.setBagValue(attribute, this.parseComponentValue(component, value)))
182+
component.$watch(watchableAttribute, value => this.setBagValue(component, attribute, value))
183183
184184
}
185185
186186
},
187187
188-
setBagValue(attribute, value) {
188+
setBagValue(component, attribute, value) {
189189
190-
valueBag[attribute] = value
190+
valueBag[attribute] = this.parseComponentValue(component, value)
191191
192192
this.$root.$emit('update-conditional-container')
193193
@@ -286,12 +286,11 @@
286286
287287
switch (component.field.component) {
288288
289-
/**
290-
* For some unknown reason this component stringify the value
291-
* https://github.com/dillingham/nova-attach-many/blob/2d461048d3e85de54795f6c03ae0bdad3356df6b/resources/js/components/FormField.vue#L210
292-
*/
293289
case 'nova-attach-many':
294-
return JSON.parse(value)
290+
return JSON.parse(value || '[]')
291+
292+
case 'BelongsToManyField':
293+
return (value || []).map(({id}) => id)
295294
296295
}
297296

src/ConditionalContainer.php

Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
namespace DigitalCreative\ConditionalContainer;
44

5-
use Laravel\Nova\Resource;
65
use Illuminate\Database\Eloquent\Model;
76
use Illuminate\Support\Collection;
87
use Illuminate\Support\Str;
98
use Laravel\Nova\Fields\Field;
109
use Laravel\Nova\Http\Controllers\ResourceUpdateController;
1110
use Laravel\Nova\Http\Controllers\UpdateFieldController;
1211
use Laravel\Nova\Http\Requests\NovaRequest;
12+
use Laravel\Nova\Resource;
1313
use logipar\Logipar;
1414

1515
class ConditionalContainer extends Field
@@ -34,7 +34,14 @@ class ConditionalContainer extends Field
3434
/**
3535
* @var Collection
3636
*/
37-
private $operators;
37+
const OPERATORS = [
38+
'===', '==', '=',
39+
'!==', '!=',
40+
'>=', '<=', '<', '>',
41+
'includes', 'contains',
42+
'ends with', 'starts with', 'startsWith', 'endsWith',
43+
'boolean', 'truthy'
44+
];
3845

3946
/**
4047
* ConditionalContainer constructor.
@@ -48,14 +55,6 @@ public function __construct(array $fields)
4855

4956
$this->fields = collect($fields);
5057
$this->expressions = collect();
51-
$this->operators = collect([
52-
'===', '==', '=',
53-
'!==', '!=',
54-
'>=', '<=', '<', '>',
55-
'includes', 'contains',
56-
'ends with', 'starts with', 'startsWith', 'endsWith',
57-
'boolean', 'truthy'
58-
]);
5958

6059
$this->withMeta([ 'operation' => 'some' ]);
6160

@@ -163,35 +162,14 @@ private function executeCondition($attributeValue, string $operator, $conditionV
163162

164163
$conditionValue = trim($conditionValue, '"\'');
165164

166-
if (in_array($operator, [ '<', '>', '<=', '>=' ]) && $conditionValue) {
165+
if (in_array($operator, [ '<', '>', '<=', '>=' ]) && $conditionValue ||
166+
(is_numeric($attributeValue) && is_numeric($conditionValue))) {
167167

168168
$conditionValue = (int) $conditionValue;
169169
$attributeValue = (int) $attributeValue;
170170

171171
}
172172

173-
/**
174-
* This is due that sometimes this function is call with data that comes
175-
* directly from the request, therefore there may be occasion that the "model" casts
176-
* may not be applied, if it doesnt cause any unforeseen issue it`s safe to keep this in here
177-
*/
178-
if (is_string($attributeValue)) {
179-
180-
$attributeValue = json_decode($attributeValue, true) ?? $attributeValue;
181-
182-
}
183-
184-
/**
185-
* If $attributeValue is an array and $operator contains/includes
186-
* assumes user is trying to match id of a belongsToMany relationship
187-
*/
188-
if (is_array($attributeValue) && in_array($operator, [ 'contains', 'includes' ])) {
189-
190-
$attributeValue = collect($attributeValue);
191-
$conditionValue = (int) $conditionValue;
192-
193-
}
194-
195173
if (in_array($conditionValue, [ 'true', 'false' ])) {
196174

197175
$conditionValue = $conditionValue === 'true';
@@ -247,10 +225,10 @@ private function executeCondition($attributeValue, string $operator, $conditionV
247225

248226
}
249227

250-
private function splitLiteral(string $literal): array
228+
public static function splitLiteral(string $literal): array
251229
{
252230

253-
$operator = $this->operators
231+
$operator = collect(self::OPERATORS)
254232
->filter(function ($operator) use ($literal) {
255233
return strpos($literal, $operator) !== false;
256234
})
@@ -341,6 +319,7 @@ public function resolveDependencyFieldUsingResource($resource): array
341319

342320
/**
343321
* @param Model|Resource $resource
322+
*
344323
* @return Collection
345324
*/
346325
private function flattenRelationships($resource): Collection

src/HasConditionalContainer.php

Lines changed: 109 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
use Illuminate\Http\Resources\MergeValue;
66
use Illuminate\Support\Collection;
7+
use Laravel\Nova\Contracts\RelatableField;
8+
use Laravel\Nova\Fields\Field;
79
use Laravel\Nova\Fields\FieldCollection;
810
use Laravel\Nova\Http\Controllers\ActionController;
9-
use Laravel\Nova\Http\Controllers\AssociatableController;
1011
use Laravel\Nova\Http\Controllers\CreationFieldController;
1112
use Laravel\Nova\Http\Controllers\FieldController;
1213
use Laravel\Nova\Http\Controllers\MorphableController;
1314
use Laravel\Nova\Http\Controllers\ResourceAttachController;
15+
use Laravel\Nova\Http\Controllers\ResourceIndexController;
1416
use Laravel\Nova\Http\Controllers\ResourceStoreController;
1517
use Laravel\Nova\Http\Controllers\ResourceUpdateController;
1618
use Laravel\Nova\Http\Controllers\UpdateFieldController;
@@ -23,7 +25,7 @@ trait HasConditionalContainer
2325
/**
2426
* Get the panels that are available for the given detail request.
2527
*
26-
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
28+
* @param NovaRequest $request
2729
* @return array
2830
*/
2931
public function availablePanelsForDetail($request)
@@ -37,7 +39,7 @@ public function availablePanelsForDetail($request)
3739
/**
3840
* Get the panels that are available for the given create request.
3941
*
40-
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
42+
* @param NovaRequest $request
4143
* @return array
4244
*/
4345
public function availablePanelsForCreate($request)
@@ -51,7 +53,7 @@ public function availablePanelsForCreate($request)
5153
/**
5254
* Get the panels that are available for the given update request.
5355
*
54-
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
56+
* @param NovaRequest $request
5557
* @return array
5658
*/
5759
public function availablePanelsForUpdate($request)
@@ -78,18 +80,30 @@ public function availableFields(NovaRequest $request)
7880

7981
$controller = $request->route()->controller;
8082

83+
/**
84+
* Exclude all instance of conditional container from index views
85+
*/
86+
if ($controller instanceof ResourceIndexController) {
87+
88+
return parent::availableFields($request)->filter(function ($field) {
89+
90+
return !($field instanceof ConditionalContainer);
91+
92+
});
93+
94+
}
95+
8196
if ($controller instanceof CreationFieldController ||
8297
$controller instanceof UpdateFieldController) {
8398

8499
$fields = parent::availableFields($request);
85100
$containers = $this->findAllContainers($fields);
101+
$expressionsMap = $containers->flatMap->expressions;
86102

87103
$cleanUpMethodName = $controller instanceof UpdateFieldController ?
88104
'removeNonUpdateFields' :
89105
'removeNonCreationFields';
90106

91-
$expressionsMap = $containers->flatMap->expressions;
92-
93107
/**
94108
* @var ConditionalContainer $container
95109
*/
@@ -107,7 +121,7 @@ public function availableFields(NovaRequest $request)
107121

108122
}
109123

110-
return $fields;
124+
return $this->preloadRelationships($expressionsMap, $fields);
111125

112126
}
113127

@@ -120,12 +134,56 @@ public function availableFields(NovaRequest $request)
120134

121135
}
122136

123-
$fields = $this->flattenDependencies($request, $this->fields($request));
137+
$allFields = $this->fields($request);
138+
$containers = $this->findAllContainers($allFields);
139+
$expressionsMap = $containers->flatMap->expressions;
140+
141+
$fields = $this->flattenDependencies(
142+
$request, $this->preloadRelationships($expressionsMap, $allFields)
143+
);
124144

125145
return new FieldCollection(array_values($this->filter($fields->toArray())));
126146

127147
}
128148

149+
private function preloadRelationships(Collection $expressionsMap, $fields)
150+
{
151+
152+
$relations = collect();
153+
154+
foreach ($fields as $field) {
155+
156+
if ($field instanceof RelatableField ||
157+
$field instanceof \NovaAttachMany\AttachMany ||
158+
$field instanceof \Benjacho\BelongsToManyField\BelongsToManyField) {
159+
160+
$relations->push($field->attribute);
161+
162+
}
163+
164+
}
165+
166+
$expressionsMap = $expressionsMap->map(function (string $expression) {
167+
return ConditionalContainer::splitLiteral($expression)[ 0 ];
168+
});
169+
170+
/**
171+
* Only load the relations that are necessary
172+
*/
173+
$relations = $relations->filter(function ($relation) use ($expressionsMap) {
174+
return $expressionsMap->contains($relation);
175+
});
176+
177+
if ($relations->isNotEmpty()) {
178+
179+
$this->loadMissing($relations);
180+
181+
}
182+
183+
return $fields;
184+
185+
}
186+
129187
private function flattenDependencies(NovaRequest $request, array $fields)
130188
{
131189

@@ -139,7 +197,11 @@ private function flattenDependencies(NovaRequest $request, array $fields)
139197

140198
}
141199

142-
return $fields->flatMap(function ($field) use ($fields, $request, $controller) {
200+
$fakeRequest = $request->duplicate();
201+
202+
return $fields->flatMap(function ($field) use ($fields, $fakeRequest, $controller) {
203+
204+
$this->parseThirdPartyPackageFieldValue($field, $fakeRequest);
143205

144206
if ($field instanceof ConditionalContainer) {
145207

@@ -157,24 +219,26 @@ private function flattenDependencies(NovaRequest $request, array $fields)
157219
$controller instanceof ResourceAttachController ||
158220
$controller instanceof FieldController) {
159221

160-
return $this->flattenDependencies($request, $field->fields->toArray());
222+
return $this->flattenDependencies($fakeRequest, $field->fields->toArray());
161223

162224
}
163225

164226
if ($controller instanceof ResourceUpdateController ||
165227
$controller instanceof ResourceStoreController) {
166228

167-
return $this->flattenDependencies($request, $field->resolveDependencyFieldUsingRequest($this, $request));
229+
return $this->flattenDependencies(
230+
$fakeRequest, $field->resolveDependencyFieldUsingRequest($this, $fakeRequest)
231+
);
168232

169233
}
170234

171-
return $this->flattenDependencies($request, $field->resolveDependencyFieldUsingResource($this));
235+
return $this->flattenDependencies($fakeRequest, $field->resolveDependencyFieldUsingResource($this));
172236

173237
}
174238

175239
if ($field instanceof MergeValue) {
176240

177-
return $this->flattenDependencies($request, $field->data);
241+
return $this->flattenDependencies($fakeRequest, $field->data);
178242

179243
}
180244

@@ -184,6 +248,35 @@ private function flattenDependencies(NovaRequest $request, array $fields)
184248

185249
}
186250

251+
/**
252+
* Intended to minimize the incompatibility with third part package
253+
*
254+
* @param Field $field
255+
* @param NovaRequest $request
256+
*/
257+
private function parseThirdPartyPackageFieldValue(Field $field, NovaRequest $request)
258+
{
259+
260+
$value = $request->get($field->attribute);
261+
262+
if ($field instanceof \Benjacho\BelongsToManyField\BelongsToManyField) {
263+
264+
$request->offsetSet(
265+
$field->attribute, collect(json_decode($value, true))->map->id
266+
);
267+
268+
}
269+
270+
if ($field instanceof \NovaAttachMany\AttachMany) {
271+
272+
$request->offsetSet(
273+
$field->attribute, collect(json_decode($value, true))
274+
);
275+
276+
}
277+
278+
}
279+
187280
private function findAllActiveContainers(Collection $fields, $resource): Collection
188281
{
189282
return $this->findAllContainers($fields)
@@ -193,9 +286,9 @@ private function findAllActiveContainers(Collection $fields, $resource): Collect
193286
->values();
194287
}
195288

196-
private function findAllContainers(Collection $fields): Collection
289+
private function findAllContainers($fields): Collection
197290
{
198-
return $fields->flatMap(function ($field) {
291+
return collect($fields)->flatMap(function ($field) {
199292

200293
if ($field instanceof ConditionalContainer) {
201294

@@ -205,7 +298,7 @@ private function findAllContainers(Collection $fields): Collection
205298

206299
if ($field instanceof MergeValue) {
207300

208-
return $this->findAllContainers(collect($field->data));
301+
return $this->findAllContainers($field->data);
209302

210303
}
211304

0 commit comments

Comments
 (0)