When to refresh an instance using Eloquent - laravel

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?

Related

Update the Record of Related Model in Laravel

How to update a record in the related table model by chain expression?
This is what I currently do (and it works)
$user = User::find(1);
$token = Token::where('user_id', $user->id)->first();
$token->token = $request->token;
$token->save();
But can I do the above in a more elegant way, such as?
$user = User::find(1);
$user->token()->token = $new_token;
$user->token()->save();
My User Model
public function token()
{
return $this->hasOne('App\Token');
}
In one line:
User::find(1)->token()->update(['token' => $new_token]);
Just know these things before using it:
User find could return null if the user id is not found.
The saved and updated model events will not be fired for the updated models.
The update method execution does not go through the Eloquent model methods.
However in your particular case I think it's valid, specially if you know that the user id will always be valid.
Yo can do it like this :
User::find(1)->token()->update(['token' => $new_token]);
Or do it in youApp\Token class like this :
User::find(1)->token()->update_token($new_token);
And create update_token function in App\Token class:
public function update_token(string $new_token)
{
$this->update(['token'=>$new_token]);
}
$user = User::with('token')->findOrFail(1);
$user->token->update(['token' => $request->token]);

Why does this Eloquent relationship return null in a foreach loop?

I have a relationship that's acting weird. If I get the results and dd(), it has the correct data. However, if I run the collection through a foreach loop it's like the relationship disappears.
The users table has a field called referred_by, which stores the user ID of the person who referred the user. In my instance I'm looking for all the new users who were referred by the user with the ID of 3.
Here's the relationship in User.php
public function referrer()
{
return $this->belongsTo(User::class, 'referred_by');
}
Here's the code which is returning funky results
$users = User::where('referred_by', 3)
->with('referrer')
->get();
// doing dd() here returns a collection with full referrer relationship;
// the returned data is as expected
dd($users);
foreach($users as $user)
{
// dd($user) here returns the relationship, as it should
// dd($user->referrer) here returns null, like the relationship doesn't exist
}
Try with
foreach($users as $user)
{
// dd($user) here returns the relationship, as it should
dd($user['referrer'])
}
Rather then
// dd($user->referrer)
Turns out I had a database column on the users table named referrer that was causing an issue. I changed the relationship's method name from referrer() to referredBy() and it worked. *eyeroll*

Laravel 5.2 How to get all user which contains permission Many to Many

I have table with many to many relationship.
User many to many Permission
I already define many to many relationship on both model, and create the pivot table also.
What I want is get all user which contain permission name
What I have done so far is
User::all()->permissions->contains('name', 'access.backend.admin')->get();
But it give me
Undefined property: Illuminate\Database\Eloquent\Collection::$permissions on line 1
What wrong with my code?
User::All() returns a collection not model object. You have iterate over the collection to get the model object and use ->permissions().
For exapmle:
$users = User::all();
foreach ($users as $user) {
$user->permissions->contains('name', 'access.backend.admin'); // returns boolean
}
Or you can get a single model from DB as:
$user = User::first();
$user->permissions->contains('name', 'access.backend.admin'); // returns boolean
Update 1
To get users which contain desired permission use filter() method as:
$filtered_users = $users->filter(function ($user) {
if ($user->permissions->contains('name', 'access.backend.admin')) {
return $user;
}
});
Update 2
You can also write a query which returns the desired result as:
$filtered_users = User::whereHas('permissions', function($q) {
$q->where('name', 'access.backend.admin');
})->get()
I have a similar case of questions and tags, they have many to many relationship.
So when i have to fetch all question with a particular tag then i do this
$tag = Tag::where('name','laravel')->get()->first();
I first retrieved the Tag model with name laravel.
and then retrieved all questions having tag laravel.
$questions = $tag->questions;
Similarly you can do this
$permission = Permission::where('name','access.backend.admin')->get()->first();
$users = $permission->users;

How to query relationships in Laravel 4 with Eloquent?

Coming from CodeIgniter's Datamapper ORM I am still trying to get my head around Laravel's Eloquent ORM.
Given the fact that I have an ACCOUNT and a USER table (simplified):
ACCOUNT
- id
- name
USER
- id
- account_id
- username
One account has many users. One user belongs to one account. So we're dealing with a one-to-many relationship. Everything is already set-up in the models.
In CodeIgniter's Datamapper I would have done the following to get the user from any given ID and at the same time check if that user is related to the current account:
$u = new User();
$u->where('username', $username);
$u->where_related_account('id', $account_id);
$u->get();
if ( ! $u->exists()) exit; // or do something...
// otherwise continue to use the "$u" user object
This syntax is very logical and easy to understand. In Eloquent I have a hard time to achieve the same with a similar easy syntax. Does anyone have any suggestions?
Very simply (ignoring the relationship between the user and the account), it could just be:
$u = User::where('username', $username)
->where('account_id', $id)
->get();
That will return you your user's details.
Otherwise, assuming that you have your User and Account classes and DB tables are set up correctly (as per the Laravel docs), you should be able to just do:
$user_exists = Account::find($account_id)
->users()
->where("username", "=", $username)
->first()
->exists;
if ($user_exists)
{
doThings();
}
If you've correctly set up your models and database tables (as #msturdy said) you should actually be able to return your user account by simply going:
$user = User::whereUsername($username)
->first(); // or User::where('username', $username)->first();
if ($user) {
$account = $user->accounts()
->whereId($account_id)
->first(); // or $user->accounts()->where('id', $account_id)->first();
}
This gives you the ability to access the user and account models
you could even extend your User model to include the following methods:
class User extends Eloquent {
...
public static function byUsername($username) {
return static::whereUsername($username)->first();
}
public function getAccount($id) {
return $this->accounts()->whereId($id)->first();
}
...
}
and then simply go
$user = User::byUsername($username);
if ($user) {
$account = $user->getAccount($account_id);
}
which might be better for you if you are using the code in multiple controllers.

Eloquent push() and save() difference

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.

Resources