dcasia / nova-inline-morph-to

A Laravel Nova field for displaying morphTo relationship inline.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Allow to set default

cord opened this issue · comments

commented

would be great to set a default model with the common nova syntax:

InlineMorphTo::make('Metricable')
->types($metricables)
->withMeta([
   'value' => $this->metricable_type ?? \Metricables\Standard::class
]),

@cord you should be able to do this already, any error?

commented

doesn't work with the syntax above, no error

if you are using morphMap this $this->metricable_type will output something like this: standard while \Metricables\Standard::class will output \App\Nova\Metricables\Standard the later should be the correct format

So perhaps a solution to this could be:

InlineMorphTo::make('Metricable')
->types($metricables)
->withMeta([
   'value' => $this->metricable_type ?? (new \Metricables\Standard::class)->getMorphClass()
]),

Sorry it should be the inverse:

InlineMorphTo::make('Metricable')
->types($metricables)
->withMeta([
   'value' => Relation::getMorphedModel($this->metricable_type) ?? \Metricables\Standard::class
]),
commented

hm, that would require a morphMap - and some refactoring:

When adding a "morph map" to your existing application, every morphable *_type column value in 
your database that still contains a fully-qualified class will need to be converted to its "map" name.
commented

The confusing part is that "value" should be the model class for creating items, but the resource class for editing items.

My solution looks like this:

On Morphable Model return the related Nova Resource:

    public static function getResourceModel() {
        return \App\Nova\Metricables\Standard::class;
    }

so it is possible to retrieve it w/o a morphMap:

'value' => $this->metricable_type ? $this->metricable_type::getResourceModel() : \Metricables\Standard::class

Works fine for creating and editing :)

Im not sure if I understood your solution, but I think it should be something really simple along these lines:

class AppServiceProvider {

    public function boot()
    {
        // Always create a morphMap so you don't couple your database with your application code
        Relation::morphMap([
            'type-a' => \App\Nova\A::class,
            'type-b' => \App\Nova\B::class,
            'type-c' => \App\Nova\C::class,
        ]);
    }

}

then on the field you use like this:

$resources = [ \App\Nova\A::class,  \App\Nova\B::class, \App\Nova\C::class ];

//...
// if you are updating the value of $this->metricable_type should be type-a / type-b / type-c
// if you are creating the value of $this->metricable_type should be null
// Relation::getMorphedModel('type-a') will return \App\Nova\A::class for example

InlineMorphTo::make('Demo')
   ->types($resources)
   ->withMeta([
        'value' => \Illuminate\Database\Eloquent\Relations\Relation::getMorphedModel($this->metricable_type) ?? \App\Nova\A::class
    ]),

The confusing part is that "value" should be the model class for creating items, but the resource class for editing items.

Uhm... I think I see what you mean, let me run some test locally, in both ways it should take the resource class instead of model class

Ok my bad... it should be this:

// Relation::getMorphedModel('type-a') will return \App\Nova\A::class \App\Models\A::class for example

'value' => Nova::resourceForModel(Relation::getMorphedModel($this->metricable_type)) ?? \App\Nova\A::class

Ok to avoid confusion and reduce the boilerplate I have added another method to set the default value

InlineMorphTo::make('Metricable')
    ->types($metricables)
    ->default(\Metricables\Standard::class),
commented

perfect solution, thanks a lot!