Skip to content

Commit 881c3b6

Browse files
committed
add support to all relation field types
1 parent 664a99a commit 881c3b6

File tree

3 files changed

+108
-21
lines changed

3 files changed

+108
-21
lines changed

dist/js/field.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/components/DetailField.vue

+30-12
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44

55
<panel :panel="{ name: field.value, fields: standardFields }"/>
66

7-
<resource-index v-for="(hasOneField, index) of hasOneFields"
8-
:key="index"
9-
:field="hasOneField"
10-
:resource-name="hasOneField.resourceName"
11-
:via-resource="hasOneField.inlineMorphTo.viaResource"
12-
:via-resource-id="hasOneField.inlineMorphTo.viaResourceId"
13-
:via-relationship="hasOneField.hasOneRelationship"
14-
:relationship-type="'hasOne'"
15-
:load-cards="false"/>
7+
<template v-for="({type, fields}) of relationalFields">
8+
9+
<resource-index v-for="(relationField, index) of fields"
10+
:key="index"
11+
:field="relationField"
12+
:resource-name="relationField.resourceName"
13+
:via-resource="relationField.inlineMorphTo.viaResource"
14+
:via-resource-id="relationField.inlineMorphTo.viaResourceId"
15+
:via-relationship="relationField[`${type}Relationship`]"
16+
:relationship-type="type"
17+
:load-cards="false"
18+
class="mb-6"/>
19+
20+
</template>
1621

1722
</div>
1823

@@ -26,14 +31,27 @@
2631
props: ['resource', 'resourceName', 'resourceId', 'field'],
2732
mixins: [ReplaceValueWithLabel],
2833
computed: {
29-
hasOneFields() {
34+
relationalFields() {
3035
31-
return this.fields.filter(field => field.component === 'has-one-field')
36+
return [
37+
{
38+
type: 'hasOne',
39+
fields: this.fields.filter(field => field.component === 'has-one-field')
40+
},
41+
{
42+
type: 'hasMany',
43+
fields: this.fields.filter(field => field.component === 'has-many-field')
44+
},
45+
{
46+
type: 'belongsToMany',
47+
fields: this.fields.filter(field => field.component === 'belongs-to-many-field')
48+
}
49+
]
3250
3351
},
3452
standardFields() {
3553
36-
return this.fields.filter(field => field.component !== 'has-one-field')
54+
return this.fields.filter(field => !['has-one-field', 'has-many-field', 'belongs-to-many-field'].includes(field.component))
3755
3856
},
3957
fields() {

src/InlineMorphTo.php

+77-8
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@
55
use App\Nova\Resource;
66
use Illuminate\Database\Eloquent\Model;
77
use Illuminate\Support\Arr;
8+
use Illuminate\Support\Collection;
89
use Illuminate\Support\Str;
10+
use Laravel\Nova\Fields\BelongsToMany;
911
use Laravel\Nova\Fields\Field;
10-
use Laravel\Nova\Fields\ID;
11-
use Laravel\Nova\Fields\MorphOne;
12+
use Laravel\Nova\Fields\HasMany;
13+
use Laravel\Nova\Fields\HasOne;
14+
use Laravel\Nova\Http\Controllers\ResourceIndexController;
15+
use Laravel\Nova\Http\Controllers\ResourceShowController;
16+
use Laravel\Nova\Http\Controllers\UpdateFieldController;
1217
use Laravel\Nova\Http\Requests\NovaRequest;
1318
use Laravel\Nova\Nova;
1419
use ReflectionClass;
@@ -61,15 +66,16 @@ public function types(array $types): self
6166

6267
$types = collect($types)->map(function (string $resource, $key) use ($useKeysAsLabel) {
6368

64-
$fields = (new $resource($resource::newModel()))->fields(app(NovaRequest::class));
69+
/**
70+
* @var Resource $resourceInstance
71+
*/
72+
$resourceInstance = new $resource($resource::newModel());
6573

6674
return [
6775
'className' => $resource,
6876
'uriKey' => $resource::uriKey(),
6977
'label' => $useKeysAsLabel ? $key : $this->convertToHumanCase($resource),
70-
'fields' => collect($fields)->reject(function ($field) {
71-
return $field instanceof ID;
72-
})->toArray()
78+
'fields' => $this->resolveFields($resourceInstance)
7379
];
7480

7581
});
@@ -80,6 +86,37 @@ public function types(array $types): self
8086

8187
}
8288

89+
private function resolveFields(Resource $resourceInstance): Collection
90+
{
91+
92+
/**
93+
* @var NovaRequest $request
94+
*/
95+
$request = app(NovaRequest::class);
96+
$controller = $request->route()->controller;
97+
98+
if ($controller instanceof UpdateFieldController) {
99+
100+
return $resourceInstance->updateFields($request);
101+
102+
}
103+
104+
if ($controller instanceof ResourceShowController) {
105+
106+
return $resourceInstance->detailFields($request);
107+
108+
}
109+
110+
if ($controller instanceof ResourceIndexController) {
111+
112+
return $resourceInstance->indexFields($request);
113+
114+
}
115+
116+
return $resourceInstance->availableFields($request);
117+
118+
}
119+
83120
private function convertToHumanCase(string $resource): string
84121
{
85122
return Str::title(str_replace('_', ' ', Str::snake((new ReflectionClass($resource))->getShortName())));
@@ -107,7 +144,9 @@ protected function resolveAttribute($resource, $attribute)
107144

108145
foreach ($fields as $field) {
109146

110-
if ($field instanceof MorphOne) {
147+
if ($field instanceof HasOne ||
148+
$field instanceof HasMany ||
149+
$field instanceof BelongsToMany) {
111150

112151
$field->meta[ 'inlineMorphTo' ] = [
113152
'viaResourceId' => $relationInstance->id,
@@ -164,11 +203,41 @@ public function fill(NovaRequest $request, $model)
164203

165204
}
166205

167-
private function getFields(Model $model): array
206+
private function getFields(Model $model): Collection
168207
{
169208
$resourceClass = Nova::resourceForModel($model);
170209

171210
return $this->meta[ 'resources' ]->where('className', $resourceClass)->first()[ 'fields' ];
172211
}
173212

213+
public function jsonSerialize()
214+
{
215+
216+
/**
217+
* @var NovaRequest $request
218+
*/
219+
$request = app(NovaRequest::class);
220+
$originalResource = $request->route()->resource;
221+
222+
/**
223+
* Temporarily remap the route resource key so every sub field thinks it's being resolved by it's original parent
224+
*/
225+
foreach ($this->meta[ 'resources' ] as $resource) {
226+
227+
$resource[ 'fields' ] = $resource[ 'fields' ]->transform(function (&$field) use ($request, $resource) {
228+
229+
$request->route()->setParameter('resource', $resource[ 'uriKey' ]);
230+
231+
return $field->jsonSerialize();
232+
233+
});
234+
235+
}
236+
237+
$request->route()->setParameter('resource', $originalResource);
238+
239+
return parent::jsonSerialize();
240+
241+
}
242+
174243
}

0 commit comments

Comments
 (0)