Eloquent push() and save() difference - laravel

I have read laravel 4 docs about eloquent and was quite intrigued by the push() part.
It says,
Sometimes you may wish to save not only a model, but also all of its relationships. To do so, you may use the push method:
Saving A Model And Relationships
$user->push();
See link here
Sorry but it's a bit blurry on my part the difference between save() and push().
I am hoping someone can clear this one out for me. Thank you.

Heres the magic behind the scenes...
/**
* Save the model and all of its relationships.
*
* #return bool
*/
public function push()
{
if ( ! $this->save()) return false;
// To sync all of the relationships to the database, we will simply spin through
// the relationships and save each model via this "push" method, which allows
// us to recurse into all of these nested relations for the model instance.
foreach ($this->relations as $models)
{
foreach (Collection::make($models) as $model)
{
if ( ! $model->push()) return false;
}
}
return true;
}
It just shows that push() will update all the models related to the model in question, so if you change any of the relationships, then call push()
It will update that model, and all its relations
Like so...
$user = User::find(32);
$user->name = "TestUser";
$user->state = "Texas";
$user->location->address = "123 test address"; //This line is a pre-defined relationship
If here you just...
$user->save();
Then the address wont be saved into the address model....
But if you..
$user->push();
Then it will save all the data, and also save the address into the address table/model, because you defined that relationship in the User model.
push() will also update all the updated_at timestamps of all related models of whatever user/model you push()
Hopefully that will clear the things....

Let's say you did this:
$user = User::find(1);
$user->phone = '555-0101';
$user->address->zip_code = '99950';
You just made changes to two different tables, to save them you have to:
$user->save();
$user->address->save();
or
$user->push();

push() can only be used to update an existing model instance along side its relations not to create a new one. Simply say: push() updates and not insert.

Related

Defining a relation in Eloquent Model Laravel

I have this query
SELECT * FROM users AS u INNER JOIN branches AS b ON u.branch_id = b.branch_id
This means to every one user there is a branch associated but one branch can be associated with many user.
Can anyone help me how to define this relation?
I did this
I wrote this relation in User model
public function branch()
{
return $this->belongsTo('App\Branch');
}
And it returns null.
You problem seems to be inverse of one to many relationship i.e. Many to One.
Here, in your case Many Users belongs to one Branch. So, you can define Many to One relationship in User model as :
public function branch()
{
return $this->belongsTo('App\Branch','branch_id');
}
Now, you can access branch of a user like this:
$user = User::find($id);
$branch = $user->branch;
Hope you understand.
You should try this:
public function branch()
{
return $this->belongsTo('App\Branch','branch_id');
}
Hope this work for you !!!

Best way to do this listing laravel with relationship

What is the best way to do this listing?
I would not want to do it that way "ugly".
/**
* Get user indicateds
* #return array|null
*/
static public function indicateds()
{
$users = ModelUser::all();
foreach( $users as $user ) {
if( $user->financial->status_payment ) {
$newArray[] = $user;
}
}
return (isset($newArray) ? $newArray : null);
}
Thanks
You can use the collection's filter method:
return ModelUser::with('financial')
->get()
->filter(function($user) {
return $user->financial->status_payment;
});
I'm supposing you have defined the financial relation and you should eager load it as I did to improve the performance.
One of the benefits to relationships is that you can use them to modify your queries, as well. So, instead of getting all users into a Collection, and then filtering that Collection, you can use the relationship to modify the query so that you only get the desired records in the first place. This will reduce the number of records returned from the database, as well as the number of model instances that get created. This will save you time and memory.
$users = ModelUser::with('financial')
->whereHas('financial', function($q) {
// $q is the query for the financial relationship;
return $q->where('status_payment', true);
}
->get();
The with() is not required, but if you'll be accessing the financial relationship on the returned users, it is a good idea to eager load it.
The whereHas() is where the magic happens. It modifies the query so that it will only return users that have a related financial record that matches the conditions added by the closure used in the second parameter.
You can read more about it in the documentation here.

When to refresh an instance using Eloquent

Why do we have to refresh an instance after adding new relations?
Example, theres a pivot table 'favourites' which stores all the favourite relation N:N between items and users:
$item = factory(App\Item::class)->create();
$user = factory(App\User::class)->create();
$user->setFavourite($item->id);
dd($user->favourites);//is Empty!!
//whereas refreshing the instance...
$user = $user->fresh();
dd($user->favourites);//is the corresponding collection within the item
The setFavourite method is simply an attach/detach of the relationship:
public function setFavorito($id)
{
if(Auth::check())
{
$user = Auth::user();
if($user->esAnuncioFavorito($id)) {
$user->favoritos()->detach($id);
}else{
$user->favoritos()->attach($id);
}
}
return Redirect::back();
}
I though that when eloquent calls for the related instances of an instance it was done at the moment, therefore a call to the DB shall be done and would end retrieving an updated collection including the added one.
Could someone explain it to me? When should I use the fresh() method?

Eloquent MorphMany relationship proxy attribute

In my application I made the strange observation, that a seemingly equal operation has different results to another.
I have the following tables:
aliases:
$table->engine = "InnoDB";
$table->increments("id");
$table->morphs("aliasable");
$table->string("alias");
$table->string("locale");
categories:
$table->engine = "InnoDB";
$table->increments('id');
The Category model has a relationship to the Alias model:
public function aliases()
{
return $this->morphMany("Alias", "aliasable");
}
When trying to manipulate the data of the alias of a category there is a difference between the two following methods:
$category = Category::find(1);
$alias = $category->aliases()->first();
$alias->alias = "test";
$alias->save();
$category = Category::find(1);
$alias = $category->aliases()->first()->alias = "test";
$category->aliases()->first()->save();
The first one is working, the second one is not saving the change.
I would like to get the second version working as I try to implement a proxy attribute on my Category model in order to change the alias like so:
$category = Category::find(1);
$category->germanAlias = "Heidi";
$category->push();
Do you have any idea why my way is not working as expected?
The key thing to understand here is the way relationships are cached on the model. When you access the relationship method directly, then no caching occurs. You are basically instantiating a new Query based off of that relationships definition.
$query = $category->aliases();
$alias = $query->first();
If you access the relationship as if it were a member/attribute of the model, then it will load and cache the relationship as a collection on the model.
$collection = $category->aliases;
$alias = $collection->first();
Future attempts to access the related model by this method will reference the same cached collection of models. This should work.
$category->aliases->first()->alias = 'test';
$category->aliases->first()->save();
Within /Illuminate/Database/Eloquent/Model __get() is a magic method that redirects request for undefined members to the getAttribute() method. The code comments do a pretty good job of explaining the rest but basically it checks for, loads, caches and reuses the relationships.
$category->aliases()->first()->save();
This line select first alias and saves it. Doesnt actually do anything. Your first method is correct. You could also do
$category->aliases()->first()->update(['alias' => 'test']);
if your alias field is included in the $fillable property of the Alias model
EDIT
Run the code below and compare the object ids;
$alias = $category->aliases()->first()->alias = "test";
var_dump(alias);
dd($category->aliases()->first());

Database relation with Laravel Eloquent ORM

I'm new to Laravel and I'm stuck. This is what I am struggling with:
$questions = Question::find($id)->quiz(); // this code retrieves data from
// the table using the primary key
// in the table. The is a parameter
// that is passed via get.
This is what I have right now:
$questions = Question::where('quiz_id', '=', $id)->quiz();
This is the error I get:
Call to undefined method Illuminate\Database\Query\Builder::quiz()
What I want to do:
I want to run a query to get data from my database table using the foreign key in the table not the primary key, I also want to be able to use relations with this as seen from what I tried to do above.
Edit: Added the Question Model
<?php
class Question extends Eloquent{
protected $table = 'quiz_questions';
public function quiz()
{
return $this->belongsTo('Quiz');
}
}
Calling the quiz() function from Question::find($id)->quiz() will return a Query Builder instance allowing you to query the parent of the Question, its not going to return any data at that point until you call ->get() or another method that actually executes the query.
If you're wanting to return all the questions belonging to a certain quiz then you can do it like this.
$questions = Question::where('quiz_id', $id)->get();
This will return an Eloquent\Collection of the results for all questions with a quiz_id that is equal to $id.
If you've setup the relations between the Quiz and Questions then you can also do this using the Laravel relations.
$quiz = Quiz::findOrFail($id);
foreach($quiz->questions as $question)
{
// Do stuff with $question
}
Laravel will automagically pull Questions from the database that belongTo the Quiz you've already got from the database, this is known as eager loading http://laravel.com/docs/4.2/eloquent#eager-loading
Wader is correct, just calling where() will not execute your query. You either call get() and get an iterable result or use first() if you only want one result.
$quiz = Question::where('quiz_id', '=', $id)->first()->quiz();

Resources