Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add field text from relationship in laravel nova in ONE form

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?

like image 986
LorenzoBerti Avatar asked Jul 26 '19 09:07

LorenzoBerti


Video Answer


1 Answers

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);
}
like image 173
Oliver Nybroe Avatar answered Sep 21 '22 19:09

Oliver Nybroe