Skip to content

Commit

Permalink
add support to all relation field types
Browse files Browse the repository at this point in the history
  • Loading branch information
milewski committed Oct 3, 2019
1 parent 664a99a commit 881c3b6
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 21 deletions.
2 changes: 1 addition & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

42 changes: 30 additions & 12 deletions resources/js/components/DetailField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@

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

<resource-index v-for="(hasOneField, index) of hasOneFields"
:key="index"
:field="hasOneField"
:resource-name="hasOneField.resourceName"
:via-resource="hasOneField.inlineMorphTo.viaResource"
:via-resource-id="hasOneField.inlineMorphTo.viaResourceId"
:via-relationship="hasOneField.hasOneRelationship"
:relationship-type="'hasOne'"
:load-cards="false"/>
<template v-for="({type, fields}) of relationalFields">

<resource-index v-for="(relationField, index) of fields"
:key="index"
:field="relationField"
:resource-name="relationField.resourceName"
:via-resource="relationField.inlineMorphTo.viaResource"
:via-resource-id="relationField.inlineMorphTo.viaResourceId"
:via-relationship="relationField[`${type}Relationship`]"
:relationship-type="type"
:load-cards="false"
class="mb-6"/>

</template>

</div>

Expand All @@ -26,14 +31,27 @@
props: ['resource', 'resourceName', 'resourceId', 'field'],
mixins: [ReplaceValueWithLabel],
computed: {
hasOneFields() {
relationalFields() {
return this.fields.filter(field => field.component === 'has-one-field')
return [
{
type: 'hasOne',
fields: this.fields.filter(field => field.component === 'has-one-field')
},
{
type: 'hasMany',
fields: this.fields.filter(field => field.component === 'has-many-field')
},
{
type: 'belongsToMany',
fields: this.fields.filter(field => field.component === 'belongs-to-many-field')
}
]
},
standardFields() {
return this.fields.filter(field => field.component !== 'has-one-field')
return this.fields.filter(field => !['has-one-field', 'has-many-field', 'belongs-to-many-field'].includes(field.component))
},
fields() {
Expand Down
85 changes: 77 additions & 8 deletions src/InlineMorphTo.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@
use App\Nova\Resource;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Laravel\Nova\Fields\BelongsToMany;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\MorphOne;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\HasOne;
use Laravel\Nova\Http\Controllers\ResourceIndexController;
use Laravel\Nova\Http\Controllers\ResourceShowController;
use Laravel\Nova\Http\Controllers\UpdateFieldController;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Nova;
use ReflectionClass;
Expand Down Expand Up @@ -61,15 +66,16 @@ public function types(array $types): self

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

$fields = (new $resource($resource::newModel()))->fields(app(NovaRequest::class));
/**
* @var Resource $resourceInstance
*/
$resourceInstance = new $resource($resource::newModel());

return [
'className' => $resource,
'uriKey' => $resource::uriKey(),
'label' => $useKeysAsLabel ? $key : $this->convertToHumanCase($resource),
'fields' => collect($fields)->reject(function ($field) {
return $field instanceof ID;
})->toArray()
'fields' => $this->resolveFields($resourceInstance)
];

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

}

private function resolveFields(Resource $resourceInstance): Collection
{

/**
* @var NovaRequest $request
*/
$request = app(NovaRequest::class);
$controller = $request->route()->controller;

if ($controller instanceof UpdateFieldController) {

return $resourceInstance->updateFields($request);

}

if ($controller instanceof ResourceShowController) {

return $resourceInstance->detailFields($request);

}

if ($controller instanceof ResourceIndexController) {

return $resourceInstance->indexFields($request);

}

return $resourceInstance->availableFields($request);

}

private function convertToHumanCase(string $resource): string
{
return Str::title(str_replace('_', ' ', Str::snake((new ReflectionClass($resource))->getShortName())));
Expand Down Expand Up @@ -107,7 +144,9 @@ protected function resolveAttribute($resource, $attribute)

foreach ($fields as $field) {

if ($field instanceof MorphOne) {
if ($field instanceof HasOne ||
$field instanceof HasMany ||
$field instanceof BelongsToMany) {

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

}

private function getFields(Model $model): array
private function getFields(Model $model): Collection
{
$resourceClass = Nova::resourceForModel($model);

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

public function jsonSerialize()
{

/**
* @var NovaRequest $request
*/
$request = app(NovaRequest::class);
$originalResource = $request->route()->resource;

/**
* Temporarily remap the route resource key so every sub field thinks it's being resolved by it's original parent
*/
foreach ($this->meta[ 'resources' ] as $resource) {

$resource[ 'fields' ] = $resource[ 'fields' ]->transform(function (&$field) use ($request, $resource) {

$request->route()->setParameter('resource', $resource[ 'uriKey' ]);

return $field->jsonSerialize();

});

}

$request->route()->setParameter('resource', $originalResource);

return parent::jsonSerialize();

}

}

0 comments on commit 881c3b6

Please sign in to comment.