Bind multiple models to a form in Laravel 5 and validate it

Reading Time: 3 minutes

Form model binding in Laravel 5 makes the programmers’ live easier, no doubt. But what if you want to bind multiple models to a form? This is not straight forward but it’s not so complex either. (May be it was till I cracked it)

Follow the steps below and you should be okay.

Note:

  • I am assuming that there is a one on one relationship between the models you are binding.
  • Form model binding works if you have Laravel Collective’s Form & HTML package installed in your project.

 

Creating the Form Controller Method

First of all, create the controller method, and pass the model to the view.

class MyProfileController extends Controller
{
    public function edit(){
        $data = [
            'user' => User::find(Auth::user()->id), //Pass the model as data
            'pageTitle' => 'Edit my profile',
        ];
        return view('profiles.edit', $data);
    }
}

In the above example, the User model has a relationship with the other models we are binding to the form.

 

Defining the relationships in the Models

The models need to be related for this method to work. In our case, we are working with User model and Profile models.

The User model

The user model was created using the artisan make:auth command but this doesn’t matter. It can as well be a child of the Model class

class User extends Authenticatable
{

    //
    //...
    //
    public function profile(){
        return $this->hasOne('App\Profile');
    }
}

 

The Profile model

This is the reverse in the one one one relationship

class Profile extends Model
{
    
    //
    //...
    // 


    public function user(){
        return $this->belongsTo('App\User');
    }
}

 

The View, where the Form Model binging takes place

Like I mentioned, form model binding works with Laravel Collective’s Form & HTML package. So here is what the view looks like

{!! Form::model($user, ['url' => url('profile/edit')]) !!}
            {!! csrf_field() !!}



            <!-- name field -->
            <div class="form-group  {{ $errors->has('name') ? ' has-error' : '' }}">
                {{ Form::label('name', 'Full name') }}
                {{ Form::text('name', null, ['id'=>'name', 'placeholder'=>'Your full name', 'class'=>"form-control"]) }}

                @if ($errors->has('name'))
                    <span class="help-block">{{ $errors->first('name') }}</span>
                @endif
            </div>

            <!-- About Me field -->
            <div class="form-group  {{ $errors->has('profile.about_me') ? ' has-error' : '' }}">
                {{ Form::label('about_me', 'About me') }}
                {{ Form::textarea('profile[about_me]', null, ['id'=>'about_me', 'placeholder'=>'A little info about you', 'class'=>"form-control", 'rows' => 4]) }}

                @if ($errors->has('profile.about_me'))
                    <span class="help-block">{{ $errors->first('profile.about_me') }}</span>
                @endif
            </div>

            <!-- city field -->
            <div class="form-group  {{ $errors->has('profile.city') ? ' has-error' : '' }}">
                {{ Form::label('city', 'Town/City   ') }}
                {{ Form::text('profile[city]', $value = null, ['id'=>'city', 'placeholder'=>'Your town or city of residence', 'class'=>"form-control"]) }}

                @if ($errors->has('profile.city'))
                    <span class="help-block">{{ $errors->first('profile.city') }}</span>
                @endif
            </div>

         

            <button class="btn btn-info btn-md" type="submit">
                <i class="fa fa-save"></i>
                Save profile
            </button>

            {!! Form::close() !!}

 

Take note

  • The name field belongs to the User model while the about_me and city fields belong to the Profile model
  • Dot notation is used for the error names of the Profile fields/properties e.g profile.city while the name of the form field uses [ ]  e.g profile[city] (No quotation marks)

 

Writing the Validation logic

We need to validate the 3 fields i.e

  1. name
  2. about_me
  3. city

There are a number of ways to write the validation logic. I usually prefer to create a Request. This allows for reuse.

class ProfileRequest extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {

        return [
            'name' => 'required|max:40|min:3',
            'profile.about_me' => 'required|max:500',
            'profile.city' => 'max:40|min:2',
        ];

    }

    public function messages()
    {
        return [
            'required' => 'This field is required',
            'min' => 'Must not be less than :min characters',
            'max' => 'Must not be greater than :max characters'
        ];
    }
}

In the rules() method, notice that I used the dot notation for about_me and city properties.

You need to create/override the messages() method and define custom messages, if not your users will see gibberish arising from :attribute property used in the default message which will make return something like “The profile.about_me field is required

 

Saving the form fields

You can go ahead and save the form fields. You don’t have to use the [] or dot notations, Request will recognise the form fields (i.e name, about_me and city) the way they are.

 

Conclusion

This process is pretty straightforward like I mentioned earlier. Go ahead and give it a try. And if you have any questions, use the comment section below.