dcasia / nova-inline-morph-to

A Laravel Nova field for displaying morphTo relationship inline.
MIT License
33 stars 15 forks source link

Allow to set default #3

Closed cord closed 5 years ago

cord commented 5 years ago

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
]),
milewski commented 5 years ago

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

cord commented 5 years ago

doesn't work with the syntax above, no error

milewski commented 5 years ago

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()
]),
milewski commented 5 years ago

Sorry it should be the inverse:

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

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.
cord commented 5 years ago

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 :)

milewski commented 5 years ago

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
    ]),
milewski commented 5 years ago

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

milewski commented 5 years ago

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
milewski commented 5 years ago

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),
cord commented 5 years ago

perfect solution, thanks a lot!