Laravel trying to check if the user has relationship with post - php

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();

Related

Build database query in Laravel with eloquent or DB

I need your help to build a query in Laravel either eloquent or DB query would do too.
My table name is Users
To see the DB structure, open the following link:
https://jsfiddle.net/vardaam/mvqzpb2j/
Every user row has 2 columns referral_code and referred_by_code which means every user can refer to someone and earn bonus similarly the same user was also been referred by some one.
I would like to return the information on page with loop in users details along with Username of the user who had referred him to this. To track the same I created those 2 columns in the same table i.e.: referral_code and referred_by_code.
I do not know how to write this in 1 query or how to combine 2 queries and get the desired results.
My controller code looks like below:
$obj_users = User::get();
$codes = [];
$referrers = [];
foreach( $obj_users as $referred_by_code )
{
//Following fetches all user's referred_by_code's code
$codes[] = $referred_by_code->referred_by_code;
}
foreach ($codes as $code)
{
//Following fetches usernames of the given referred_by_code's codes
$referrers[] = User::where('referral_code', $code)->first()->username;
}
return view('users.users', compact(['users', 'paginate', 'referrers']));
The returning $users variable provides me loop of users data but I do not know how to attach those referrer's username to that object.
I tried my level best to describe, please ask incase what I said doesn't make sense, will be happy to provide further clarification.
Best
You can add into your User model the following relationship:
public function referredBy()
{
return $this->belongsTo(User::class, 'referred_code', 'referral_code');
}
In your controller you can use:
$users = User::with('referredBy')->get();
return view('users.users', compact('users'));
and later in your view you can use:
#foreach ($users as $user)
{{ $user->username }} referred by {{ $user->referredBy ? $user->referredBy->username : '-' }}
#endforeach

Check if collection contains a value

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

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

How to get a list of posts and check if the user already "Liked" them? (Check existing relation between two models)

I'm having fun with Laravel framework trying to build a little "blog" site that works the following way:
When you enter the webpage, a cached index of the latest / most popular posts is shown
There is a ManyToMany Relationship "user_likes" between the User and Post models, so that if you're logged in then you can "Like" or "upvote" each of these posts with a "heart" button, so that a relation between the two models will be created in the user_likes pivot table.
I have two database tables
users table:
user_id name
1 TheUser
posts table:
post_id title
1 MyPost
2 Another Post
3 Yet another post
user_likes pivot table:
post_id user_id
1 1
3 1
And the User Model Class:
class User extends BaseUser {
protected $table = 'users';
public function likes()
{
return $this->belongsToMany('Post', 'user_likes','user_id','post_id');
}
}
The question is, what's an efficient way of retrieving a list of Post models and checking if the logged in User has already liked / upvoted them?
The thing is that i'd like to check for every Post if the relation between the logged in User and the Post model exists in the most efficient way.
Thanks in advance!
EDIT:
This SQL Fiddle would be a way of achieving what I'd like to do, the problem is that If i'm not wrong, I won't be able to cache the posts, as I'll need to check them every time a new user logs in.
http://www.sqlfiddle.com/#!2/e5bab/2
Using Laravel's Query builder:
DB::table('posts')
->leftJoin('user_likes', function($join) {
$join->on('user_likes.post_id', '=', 'posts.id')
->where('user_likes.user_id', '=', 1);
})
->select('posts.id as post_id', 'posts.title', 'user_likes as did_i_like')
->groupBy('posts.id')
->orderBy('posts.id');
Right now, I'm doing it in my application in a different way:
I have the paginated posts cached, and then each User has a cached collection of the posts ids that they liked, so when they log in, I'll check if each post is in the user's liked post collection:
$liked = Auth::user()->getLikedPosts(); // returns a cached collection of the User liked posts ids
$posts = Post::popular(1); // returns a cached and paginated index of the most popular posts.
Then, I'll check if the liked collection contains the post id:
foreach($posts as $post)
{
.......
if($liked->contains($post->id)
{
// show red Heart
}
else
{
// show gray heart
}
.......
I think It's not a good way of doing it, since the $liked collection will be growing a lot... However, with the new Query, I really don't know how could I cache the posts, so that I don't have to query the Database each time a user logs in or navigates throught the posts pages.
Thanks in advance!
I am honestly not sure if it's good or not, but I did it like this:
Post Model:
public function likes()
{
return $this->hasMany('Like');
}
public function likedByUser()
{
return $this->likes()->where('user_id', Auth::user()->id);
}
than in blades:
#if(isset($post->likedByUser[0]))
style="background-position: right;" data-value="liked"
#endif
I don't much about speed, but I'm paginating 9-12 each time, so It's not that bad, I hope :)
What's an efficient way of retrieving a list of Post models and
checking if the logged in User has already liked / upvoted them?
in your Post model declare a relationship:
public function likedByUser()
{
return $this->belongsToMany('User', 'user_likes', 'post_id', 'user_id')
->where('user_id', Auth::user()->id);
}
Then retrieve posts which has been liked by the logged in user like this:
$posts = Post::has('likedByUser')->get();
Update:
$posts = Post::get();
$firstPost = $posts->first();
$firstPost->has('likedByUser');
Also you may loop and check:
$posts = Post::get();
foreach($posts as $post) {
if($post->has('likedByUser')) {
// liked it
}
}

Laravel 4 whereIn and many to many

I have a tag system, where you can add tags to photos and users.
I have a function where the users are able to add their favorite tags, and select images based on those tags
But my problem i am a really big beginner with php and laravel and i do not know how to pass the values to the whereIn function
Model
public function tag()
{
return $this->belongsToMany('Tag', 'users_tag');
}
Controller
// get the logged in user
$user = $this->user->find(Auth::user()->id);
// get tags relation
$userTags = $user->tag->toArray();
// select photos based on user tags
$photos = Photo::whereHas('tag', function($q) use ($userTags)
{
$q->whereIn('id', $userTags);
})->paginate(13);
$trendyTags = $this->tag->trendyTags();
$this->layout->title = trans('tag.favorite');
$this->layout->content = View::make('main::favoritetags')
->with('user', $user)
->with('photos', $photos)
->with('trendyTags', $trendyTags);
When i pass i get an error
preg_replace(): Parameter mismatch, pattern is a string while replacement is an array
than i tried to use array_flatten() to clean my array
// get the logged in user
$user = $this->user->find(Auth::user()->id);
// get tags relation
$userTags =array_flatten($user->tag->toArray());
// select photos based on user tags
$photos = Photo::whereHas('tag', function($q) use ($userTags)
{
$q->whereIn('id', $userTags);
})->paginate(13);
$trendyTags = $this->tag->trendyTags();
$this->layout->title = trans('tag.favorite');
$this->layout->content = View::make('main::favoritetags')
->with('user', $user)
->with('photos', $photos)
->with('trendyTags', $trendyTags);
This way it works but not returning the correct tags.
Could please someone could lend me a hand on this?
Sure thing and I'll make a couple recommendations.
To get the user model, you simply have to use $user = Auth::user().
To use whereIn(), it's expecting a 1 dimensional array of user id's. The toArray() function is going to return an array of associative arrays containing all the users and their properties, so it's not going to work quite right. To get what you need, you should use lists('id').
And one last thing that has really helped me is when you are setting up a relation that's going to return a collection of objects (hasMany, belongsToMany()), make the relation name plurual, so in this case you would modify your tag() function to tags().
So with all that in mind, this should work for you.
// get the logged in user
$user = Auth::user();
// get tags relation
$userTags = $user->tags()->lists('id');
// select photos based on user tags
$photos = Photo::whereHas('tags', function($q) use ($userTags)
{
$q->whereIn('id', $userTags);
})->paginate(13);
$trendyTags = $this->tags->trendyTags();
$this->layout->title = trans('tag.favorite');
$this->layout->content = View::make('main::favoritetags')
->with('user', $user)
->with('photos', $photos)
->with('trendyTags', $trendyTags);
And I'd suggest to modify your relation to... though not hugely important.
public function tags()
{
return $this->belongsToMany('Tag', 'users_tag');
}

Categories