How to find inverse of Eloquent query - laravel

I've got a query to find enrolled students in a particular activity. On the User model:
public function enrolledStudents($activity)
{
$students = $activity->students()
->wherePivot('user_id', $this->id)
->get();
return $students;
}
Where the Activity model's students method is this:
public function students()
{
return $this->belongsToMany('Student', 'activity_student', 'activity_id', 'student_id')
->withPivot('user_id')
->withTimestamps();
}
I want another method to find the students who aren't enrolled in this activity - how could I go about this?
I.e. $user->students()->notEnrolled($activity)

Basically, you'd have to come from the Student angle. Something like this:
$students = Student::whereDoesntHave('activities', function($q) use ($activity){
$q->where('activity_id', $activity->id);
})->get();
Note that this method is quite new, so you might need to update Laravel with composer udpate

Related

Laravel Eloquent is there a better way to write this query?

I have a typical pivot table structure like this:
Users
id [...]
Locations
id [...]
User_Location
id | user_id | location_id
I need to get the locations the current authorized user has access to, and then I need to get all the users who also have access to all of those locations.
I tried to figure out an "eloquent" way to do this, but I'm not familiar enough with it. This works, but I'm wondering if it's the best way to do it?
$locations = auth()->user()->locations(); //returns the user_location records
$locationIds = $locations->pluck('location_id');
$locationUsers = new UserLocation();
$userIds = $locationUsers->whereIn('location_id', $locationIds)->groupBy('user_id')->pluck('user_id');
$users = User::withTrashed()
->whereIn('id', $userIds)
->get();
return view('users.index')->with('users', $users);
here's the locations() relationship referenced in the code:
public function locations()
{
return $this->belongsToMany(Location::class, 'user_location')->withPivot('primary');
}
You must create a new method in the Locations model.
public function users()
{
return $this->belongsToMany(User::class, 'user_location');
}
Then your query could look like this.
$locations = auth()->user()->locations()->with('users')->get();
$users = $locations->pluck('users');
If you need to get all users withTrashed then you should modify the first line for this.
$locations = auth()->user()->locations()->with(['users' => function ($user) {
$user->withTrashed();
}])->get();

Laravel: sort query results based on field of nested relationship

I have two models with relations as defined below
Order
public function owner()
{
return $this->belongsTo(User::class, 'owner_id');
}
User
public function company(){
return $this->belongsTo(Company::class, 'company_id');
}
company table have 'title' field.
what I want is to get all the orders sorted/order by company title. I've tried different solution but nothing seems to work. Any help or hint would be appreciated.
Recent solution that I tried is
$query = OrderModel::whereHas('owner', function($q) use ($request){
// $q->orderBy('owner');
$q->whereHas('company',function ($q2) use ($request){
$q2->orderBy('title',$request->get('orderByDirection') ?? 'asc');
});
});
but I am not getting user and company relation in query results. also the result remains same for 'ASC' and 'DESC' order.
You could sort the query after adding join like:
return Order::join('users', 'users.id', '=', 'owner_id')
->join('companies', 'companies.id', '=', 'users.company_id')
->orderBy('companies.title')
->select('orders.*')
->get();
You can define new relations in User and Company models.
User
public function orders()
{
return $this->hasMany(Order::class);
}
Company
public function users()
{
return $this->hasMany(User::class);
}
Now you can fetch companies that are in asc order and with the use of relation, you can fetch users and orders. So the ORM like be,
$companies = Company::with('users.orders')->orderBy('title', 'ASC')->get();
So these are the company-wise orders. You can use this too.

hasMany and belongsTo in laravel

I have a Student in the users table, Parent is in the same table, and that Parent is the parent of that Student.
The Student has a Schedule in the schedules table.
How I can write hasMany and belongsTo to get the proper relation like in following custom query which works fine:
$schedules = DB::table('users')
->join('schedules', 'users.id', '=', 'schedules.studentID')
->select('users.*', 'schedules.*', 'users.fname as fname', 'users.lname as lname')
->where('users.parent_id',$request->id)
->where('schedules.status','1')
->where('schedules.status_dead','0')
->whereIn('schedules.std_status',[1, 2])
->get();
As shown in the image below:
Before the relationship lets create parent scope and find student more elegant way
User Model
public function scopeByParent($query,$parentId){
return $query->where("parent_id",$parentId);
}
Above scope provide us to get user or users by parent id.
Then create relationships.
User Model
public function schedules(){
return $this->hasMany("App\Schedule","studentID","id");
}
Schedule Model
public function users(){
return $this->belongsTo("App\User","id","studentID");
}
Then lets create our query using above scope and relation.
User::with(["schedules" => function ($query) {
$query->whereStatusAndStatusDead(1, 0)
->whereIn('std_status', [1, 2]);
}])
->byParent($request->id)
->get();

Laravel eloquent get data from two tables

Laravel Eloquent Query builder problem
Hello I have a problem when I am trying to get all the rows where slug = $slug.
I will explain in more details:
I have two tables, cards and card_categories.
cards has category_id.
card_categories has slug.
What I need is a query which returns all the cards which contents the slugs.
For example I made this:
$cards = Card::leftJoin('card_categories', 'cards.id', '=', 'card_categories.id')
->select('cards.*', 'card_categories.*')
->where('card_categories.slug', $slug)
->paginate(5);
But what happens is that just return 1 row per category.
I don't know what is wrong.
Many thanks.
I think I understand what you mean, from your explanation I would imagine your card model is as follows.
class Card extends Model {
protected $table = 'cards';
public function category()
{
return $this->belongsTo(Category::class)
}
}
In which case, you should just be able to do this:
$cards = Card::whereHas('category', function ($query) use ($slug) {
$query->where('slug', $slug);
})->paginate(5);
That will select all of the cards that has the category id of the given slug.

Laravel database relations - get all children from more than one parent

I have users and books.
User model:
public function books() {
return $this->hasMany('Books');
}
I can do the following:
$user = User::find(1);
$books = $user->books;
Now, I want to get all books from several users with the name Brian.
So what I did is:
$users = User::where('name', 'Brian')->get();
$books = $users->books;
Of course this does not work because books() is a method of a user and not of a group of users.
How can I can all books from all users named Brian? I could loop through all Brians but that does not seem best practice.
How could I do this?
This is the perfect spot for a whereHas call:
Give books a user relationship, then simply do:
Book::whereHas('user', function($q) {
$q->whereName('Brian');
})->get();

Resources