Add field text from relationship in laravel nova in ONE form
Asked Answered
P

2

5

I'm new on Laravel Nova. I'm trying to build a User form. In this moment I have these models: User, UserDetail

In User I have: email, password, username. In UserDetail I have: Name, Lastname, Gender, Number, etc.

Now I would create One form for user. Why I'm focusing on ONE? Because in my User Resource fields I have:

HasOne::make("UserDetail", "details"),

But For set user detail I have 2 form: One for User data (username, password, email) And after save the user I can set detail.

So I don't want compile 2 different form for 1 resource.

I have found this package, but seems broke:

https://github.com/yassipad/laravel-nova-nested-form/issues/66

And the fields UserDetails doens't shown.

So is there any other way for add text field from relationship and merge in same Form?

Praxis answered 26/7, 2019 at 9:56 Comment(0)
A
16

You could solve this by using Laravel's accessors and mutators.

In this example I am only going to add gender from UserDetail because I am lazy. So we start with adding a accessor for gender in our User model

public function details()
{
    return $this->hasOne(UserDetail::class);
}

public function getGenderAttribute()
{
    return $this->details->gender ?? null;
}

This getter will get the gender from the details or null if no details exist.

Now we add a new field to our User resource in Nova.

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),

        Gravatar::make(),

        Text::make('Name')
            ->sortable()
            ->rules('required', 'max:255'),

        Text::make('Email'),

        Password::make('Password'),

        Text::make('Gender')
            ->rules('required'),
    ];
}

Going to the create user form, it will look something like this:

enter image description here

Of course this will not make it save it, as it has no idea how to handle the gender field. For handling this we override fillFields method.

protected static function fillFields(NovaRequest $request, $model, $fields)
{
    // Get all of our user details data
    $userDetails = $request->only(['gender']);

    // Remove them from the request
    $request->request->remove('gender');

    $result = parent::fillFields($request, $model, $fields);

    // Insert them in the details object after model has been saved.
    $result[1][] = function () use ($userDetails, $model){
        $model->details()->updateOrCreate(
            [],
            $userDetails
        );
    };

    return $result;
}

Now we are able to see the gender field as a normal field on the user, and have no need for the UserDetail resource. To add more fields to be saved in the user details table, we have to add them to our only and remove them from our request. (would make sense to have that in a array)

This method also works when updating a user because we choose to use updateOrCreate. enter image description here



A extra note about this approach is that we just introduced a n+1 query, as we are lazy loading the details relation when trying to get the gender attribute. To solve this we simply override indexQuery and add details to the query builder.

public static function indexQuery(NovaRequest $request, $query)
{
    $query->with('details');
    return parent::indexQuery($request, $query);
}
Astringent answered 29/7, 2019 at 14:40 Comment(6)
It works! you have saved my life :D Now I have only understand what and how You have done this and how you have understand this! but It Work! thankyou so much my friend!Praxis
No problem :) So basically all the magic is in fillFields. That one returns an array with two elements. The first one is the model before it has been saved, but with attributes filled to it, the other element is a array of closures which will be run after it has saved.Astringent
We need the model after is has been saved because else we don't have a user id to attach our user details to.Astringent
Thank you , as soon possible(16 hours) I'll give you bounty!Praxis
No problem. Was fun hacking a solution for thisAstringent
I have tested and The solutions works, but caution, because when you save other resource that is liked tho resource that you have "hacked" can throw an error on save :) but nice work! :DPraxis
S
0

Nova 4 supports now hasOne relation inline form

https://nova.laravel.com/docs/4.0/releases.html#inline-hasone-creation

Sikata answered 16/4, 2022 at 16:57 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.