Hi, it would be great if Eloquent could accept nested models, exactly as rails does with the _accepts_nested_attributes_for_ method. Is there a chance it will be added?
I think you're going to have to provide some examples of how it would look/work.
If someone is interested here is rails method documentation http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Basically you specify in the parent model, after the has_many relation, accepts_nested_attributes_for and the nested model name, and, provided that you have specified in the form the fields that belongs to the nested model, it automagically insert the values at their place.
For example if I have an address book database, with model Contact that has many PhoneNumbers and I want to create the contact, and in the same form add a bunch of phone numbers, I will create a form with the contact base information, and some fields, assigned to the nested model, in this case PhoneNumbers.
Then in the Contact model i'll specify the hasMany('PhoneNumbers') relation, and the acceptsNestedAttributesFor('PhoneNumbers') and when I insert a record from the form, it inserts both the Contact and the various PhoneNumbers at the same time.
I am pretty new to laravel and am not sure it's not already implemented, but i've not been able to find it documented somewhere, forgive me if i'm wrong, I think it would be a great addition making the rails to larval step a little easier, since according to what i've read this one line feature in Rails is more code-expensive in larval, being forced to loop through the array and insert with Fluent as reported here http://stackoverflow.com/questions/14012061/laravel-inserting-nested-eloquent-orm-model
Thank you for the attention and sorry if i'm asking for something that is already implemented or that isn't in line with the Laravel design or philosophy.
Regards,
Francesco
I think that model relation handling could definitely be improved in this area, but suspect it is rather tricky to do "automatically" due to some limitations of PHP and the way Eloquent is structured. However, it is possible as is with a few tweaks.
First of all we need to set the relation as fillable. Then we need to set up a setter/mutator for it to tweak its behaviour when being filled. Lastly we use push() instead of save(), which saves the model and all its relations.
// the model
class MyModel extends Eloquent
{
protected $fillable = ['name', 'relation'];
public function relation()
{
return $this->belongsTo('OtherModel');
}
public function setRelationAttribute(array $value)
{
if ($this->relation) $this->relation->fill($value);
}
}
// in the view
<?= Form::text('name') ?>
<?= Form::text('relation[name]') ?>
// the controller
$model->fill(Input::all());
$model->push();
There are cases where this won't work, like if one of the models don't exist, but you can tweak the behaviour to fit your use case. This is due to more overarching issues in Eloquent like not being able to attach a related model if it does not yet have a primary key.
Help me understand your code, it's not easy for me:
Is the setRelationAttribute method is called automatically when in the controller it executes the $model->fill() method?
the method relation, creates an attributes from which i can access the OtherModel methods? let's say, OtherModel has attribute _number_, can I access it with _$model->relation->number_?
Could you please explain when it would not work? when does not exist a OtherModel.php file? I can't understand.
Thank you again
Is the setRelationAttribute method is called automatically when in the controller it executes the $model->fill() method?
Yes.
the method relation, creates an attributes from which i can access the OtherModel methods? let's say, OtherModel has attribute number, can I access it with $model->relation->number?
Yes.
Could you please explain when it would not work? when does not exist a OtherModel.php file? I can't understand.
$model = new MyModel;
// the relation will not be created for you in this case!
$model->fill(['name' => 'foobar', 'relation' => ['name' => 'barfoo']]);
$other = new OtherModel;
// the following will not work unless you call $other->save() first -
// the model passed to associate() must have a primary key
$model->relation()->associate($other);
// the following will work though.
$other = new OtherModel;
$other->save();
$model = new MyModel;
$model->relation()->associate($other);
$model->fill(['name' => 'foobar', 'relation' => ['name' => 'barfoo']]);
$model->push();
Thank you, now I think I got it, I have to create an empty record in the database with sets only the primary key (automatically by auto_increment), and then I can update the values with the fill() and push().
Is Eloquent going to be able in the future to work with related models that doesn't yet have a primary key?
It is nice to see that Eloquent can handle that type of workaround, but I agree something builtin would be nice.
I think it's been brought up a few times. It's a bit tricky but would definitely be nice :)
Is it likely that we'll se someone on it? I would contribute myself but I haven't the skills nor the time to learn them.
I have no plans to implement at this time.
Hello! Its realy very comfortable feature. Cause now laravel dont have it i made a little addon. Look up, may be you will though create this feature.
In model, where i need nested attribute creating i add:
public static $accept_nested_attributes = array('lines');
And now i use special function, but you can combine it with your Eloquent "create".
public static function modelCreateWithNested($model, $data)
{
//Allower nested attributes
$nested = $model::$accept_nested_attributes;
//Nested attributes creating plan
$creating_plan = array();
//extract data of nested attributes from "data" array
foreach($nested as $attribute)
{
if ( isset($data[$attribute]) )
{
//and attach in to creating plan
$creating_plan[$attribute] = $data[$attribute];
unset($data[$attribute]);
}
}
//create parent object
$new_general_obj = $model::create($data);
//and its nested ones
foreach($creating_plan as $attribute=>$data)
{
foreach($data as $data_line)
{
$new_general_obj->$attribute()->create($data_line);
}
}
return $new_general_obj;
}
And when i need to create object with nested models i use MyAddon::createWithNested(MyModel, $data); instead of MyModel::create...
It is very good for me, may be some one will use it too.
Most helpful comment
Hello! Its realy very comfortable feature. Cause now laravel dont have it i made a little addon. Look up, may be you will though create this feature.
In model, where i need nested attribute creating i add:
public static $accept_nested_attributes = array('lines');
And now i use special function, but you can combine it with your Eloquent "create".
And when i need to create object with nested models i use MyAddon::createWithNested(MyModel, $data); instead of MyModel::create...
It is very good for me, may be some one will use it too.