Getting all related fields to related field in Eloquent - php

I have this DB structure:
classroom_user is Elqouent many-to-many pivot.
User.php:
public function classrooms() {
return $this->belongsToMany(ClassRoom::class, 'classroom_user', 'classroom_id', 'user_id');
}
ClassRoom.php:
public function users()
{
return $this->belongsToMany(User::class, 'classroom_user', 'user_id', 'classroom_id');
}
I have a $user and want to write Eloquent method which gets all users who are in at least one of classrooms the $useralso is in. Something like $user->classrooms->users. But this falls with error Property [users] does not exist on this collection instance.. How can I do this?

I think you can do it like this:
$users = User::whereHas('classrooms', function($query) {
$query->whereHas('users', function($query) {
$query->where('id', auth()->user()->id);
});
})->get();
You could store this as a scope in your User model:
public function scopeClassmatesOf($query, $user)
{
$query->whereHas('classrooms', function($query) use($user) {
$query->whereHas('users', function($query) use($user) {
$query->where('id', $user->id);
});
})
}
And then call it from a controller like:
$user = auth()->user();
$users = User::classmatesOf($user)->get();

Your asking for users of a collection. $user->classrooms is a collection of classrooms.
If you do $user->classrooms->first()->users you will get all the users from the first classroom.
To get all users from all classrooms, you can do something like;
$users = $user->classrooms->map(function ($classroom) {
return $classroom->users;
});
Note that will return duplicate users and authenticated user him self witin the collection. So, you might need to do some filtering to the result.

This worked for me:
public function classmates() {
$self = $this;
$a = User::with('classrooms')->whereHas('classrooms', function ($query) use ($self) {
$query->whereHas('users', function ($query) use ($self) {
$query->where('users.id', $self->id);
});
});
return $a;
}

Related

How to fix the relationship problem of "Property [id] does not exist" problem

I have three model 1. Task.php 2. Project.php 3. User.php.
Task have a one to many relationship with user and project.php.
Task.php
public function project()
{
return $this->belongsTo(Project::class);
}
public function user()
{
return $this->belongsTo(User::class,'member_id');
}
User.php
public function tasks()
{
return $this->hasMany(Task::class);
}
Project.php
public function tasks()
{
return $this->hasMany(Task::class);
}
Nowi want to retrieve all the task that is associated with users where project id is one (Actually not one, id is passed through url).Here is my attempt
public function taskList($id)
{
$project=Project::with('tasks')->find($id);
$tasks=Task::has('user')->whereHas('project',function($project){
$project->where('id',$project->id);
})->get();
dd($tasks);
return view('leader.tasks',compact('project'));
}
In the above either i give the $id which is i get from the url either $project->id, it always through me the error.Please help me to solve this.
public function taskList($id)
{
$project=Project::with('tasks')->find($id);
$tasks=Task::has('user')->whereHas('project', function($query) use ($project) {
$query->where('id', $project->id);
})->get();
dd($tasks);
return view('leader.tasks',compact('project'));
}
You need to use with() method along with has()
public function taskList($id)
{
$project=Project::with('tasks')->find($id);
$tasks=Task::with('user')->has('user')->whereHas('project', function($query) use ($project) {
$query->where('id', $project->id);
})->get();
dd($tasks);
return view('leader.tasks',compact('project'));
}

Laravel how to get users by roles dynamically from api endpoint

How can I get the users based on which role they have in laravel? I have roles like for example "admin", "author", "editor" and I want to have a dynamic api-endpoint.
so in my api.php I have:
Route::get('users/{role}', "Api\UserController#role");
and my Controller looks like this:
public function show()
{
$user_role = User::whereHas(
'roles',
function ($q) {
$q->where('name', 'admin');
}
)->get();
return $user_role;
}
This works fine so far, but I want the endpoint to be dynamic, like if want all my editor users the endpoint should be api/users/editors etc. etc.
How can I achieve this?
public function show($role) //example: $role = 'admin'
{
return User::whereHas('roles', function ($q) use ($role) {
$q->where('name', $role);
})->get();
}
Your controller function should look like this:
public function show(Role $role)
{
$users = $role->users;
return $users;
}
And your Role Eloquent Model should have these methods:
public function users()
{
return $this->belongsToMany(User::class, 'user_role')
}
public function getRouteKeyName()
{
return 'name';
}

Laravel Eloquent deep nested query

I'm still learning Laravel and I can't find the solution for this problem.
I need to get invoices(with expenses) that are related to specific Partner Type.
I tried this:
$p = Project::with(['invoices.partner.partnerType' => function($query){
$query->where('partnerTypeName', 'Lieferant');
}, 'expenses'
])->where('id', $id)
->first();
I want to select invoices for Lieferant, but I get all invoices for one project.
Project Model:
public function invoices()
{
return $this->hasMany('App\Invoice');
}
Invoice Model
public function expenses()
{
return $this->hasMany('App\Expense');
}
public function partner()
{
return $this->belongsTo('App\Partner');
}
Partner Model
public function partnerType()
{
return $this->belongsTo('App\PartnerType');
}
Edit: PartnerType Model
public function partners()
{
return $this->hasMany('App\Partner');
}
Edit 2: Database
Partner(partnerID, name, partnerTypeId)
PartnerType(partnerTypeId, partnerTypeName)
Project(projectID, name)
Invoice(invoiceID, name, projectID, partnerID)
Expenses(expenseID, invoiceID)
If your models look like that.
Should be like :
$p = Project::with(['invoices' => function($query){
$query->where('partnerTypeName', 'Lieferant')
->with(['expenses','partner' => function($q){
$q->with('partnerType');
}]);
}])->where('id', $id)
->first();
return dd($p);
The solution to your problem is to update your query like this:
$p = Project::with(['invoices' => function($query){
$query->with('expenses')->whereHas('partner.partnerType', function($q){
$q->where('partnerTypeName', 'Lieferant');
});
}])
->where('id', $id)
->first();
But a cleaner solution would be using a scope for your problem.
In your Invoice model.
// Invoice.php
public function scopeByPartnerType($query, $partnerType)
{
$query->whereHas('partner.partnerType', function($q) use ($partnerType) {
$q->where('partnerTypeName', $partnerType);
});
}
And then in your Project model, add another relation that will just get Invoices with a particular partner type.
// Project.php
public function lieferantInvoices()
{
return $this->hasMany('App\Invoices')->byPartnerType('Lieferant');
}
Now you can do just this:
$project->find($id)->load('lieferantInvoices');

Laravel 5.1 constrain and eager load multiple nested relations

I have four models: OwnerCompany, Owner, User, and Role.
I want to get all OwnerCompanys eager loading their Owner and also eager loading its Users who have the Role with the name 'admin'.
OwnerCompany::with('owner.users')->whereHas('owner.users.roles', function ($query) {
$query->where('name', 'admin');
})->get();
This loads in the models but doesn't constrain the users, they are all loaded.
Not tested . I think you are missing like or equal operator.
OwnerCompany::with('owner.users')->whereHas('owner.users.roles', function ($query) {
$query->where('name','like','admin');
})->get();
I try this, if work then let me know. not tested
1).
OwnerCompany::with('owner.users.roles')->whereHas('owner', function ($query) {
$query->whereHas('users', function($qr){
$qr->whereHas('roles', function($q){
$q->where('name', 'admin');
});
});
})->get();
OR
2).
OwnerCompany::with('owner.users.roles')->whereHas('owner.users.roles', function ($query) {
$query->where('name', 'admin');
})->get();
If I got it right, you want each OwnerCompany object to contain the Owner object, which will contain "admins". I would do something like this.
$ownerCompany = OwnerCompany::all();
return $ownerCompany->each(function ($company) {
$company->owner;
$company->owner->users->each(function ($user) {
return $user->hasRole('admin');
});
});
and inside User class:
public function role()
{
return $this->belongsTo(Role::class);
}
public function hasRole($role)
{
if ($this->role()->where('name', $role)->first()) {
return $this;
}
return null;
}
Unfortunately, I can't test it right now, so If you have any trouble let me know.

Laravel 4.1 eager loading

I'm having trouble on the eager loading.
Let's say I have models of Members, TrainingCategory, TrainingCategoryResult and Registration
Member Model:
public function registration() {
return $this->hasMany('Registration', 'member_id');
}
public function trainingResults(){
return $this->hasMany('trainingResult', 'member_id');
}
public function trainingCategoryResults() {
return $this->hasMany('TrainingCategoryResult', 'member_id');
}
TrainingCategory Model:
public function trainings() {
return $this->hasMany('Training', 'id');
}
public function trainingCategoryResults() {
return $this->hasMany('trainingCategoryResult', 'category_id');
}
TraningCategoryResult Model:
public function category() {
return $this->belongsTo('TrainingCategory', 'id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
Registration Model:
public function course() {
return $this->belongsTo('Course', 'course_id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
I am trying to eager load all the registration info and its related info including the TraningCategoryResult info but I not sure how to get that TraningCategoryResult which required two foreign keys (category_id and member_id), is there any way to do that?
Here is my code atm:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
});
$members= $members
->with('registration.course',
'registration.course.traningCategories',
->get(['member.id']);
Thank you.
This will not work Member::with('categoryResult')->with('registration')->get()
You can make a new relation in Member Model
public function categoryResult()
{
return $this->belongsTo('Category')->with('Registration');
}
//and then call
Member::with('categoryResult')->get();
You could use a few options to achieve that:
OPTION 1: create a variable relationship
Change your relation in the Member model
public function trainingCategoryResults($category_id = null) {
if(empty($category_id))
return $this->hasMany('TrainingCategoryResult', 'member_id');
else
return $this->hasMany('TrainingCategoryResult', 'member_id')
->where('category_id', $category_id);
}
The code above might have limitations and it doesn't take advantage of many laravel features, but it will work.
OPTION 2: Access from relationship
You can keep everything as is, and load as follow:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
})
->where('id', $member_id) // set the id of the memeber
->with(array(
'traningCategoryResults' => function($q)use($category_id){
$q->where('category_id', $category_id); // This makes sure you get only desired results
}
))
In this way you will have only what you need, assuming you know the $category_id

Categories