How to improve where clause condition with unique of two columns combined? - laravel

I have two tables of User(id, name, ...) and friends(id, user_id, friend_id). I would like to check the relationship if users are already friends. But I feel like it could have done better. Please advise, thank you.
With the below function, I can already is user_a is a friend with user_b regarding who added who.
public function isFriend($friend_id) {
$isFriend = false;
$isFriend = Friend::where('user_id', auth()->id())
->where('friend_id', $friend_id)->exists();
if(!$isFriend)
$isFriend = Friend::where('friend_id', auth()->id())
->where('user_id', $friend_id)->exists();
return $isFriend;
}

I removed $isFriend = false; Here is my data:
id
user_id
friend_id
1
1
2
public function hasFriendship($friend_id) {
return Friend::where(function($query) use ($friend_id)
{
$query->where('user_id', auth()->id())
->where('friend_id', $friend_id);
})
->orWhere(function($query) use ($friend_id)
{
$query->where('friend_id', auth()->id())
->where('user_id', $friend_id);
})
->first();
}

Related

Different relation by condition

I have the table followers, with:
id, user_id, follower_id, type
type = type of follow, if follow user = 0, page = 1, group = 1
I use the user_id to put the page_id and group_id too.
Now is the problem, I want to make different relations if type is different... If type = 0, will relate with users table and share table, if type = 1, will relate with pages table...
I'm try like this:
Model:
public function page_links()
{
return $this->hasMany(Link::class, 'page_id', 'user_id')->Select('links.id', 'links.title', 'links.photo', 'links.country', 'links.friendly_url', 'links.clicks', 'links.description', 'links.suggestions', 'links.count_comments', 'links.url', 'links.shares', 'links.page_id', 'links.tag_id', 'links.created_at')->where('sponsored', 0)->where('scheduled', 0)>where('status', 1)->take(3)->orderBy('id','desc');
}
public function user_links()
{
return $this->hasMany(Share::class, 'user_id', 'user_id')->Select('id', 'link_id', 'user_id', 'shared_in', 'content', 'created_at')->take(3)->orderBy('id', 'desc')->where('type', '=', 0);
}
public function scopeProfile($query) {
return $query
->when($this->type == 0, function($q){
return $q->with('user_links');
})
->when($this->type == 1, function($q){
return $q->with('page_links');
})
->when($this->type == 2, function($q){
return $q->with('group_links');
});
}
Controller:
$feed = Feed::Profile()->where('follower_id', auth()->user()->id)
->take(10)
->get();
But ALL, even the type 1 returns "user_links" relation. I don't know if the relation is correct...
Someone can help me?
Well, in my point of view, you should modify your migration.
Instead of have your table with :
id, user_id, follower_id, type
I'll do this :
id, user_id, page_id, group_id, follower_id, type
Don't do weird stuffs like that in your database, just add 2 fields and / or relations in your migration table. Set it to unsigned() AND nullable(), this way you'll be able to know quickly if there is a relation or not with each one of your page or group, and you won't have to make weird stuff to check for it :D

Laravel 5 - Use 'isAdmin' role check method when querying a model

I have implemented a basic role system that uses a table 'role_user'.
On my user model I have a few methods that check the roles, one of them is:
public function isStaff()
{
foreach ($this->roles()->get() as $role)
{
if ($role->id == 3)
{
return true;
}
}
return false;
}
How can I use this method when I am querying users?
This query here:
return User::where('name', 'like', "%".$request->name."%")
->orWhere('email', 'like', "%".$request->name."%")
->whereDoesntHave('Teams', function ($query) use($teamId) {
$query->whereId($teamId);
})
->with('teams')
->get();
Currently returns all users, but I only wish to return users that have a role of 3 (isStaff)
You can using Scopes With Laravel instead of multiple methods to check for different methods.
public function scopeRole($query, $flag)
{
return $query->where('role', $flag);
}
and then
$users= User::role(3)->get();
check the reference tutorial for Creating Dynamic Scopes
it's better to do condition
return User::where('name', 'like', "%".$request->name."%")
->orWhere('email', 'like', "%".$request->name."%")
->whereDoesntHave('Teams', function ($query) use($teamId) {
$query->whereId($teamId);
})
->whereHas('roles', function($q) use ($role_id){
$q->where('id',$role_id);
})
->with('teams')
->get();
or also you can create a method for above query and based on param reurn result
You can have a scope called staff in your User model, then use that to narrow down your result:
public function scopeStaff($query, $roll_id = 3)
{
return $query->where('role_id', '=', $roll_id)
}
So when checking (with the model) for staff roles, you can improve the function that does that:
public function isStaff($role_id = 3)
{
return $this->role_id = $role_id ? $this : false;
}
Therefore, when using the query builder you can use the first method to narrow the result to those with the specified id, as you can see the default is 3 but will change to any value you give:
$staff_users = User::staff()->get();
Then the other one for verifying if a matched user model is a staff:
$user = User::find(1);
$is_staff = $user->isStaff(); //false or returns the same model
Hope this helps

Laravel include relationship result if one exists

I am trying to write a query where all items are returned (products) and if a relationship exists for that particular item (many to many) then that information is included too. When I include the relationship at the moment on the query it only returns items that have that relationship rather thatn every single item, regardless of whether that relationship exists or not.
Here is my query at the moment:
public static function filterProduct($vars) {
$query = Product::query();
if((array_key_exists('order_by', $vars)) && (array_key_exists('order', $vars))) {
$query = $query->orderBy($vars['order_by'], $vars['order']);
}
if(array_key_exists('category_id', $vars) && $vars['category_id'] != 0) {
$query = $query->whereHas('categories', function($q) use ($vars) {
return $q->where('id', $vars['category_id']);
});
}
if(array_key_exists('manufacturer_id', $vars)) {
$query = $query->whereHas('manufacturer', function($q) use ($vars) {
return $q->where('id', $vars['manufacturer_id']);
});
}
$query = $query->whereHas('options', function($q) use ($vars) {
});
As you can see, when an item has the 'options' relationship I need to have that particular row include details of that relationship in the returned date. With the code as it is though it is only returning items that have this relationship rather than every single item.
Can someone advise me as to how this is achieved please?
Thanks!
I feel a bit stupid as it was so simple but it was solved by adding this:
$query = $query->with('options');

combining 2 many to many queries in Laravel Eloquent

I have the following tables:
occupations <- occupation_user -> users
occupations <- occupation_vacancy -> vacancies
And I want to find all vacancies that the current user shares occupations with...
I have it working by querying the occupation_user table to retrieve the users occupations and then using whereIn with the resulting array on the vacancies table.
I have a nagging feeling there may be a better way but I can't see it?
Can anyone advise?
public function scopeFilteredForUser($query, $user_id, $university_id) {
$query->with('occupations')->select('id','university_id','title','employer_name','remuneration','city','state','country','commencement_date','num_positions','expire','contract_type','contract_hours')
->whereDoesntHave('users', function($q) use($user_id) {
$q->where('user_id', $user_id);
})
->withOccupationsFilter($user_id);
}
public function scopeWithOccupationsFilter($query, $user_id) {
$user_occupations = DB::table('occupation_user')
->select('occupation_id')
->where('user_id', '=', $user_id)
->lists('occupation_id');
if (empty($user_occupations)) {
return $query;
}
return $query->whereIn('id', function ($query) use ($user_occupations)
{
$query->select('vacancy_id')
->from('occupation_vacancy')
->whereIn('occupation_id', $user_occupations);
});
}

Where NOT in pivot table

In Laravel we can setup relationships like so:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Allowing us to to get all items in a pivot table for a user:
Auth::user()->items();
However what if I want to get the opposite of that. And get all items the user DOES NOT have yet. So NOT in the pivot table.
Is there a simple way to do this?
Looking at the source code of the class Illuminate\Database\Eloquent\Builder, we have two methods in Laravel that does this: whereDoesntHave (opposite of whereHas) and doesntHave (opposite of has)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
this works correctly for me!
For simple "Where not exists relationship", use this:
User::doesntHave('Role')->get();
Sorry, do not understand English. I used the google translator.
For simplicity and symmetry you could create a new method in the User model:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
To use call:
Auth::user()->availableItems();
It's not that simple but usually the most efficient way is to use a subquery.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
If this was something I did often I would add it as a scope method to the Item model.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Then use that later like this.
$items = Item::whereNotRelatedToUser($user_id)->get();
How about left join?
Assuming the tables are users, items and item_user find all items not associated with the user 123:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();
this should work for you
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);
Ended up writing a scope for this like so:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
And then call:
Items::avail()->get();
Works for now, but a bit messy. Would like to see something with a keyword like not:
Auth::user()->itemsNot();
Basically Eloquent is running the above query anyway, except with a = instead of a <>.
Maybe you can use:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Source: http://laravel.com/docs/4.2/queries#advanced-wheres
This code brings the items that have no relationship with the user.
$items = $this->item->whereDoesntHave('users')->get();

Resources