Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel form binding with one to one relationships

I have an Account model that has a polymorphic relation to an Address model. This is set up as a one-to-one releationship set up like so:

Account:

public function address()
{
    return $this->morphOne('Address', 'hasAddress', 'add_hasaddress_type', 'add_hasaddress_id', 'act_id');
}

Address:

public function hasAddress()
{
    return $this->morphTo('hasAddress', 'add_hasaddress_type', 'add_hasaddress_id');
}

On my form to edit the account, I also have the address fields. I can bind my account object simply enough by doing:

{{ Form::model($account, array('route' => array('accounts/edit', $account->act_id), 'method' => 'put')) }}
    {{ Form::label('act_name', 'Account Name:') }}
    {{ Form::text('act_name', Input::old('act_name')) }}

and that fills in the fields properly. But, how do I populate the address fields? From what I researched, I need to do:

{{ Form::text('address.add_city', Input::old('address.add_city')) }}

To access the relation's values, but this doesn't work.

I also tried

{{ Form::text('address[add_city]', Input::old('address[add_city]')) }}

as suggested by a SO with a similar title. Both of these I tried with and without the old input. Does this just not work with poymorphic relations or am I doing something wrong?

Also, how do you handle these forms in the controller?

Nothing about relations is in the form model binding documentation, and doing a search mainly brings up people asking for one-to-many binding.

like image 304
Troncoso Avatar asked Oct 11 '14 22:10

Troncoso


1 Answers

It works with any *-to-one relation (for many-to-many, ie. a collection of models it won't work):

// prepare model with related data - eager loading
$account = Account::with('address')->find($someId);

// or lazy loading
$account = Account::find($someId);
$account->load('address');

// view template
{{ Form::model($account, ...) }}
  Account: {{ Form::text('acc_name') }}
  City: {{ Form::text('address[add_city]') }}
{{ Form::close() }}

No need for Input::old or whatsoever, null is enough as default value. Laravel will fill the data in this order (Docs are wrong here!):

1. old input
2. bound data
3. value passed to the helper

Mind that you must load the relation (dynamic call won't work in this case).

Another thing is processing the input later - Laravel will not automatically hydrate the related model, so you need something like:

$accountData = Input::only(['acc_name', ... other account fields]);
// or
$accountData = Input::except(['address']);
// validate etc, then:
$account->fill($accountData);

$addressData = Input::get('address');
// validate ofc, then:
$account->address->fill($addressData);
like image 86
Jarek Tkaczyk Avatar answered Sep 25 '22 17:09

Jarek Tkaczyk