Check if collection contains a value - php

I have the relationships set up (correctly i think).. I have 3 tables, users, comments, and comments' likes table.
In my blade, I can access {{ $comment->commentLikes }} with this and it's returning me:
[{"id":85,"comment_id":12,"user_id":1,"action":1},
{"id":86,"comment_id":12,"user_id":3,"action":1},
{"id":87,"comment_id":12,"user_id":4,"action":1},
{"id":88,"comment_id":12,"user_id":6,"action":1},
{"id":89,"comment_id":12,"user_id":9,"action":1}]
user_id represents owner of the like.
Now I want to check if this collection has the authenticated user, in other words if the current user liked this comment or not.. Is there a way to do that rather than using a for loop? Maybe something like {{ $comment->commentLikes->owner }} so that I can use
'if (this) contains Auth::user->id()'...

One way to check this is using where() and first() collection methods:
if ($comment->commentLikes->where('user_id', auth()->user()->id)->first())

// This works if $comment->commentLikes returns a collection
$userLikes = $comment->commentLikes->where('user_id', Auth::user()->id)->all();
if ($userLikes->count() > 0) {
// Do stuff
}

Option 1
Using Laravel collection you could do this:
$comment->commentLikes->search(function ($item, $key) {
return $item->user_id == auth()->user()->id;
});
This will return false if none is found or index if the user is in the collection.
Making it pretty
But since you'll probably use this in a view I would package it in an accessor, something like this:
class Comment extends Model
{
public function commentLikes() {
// relationship defined
}
public function getHasLikedAttribute()
{
// use getRelationValue so it won't load again if it was loaded before
$comments = $this->getRelationValue('commentLikes');
$isOwner = $comment->commentLikes->search(function ($item, $key) {
return $item->user_id == auth()->user()->id;
});
return $isOwner === false ? false : true;
}
}
This way you can call $comment->has_liked which will return true if currently logged in user is in the relationship commentLikes or false if he isn't.

Use:
if ($comment->commentLikes()->where('user_id', auth()->user()->id)->count() > 0)
This is more efficient than other answers posted because both the where() and the count() applies on the query builder object instead of the collection

Related

Laravel filtering a hasMany relation

Background first on my question. A user hasMany contacts and a contact hasMany anniversaries. I want to filter the upcoming anniversaries. So far I have this:
$filtered = auth()->user()->contacts()->get()->each(function ($contact) {
$contact->anniversaries->filter(function ($anniversary) {
// return true or false based on a method on the anniversary model
return $anniversary->method() == true;
});
});
But this just returns all the contacts (obviously) with all their anniversaries, and I wish to exclude the ones that are false when calling the $anniversary->method().
Whatever is in the $anniversary->method() is not important, this just returns a true or false.
When I do the following, it works:
$collection = auth()->user()->anniversaries()->get();
$filtered = $collection->filter(function ($anniversary) {
return $anniversary->method() == true;
});
I get only the anniversaries from where the $anniversary->method() is indeed true.
My question is mainly, why does this happen, I only want to understand it, not so much need an answer on how to make it work. Thanks in advance for any insights!
In the first example, you are only filtering the anniversaries of each contact. You are not filtering the contacts directly per see.
$filtered = auth()->user()->contacts()->get()->each(function ($contact) {
// You are filtering only the anniversaries of each contact
$anniversaries = $contact->anniversaries->filter(function ($anniversary) {
return $anniversary->method() == true;
});
// over here you should get the same as in your second example
dd($anniversaries);
});
In your second example you are doing the following pseudo-code:
Fetch all anniversaries of each user
Filter the anniversaries that matches $anniversary->method() === true
To get the same results in the first example you would have to use a combination of filter with ->count()
$filtered = auth()->user()->contacts()->get()->filter(function ($contact) {
$filteredByMethod = $contact->anniversaries->filter(function ($anniversary) {
// return true or false based on a method on the anniversary model
return $anniversary->method() == true;
});
return $filteredByMethod->count() > 0;
});
Which one is more performant is beyond the scope of this answer.
Quick tip
The method filter from Laravel's collections needs to return a truthy value to be filtered by. Since your method returns true or false you can just call the method directly without comparing with true:
$collection = auth()->user()->anniversaries()->get();
$filtered = $collection->filter(function ($anniversary) {
return $anniversary->method();
});

Foreach with eloquent in laravel

I'm trying to loop through the items using eloquent in laravel but I'm getting 0. Please see my code below.
Model
Class Store{
public function products(){
return $this->hasMany('App\Product');
}
}
Controller
$products_count = 0;
foreach($store->products() as $product)
{
if($product->status == 1)
{
$products_count++;
}
}
dd($products_count);
Note: I have data in my database.
You can also use withCount method something like that
Controller
$stores = Store::withCount('products')->get();
or
$store = Store::where('id', 1)->withCount('products')->first();
WithCount on the particular status
$stores = Store::withCount(['products' => function ($query) {
$query->where('status', 1);
}
])
->get();
ref: withcount on relationship
That's because $store->products() returns an eloquent collection which doesn't contain the data from the database yet. You need to do $store->products instead.
If you need to get the count from the database then use
$store->products()->where('status', 1)->count()
With the function-annotation (i.e. products()) you are retrieving the \Illuminate\Database\Eloquent\Builder-instance, not the actual Eloquent-collection.
Instead, you would have to use $store->products – then you will get retrieve the related collection.
In Laravel $store->products() makes you access the QueryBuilder instance, instead there is the Laravel way of doing $store->products, which loads the QueryBuilder and retrieves the collection automatically and down the line is easy to optimise.

Laravel trying to check if the user has relationship with post

I have posts and these posts can be saved by users to read later. I created this relation and I can save or delete them easily. The problem is I can't check if the post is saved or not in frontend. Now I wrote some code to handle this but it doesn't seem to work. here is my controller code:
$articleFlag = 1;
$userID = Auth::User()->id;
if (count($bestarticles) > 0) {
foreach ($bestarticles as $bestarticle) {
$saveddata = DB::table('savearticle')->where('user_id', $userID && 'article_id', $bestarticle);
if (count($saveddata) > 0) {
$articleFlag = 1;
} else {
$articleFlag = 2;
}
} //foeach endes here
} //first if endes here
and than I pass the $articleFlag to the view than checking it's value with an if
But the problem is, no matter what I do if (count($bestarticles) > 0) returns true and I get value 1 in view.
Does anybody have any idea what I might be missing?
Here is my user controller relationshio:
function savedarticle(){
return $this->belongsToMany('App\User', 'savearticle', 'user_id',
'article_id');
}
and here goes the functions that i use for saving and deleting:
function savethearticle(Article $article){
$this->savedarticle()->syncWithoutDetaching([$article->id]);
}
function removethearticle(Article $article){
$this->savedarticle()->detach([$article->id]);
}
But there is nothing you need to worry about. I'm able to delete and add.
Or is there another way to check for existing relationship in view or a better way to check it in controller and pass into view?
I am using Laravel 5.4.
It looks as though you have a Collection of Article models, and you're trying to determine whether it is related to the User or not.
If that's the case, I would suggest eager loading the User relation when you originally query the Article models. This has the advantage of using one query to load the relationship, rather than one per Article.
$userId = Auth::id();
$articles = Article::with(['savedarticle' => function ($query) use ($userId) {
return $query->where('user_id' => $userId);
}])->get();
With this Collection, because we have loaded specifically the currently authenticated User, you can then proceed knowing that if the savedarticle relation has a count of 1, that the User relation exists.
foreach ($articles as $article) {
if ($article->savedarticle->count()) {
// User has already saved article
} else {
// User has not saved article
}
}
Should you not be passing the id of bestarticle in the Where clause? Also, it requires a ->get() to actually fire the request off to the database and run the query.
$saveddata = DB::table('savearticle')->where('user_id', $userID && 'article_id', $bestarticle);
Should be
$saveddata = DB::table('savearticle')->where('user_id', $userID && 'article_id', $bestarticle->id)->get();

Laravel Multiple Models Eloquent Relationships Setup?

I have 3 models
User
Pick
Schedule
I'm trying to do something like the following
$picksWhereGameStarted = User::find($user->id)
->picks()
->where('week', $currentWeek)
->first()
->schedule()
->where('gameTime', '<', Carbon::now())
->get();
This code only returns one array inside a collection. I want it to return more than 1 array if there is more than 1 result.
Can I substitute ->first() with something else that will allow me to to return more than 1 results.
If not how can I set up my models relationship to allow this to work.
My models are currently set up as follow.
User model
public function picks()
{
return $this->hasMany('App\Pick');
}
Schedule model
public function picks()
{
return $this->hasMany('App\Pick');
}
Pick model
public function user()
{
return $this->belongsTo('App\User');
}
public function schedule()
{
return $this->belongsTo('App\Schedule');
}
Since you already have a User model (you used it inside you find method as $user->id), you can just load its Pick relationship and load those Picks' Schedule as follows:
EDIT:
Assuming you have a schedules table and your picks table has a schedule_id column. Try this.
$user->load(['picks' => function ($q) use ($currentWeek) {
$q->join('schedules', 'picks.schedule_id', '=', 'schedules.id')
->where('schedules.gameTime', '<', Carbon::now()) // or Carbon::now()->format('Y-m-d'). See what works.
->where('picks.week', $currentWeek);
}])->load('picks.schedule');
EDIT: The code above should return the user's picks which have a schedules.gameTime < Carbon::now()
Try it and do a dump of the $user object to see the loaded relationships. That's the Eloquent way you want.
Tip: you may want to do $user->toArray() before you dump $user to see the data better.
EDIT:
The loaded picks will be in a form of Collections so you'll have to access it using a loop. Try the following:
foreach ($user->picks as $pick) {
echo $pick->schedule->gameTime;
}
If you only want the first pick from the user you can do: $user->picks->first()->schedule->gameTime
I think a foreach loop may be what you're looking for:
$picks = User::find($user->id)->picks()->where('week', $currentWeek);
foreach ($picks as $pick){
$pickWhereGameStarted = $pick->schedule()->where('gameTime', '<', Carbon::now())->get();
}
Try this and see if it's working for you

Retrieving relation of users and usermeta table from wordpress database using Eloquent

I am trying to access a user's first_name in my custom script which uses Eloquent to retrieve data (in Laravel 5 actually )
So,
Here is how i defined relationship (one to many ) // is that correct ?? Wp Guru may tell
In User Model, i have
public function usermeta() {
return $this->hasMany('App\Usermeta','user_id');
}
In my UserController I have
$users = \App\User::with('usermeta')->get();
And here how i access it in my views
#foreach ($users as $user)
<tr>
<th>{{$user->ID}}</th>
<th>{{$user->usermeta->/*how to access particular meta key here*/}}</th>
<th>{{$user->display_name}}</th>
</tr>
#endforeach
So the problem is, everything works except when i try to access the usermeta relation, I'm actually not sure how to query a particular meta key's value by passing meta_key as an argument either in my relation or in foreach loop
I tried directly accessing like $user->usermeta->first_name but that is incorrect for sure.
How can i retrive the meta_value from a usermata table in wordpress database using Eloquent Model?
Edit 1
trying the accessor method approach by #james-flight
https://stackoverflow.com/a/30871346/1679510
It works when i know the position of the record in collection object.
if ($usermeta->count() > 0) {
return $usermeta[0]->meta_value;
}
However, since the meta_key can be anything, and may reside at other position.
if the meta_key is first_name , then $usermeta[1] have the array of column values for it, and so on.
if ($usermeta->count() > 0) {
return $usermeta[/*This cannot be hard code */]->meta_value;
}
How to get it resolved
Usermeta is a hasMany relationship, which means Eloquent will return a Collection object containing multiple Usermeta models.
You could instead do this:
{{ $user->usermeta[0]->first_name }}
Or this:
#foreach($user->usermeta as $usermeta)
{{ $usermeta->first_name }}
#endforeach
Edit
To use meta_key and meta_value as a key value pair, you could write an accessor method on User:
public function getMetaValue($key) {
$usermeta = $this->usermeta->filter(function ($usermeta) use ($key) {
return $usermeta->meta_key === $key;
});
if ($usermeta->count() > 0) {
return $usermeta[0]->meta_value;
}
}
And then access in blade like so:
{{ $user->getMetaValue('first_name') }}
This will get slow at high volume though.
Edit 2
The above method should in fact be as follows, to ensure the array key exists:
public function getMetaValue($key) {
$usermeta = $this->usermeta->filter(function ($usermeta) use ($key) {
return $usermeta->meta_key === $key;
});
if ($usermeta->count() > 0) {
return $usermeta->first()->meta_value;
}
}

Categories