Use Eloquent/Builder instance in other Eloquent Query - laravel-5

Is it possible to use a Eloquent/Builder Instance in an other Eloquent Query?
For example, if I have this query:
$users = User::whereHas('posts', function($query) { $query->where('great_post', true); })->get();
Can I somehow split in two parts like this?
$postsQuery = Posts::where('great_post', true);
$users = User::where('posts', $postsQuery)->get(); // not working

You can do like that:
$postsQuery = function($query) { $query->where('great_post', true);};
$users = User::where('posts', $postsQuery)->get();
But there is other way called Local Scopes in Laravel and I recomment you use it if this subquery can be reused again in other queries.
For example:
class User extends Model
{
public function scopeHasPosts($query)
{
return $query->whereHas('posts', function($subquery) {
$subquery->where('great_post', true); });
}
}
then call it like this:
$users = User::hasPosts()->get();

Related

How to use custom model function in eloquent

I want to get all user's online friends, how can I call a custom model function inside the eloquent condition?
this is my code
$friends = $user->friends()->where(function (Builder $query){
$query->where('friend', 'yes');
})
->get();
and this is my function in model
public function getIsOnlineAttribute(): bool
{
// check if the user is online or not
return $this->is_online;
}
I can access is_online after eloquent by foreach, but in my case, I want to check everything in one step ( inside where condition in eloquent). how can I do that???
You can't use conditions for eloquent accessors, in this case you can use (assume 1 is database column value):
$friends = $user->friends()->where('is_online', 1)->get();
or
$friends = $user->friends()->whereIsOnline(1)->get();
or you can create eloquent scope on your model:
public function scopeIsOnline($query) {
$query->where('is_online',1);
}
and you can use this eloquent scope on your controller in this way:
$friends = $user->friends()->isOnline()->get();
this worked for me :)
$friends = $user->friends()
->simplePaginate()
->reject(function ($friend) {
return $friend->is_online === false;
});

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 5.2 if else to query database

stuck on a form that allows the user to enter a value into a choice of two fields. I can query the database using one field but want to add more range to database queries. With the following code below when i try to access the page to query it just shows me a white screen.
public function index()
{
$data = $request->all();
if(!empty($data['pstoreNum']))
{
$pstoreNum = $data['pstoreNum'];
$result = DB::table('perfumes')->where('StoreNumber','=',$pstoreNum)
->get();
return view('perfumes',compact('result'));
}
else if(!empty($data['pweekNum']))
{
$pweekNum = $data['pweekNum'];
$result = DB::table('perfumes')->where('WeekNumber','=',$pweekNum)
->get();
return view('perfumes',compact('result'));
}
}
My routes file simple calls the index function. Any help would be appreciated.
You can add query functions within your query like so
public function index(Request $request)
{
$data = $request->all();
$result = \DB::table('perfumes')->where(function($query) use ($data) {
if(!empty($data['pstoreNum'])) {
$query->where('StoreNumber', '=', $data['pstoreNum']);
}
if(!empty($data['pweekNum'])) {
$query->where('WeekNumber', '=', $data['pweekNum']);
}
})->get();
return view('perfumes',compact('result'));
}
You can then use the one query and add multiple wheres on various conditions.
https://laravel.com/docs/5.2/queries#advanced-where-clauses

Eloquent where condition based on a "belongs to" relationship

Let's say I have the following model:
class Movie extends Eloquent
{
public function director()
{
return $this->belongsTo('Director');
}
}
Now I'd like fetch movies using a where condition that's based on a column from the directors table.
Is there a way to achieve this? Couldn't find any documentation on conditions based on a belongs to relationship.
You may try this (Check Querying Relations on Laravel website):
$movies = Movie::whereHas('director', function($q) {
$q->where('name', 'great');
})->get();
Also if you reverse the query like:
$directorsWithMovies = Director::with('movies')->where('name', 'great')->get();
// Access the movies collection
$movies = $directorsWithMovies->movies;
For this you need to declare a hasmany relationship in your Director model:
public function movies()
{
return $this->hasMany('Movie');
}
If you want to pass a variable into function($q) { //$variable } then
function($q) use ($variable) { //$variable }
whereBelongsTo()
For new versions of Laravel you can use whereBelongsTo().
It will look something like this:
$director = Director::find(1);
$movies = Movie::whereBelongsTo($director);
More in the docs.
is()
For one-to-one relations is() can be used.
$director = Director::find(1);
$movie = Movie::find(1);
$movie->director()->is($director);

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