Eloquent querying relation based on main query - laravel

I have 4 tables:
Users with column id
Teams with column id
Roles with column id
Pivot teams_users with columns team_id user_id role_id
Goal: get teams, each team has members. Each member has a role in that team.
My approach:
Fetch teams, then fetch members and roles of that team. Loop the collection, add the role to the correct member, delete the role after.
$teams->each(function($team, $teamKey) use ($teams) {
if(empty($team->members) === false && empty($team->roles) === false) {
$team->members->each(function($member, $memberKey) use ($team) {
$team->roles->each(function($role) use ($member) {
if($member->id === $role->pivot->user_id) {
$member->role = $role;
}
});
});
}
});
My goal:
I want to do it using Eloquent and without looping the collection.
My Team model has two relations:
public function members() {
return $this->belongsToMany(User::class, "teams_users", "team_id", "user_id")->withPivot("role_id")->withTimestamps();
}
public function roles() {
return $this->belongsToMany(Role::class, "teams_users", "team_id", "role_id")->withPivot("user_id")->withTimestamps();
}
expected output should be like this:
{
teams: [
{
id: 1,
title: "Awesome team",
members: [
{
id: 1
name: "Test",
role: {
id: 1,
title: "Admin"
}
}
]
}
]
}
Your help is much appreciated.

Related

How to Query Multiple Pivot Relationship in Laravel Lighthouse

Hi, there I'm fairly new to laravel-lighthouse. I've read the documentation but unfortunately, there is no detail about this issue. My question is How can I query more than one pivot table. I have an Item table that belongs to many other Models.
The code is given below.
class Item extends Model
{
public function provisions(): BelongsToMany
{
return $this->belongsToMany(Pwmp::class,
'project_wise_material_provision_items', 'item_id', 'provision_id')
->withPivot('qty', 'unit_cost')
->withTimestamps()
->as('provision_items');
}
public function procurements(): BelongsToMany
{
return $this->belongsToMany(Pwpp::class,
'project_wise_procurement_plan_items', 'item', 'procurement')
->withTimestamps()
->as('procurement_items')
->withPivot('qty', 'unit_cost');
}
public function log_sheets(): BelongsToMany
{
return $this->belongsToMany(Braols::class,
'bid_receiving_and_opening_log_sheet_items', 'item', 'braols')
->withTimestamps()
->as('log_sheet_items')
->withPivot('qty', 'unit_cost', 'tax');
}
public function workshop(): BelongsToMany
{
return $this->belongsToMany(TransformerWorkshop::class,
'transformer_workshop_items', 'item', 'workshop')
->as('workshop_items')
->withTimestamps()
->withPivot('qty', 'flow', 'type');
}
public function sub_office(): BelongsToMany
{
return $this->belongsToMany(MaterialReceiptInSubOffice::class,
'material_receipt_in_sub_office_items', 'item', 'receipt')
->as('sub_office')
->withTimestamps()
->withPivot('id','qty', 'type');
}
Here is my GraphQL schema
type Item{
id: ID!
workshop_items: [TransformerWorkShopItemsPivot]
provision_items: [ProjectWiseMaterialProvisionItem]
sub_office: MaterialReceiptInSubOfficeItemsPivot
}
type MaterialReceiptInSubOfficeItemsPivot{
qty: Int
type: Int
id: ID
}
type ProjectWiseMaterialProvisionItem {
qty: String
unit_cost: String
}
type TransformerWorkShopItemsPivot{
qty: Int
type: Int
flow: Int
}
Now when i query the api
```graphql
material_receipt_in_sub_office_store(id: 4){
id
items{
id
provision_items{
unit_cost
qty
}
sub_office{
type
id
qty
}
}
}
}
```
it returns the following result
{
"data": {
"material_receipt_in_sub_office_store": {
"id": "4",
"items": [
{
"id": "431",
"name": "Drill Machine",
"image": "crane2.jpg",
"category_id": {
"id": "993"
},
"provision_items": null,
"sub_office": {
"type": null,
"id": null,
"qty": null,
"__typename": "MaterialReceiptInSubOfficeItemsPivot"
}
},
I am unable to fetch the multiple pivot table data.
however, if I query pivot it returns the data of only one pivot.
First, it looks like you don't use Laravel model's relationships into your type definition.
By specifying a #belongsToMany / #hasMany directive (see more here) you'll be able to optimize your queries.
type Item{
id: ID!
workshop_items: [TransformerWorkShopItemsPivot] #hasMany(relation: "workshop")
provision_items: [ProjectWiseMaterialProvisionItem] #hasMany(relation: "provisions")
sub_office: MaterialReceiptInSubOfficeItemsPivot #hasMany
}
I'm just not sure about the fact you give table aliases in your relation definition..
Then, by doing the query, you can fetch as much pivot relations as you want. Never got relation problems by doing this.

Laravel: Get all projects and check if user has liked them

I want to get all projects, and foreach project I want to get a property for example is_liked which indicates that if the current_user (I've his Id) has liked this project or not.
User Model
class User extends Model
{
public function projects()
{
return $this->hasMany(Project::class);
}
public function favorite_projects()
{
return $this->belongsToMany(Project::class, 'favorite_projects', 'user_id', 'project_id')->withTimestamps();
}
}
Project Model
class Project extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
User Table
- id
- name
Project Table
- id
- user_id
- title
favorite_projects table
- user_id
- project_id
What is the best way to get this done ? the data I want to get is something like this:
[
{
"id": 1,
"user_id": 3,
"title": "my title",
"is_liked": true
}
]
Note: the current_user->id might or might not be same as the project->user_id.
$projects = DB::table('projects')
->join('favorite_projects', 'favorite_projects.project_id', '=', 'projects.id')
->select('projects.*', 'favorite_projects.*')
->where('projects.user_id', Auth::id())
->get();
This join statement allows you to join 2 tables together and for each project that is being favorited by the user, you will see the favorite record attached with the record.
Perform a dd($projects) after that SQL query and see what the result is like, and then for each result, you set $project['is_liked'] accordingly.

Multiple Relationship Laravel - Object in Object

I want use Laravel Eloquent to do relationship, but I have a problem accessing a specific filtered object in the relationship.
My objects:
courses:
id - integer
name - string
contents:
id - integer
name - string
course_contents:
id - integer
course_id - integer
content_id - integer
I want get the contents by the course. Until now I can only filter the course_contents to filter contents
My controller:
Course::hasContents()->find($id);
Course Model
public function contents()
{
return $this->hasMany('App\CourseContent');
}
public function scopeHasContents($query)
{
$query->with(['contents' => function($contentQuery) {
$contentQuery->has('content')->with('content');
}]);
}
CourseContents Model:
public function content()
{
return $this->hasOne('App\Content', 'id');
}
My json return ( Course Find ) :
{
"id":1,
"name":"Course Example 1",
"contents":[
{
"id":1,
"course_id":1,
"content_id":1,
"deleted_at":null,
"created_at":"2019-07-16 17:31:05",
"updated_at":"2019-07-16 17:31:05",
"content":{
"id":1,
"name":"Content Example 1",
"deleted_at":null,
"created_at":"2019-07-16 17:31:05",
"updated_at":"2019-07-16 17:31:05"
}
},
{
"id":2,
"course_id":1,
"content_id":2,
"deleted_at":null,
"created_at":"2019-07-16 17:31:05",
"updated_at":"2019-07-16 17:31:05",
"content":{
"id":2,
"name":"Content Example 2",
"deleted_at":null,
"created_at":"2019-07-16 17:31:05",
"updated_at":"2019-07-16 17:31:05"
}
},{ ... }
],
}
What I need:
{
"id":1,
"name":"Course Example 1",
"contents":[
{
"id":1,
"name":"Content Example 1",
"deleted_at":null,
"created_at":"2019-07-16 17:31:05",
"updated_at":"2019-07-16 17:31:05"
},
{
"id":2,
"name":"Content Example 2",
"deleted_at":null,
"created_at":"2019-07-16 17:31:05",
"updated_at":"2019-07-16 17:31:05"
},{ ... }
],
}
First, you need to adjust the relationships a bit. You've many to many relationships so the models should look like:
Course.php
public function contents()
{
return $this->belongsToMany(Content::class, 'course_contents');
}
Content.php
protected $hidden = ['pivot'];
public function courses()
{
return $this->belongsToMany(Course::class, 'course_contents');
}
You can retrieve contents data as given below:
for instance: you want to get all contents for a course 1
Content::whereHas('courses', function($query) {
$query->where('courses.id', 1);
})->get();
// You need to pass course id dynamically but for demonstration, I hard coded it.
This will give you the following result:
array:1 [
0 => array:2 [
"id" => 1
"name" => "Content 1"
]
]
Use the belongsToMany relationship:
In your Course model:
public function contents()
{
return $this->belongsToMany(Contents::class, 'course_contents');
}
Then, use $course->contents;
This function returns all content models of the course.
Hope it helps.
The many-to-many relationship is defined by returning a belongsToMany relationship in the relationship method contents in the Course model. As stated in the Laravel many-to-many documentation.
To retrieve only the Content items in the many to many relationship and not the pivot columns, you should change the relationship instance from App\CourseContent to App\Content.
in content model
public function course()
{
return $this->hasMany('App\Course');
}
in course model
public function content()
{
return $this->hasMany('App\Content');
}
you can do
Course::with('content')->find($id)
or
Content::whereHas('course',function($q)use($id){
$q->where('id',$id)
})->get();

advanced filters in laravel

In my case, I have to filter the data by city or institute
I have two tables like below
Institutes table
id | institute_name | phoneNumber
-------------------------------------
1 infocampus 9999999999
-------------------------------------
2 jspider 2348234982
courses table
id | institute_id | course_name
------------------------------------------
1 1 java
2 1 php
Relations that I have created
Institue model
public function courses()
{
return $this->hasMany(Course::class);
}
Course model
public function institute()
{
return $this->belongsTo(Institute::class);
}
I have tried with below code
public function filter(Request $request)
{
$institute = (new Institute)->newQuery();
// Search for a user based on their institute.
if ($request->has('institute_name')) {
$institute->where('institute_name', $request->input('institute_name'));
}
// Search for a user based on their course_name.
if ($request->has('course_name')) {
$institute->whereHas('courses', function ($query) use ($request) {
$query->where('courses.course_name', $request->input('course_name'));
});
}
return response()->json($institute->get());
}
From above i able to filter the data but it show only institution table data like below
[
{
"id": 2,
"institute_name": "qspider",
"institute_contact_number": "9903456789",
"institute_email": "qspider#gmail.com",
"status": "1",
"created_at": null,
"updated_at": null
}
]
but what I need is when I do seach with course_name or instute_name I need to fetch data from institue table as well as courses table data.
Can anyone help on this, please?
Try the following it should return the institutes with the courses.
$institute->with(['courses' => function ($query) use ($request) {
$query->where('courses.course_name', $request->input('course_name'));
}])

How to return a collection of models with selected columns and relation eager loaded in Laravel 5.2

Problem details:
I have three models
a Directorate with id and name fields,
an Employee with id and name fields and
a Telephone with id, tel, employee_id, directorate_id, description and type fields. The employee_id may be nullable, that is there are telephones stored in database with employee_id = null
The models are related as follows:
an employee may have many telephones
a directorate, may have many telephones
class Directorate extends Model
{
public function telephones()
{
return $this->hasMany(Telephone::class);
}
public function employees()
{
return $this->hasMany(Employee::class);
}
}
class Employee extends Model
{
public function telephones()
{
return $this->hasMany(Telephone::class);
}
public function directorate()
{
return $this->belongTo(Directorate::class);
}
}
class Telephone extends Model
{
public function employee()
{
return $this->belongsTo(Employee::class);
}
public function directorate()
{
return $this->belongsTo(Directorate::class);
}
}
Question:
I want to fetch a Collection of all the Telephone models that belong to a specific Directorate, that have employee_id = null and also having their directorate relation eager loaded. In addition, from that resulting collection of Telephone models, I need only some of the models' fields, that is id, tel and description
Tries
What I tried so far was the following:
I created a query scope in the Telephone model:
public function scopeHaveNoEmployeeId($query)
{
return $query->where('telephones.employee_id', '=', null);
}
In my controller
$myTelephones = Telephone::with('directorate')
->haveNoEmployeeId()
->where('directorate_id', $directorateId)
->get(['id', 'tel', 'description']);
However what I am receiving are the requested fields of the filtered models without the relation eager loaded, for instance:
[
{
"id": 79,
"tel": "0648136867",
"directorate": null
},
{
"id": 380,
"tel": "0223796011",
"directorate": null
}
]
I tried also to lazy eager load the relation afterwards but with no luck.
Finally I noticed that if I request all the Telephone models fields, the relation will eager load as I request. For example:
$myTelephones = Telephone::with('directorate')
->haveNoEmployeeId()
->where('directorate_id', $directorateId)
->get();
Then as a result:
[
{
"id": 79,
"tel": "0648136867",
"directorate": {
"id": 23
"name": "Some name"
}
},
{
"id": 380,
"tel": "0223796011",
"directorate": {
"id": 23
"name": "Some name"
}
}
]
Your telephone does not have any relationship with the directorate model.
put this in your Telephone model.
public function directorate()
{
return $this->belongsTo(Directorate::class);
}
Actually, after digging into Laravel's details for a while, I noticed that my initial question was out of context and somewhat silly. I was first eager loaded a relationship and then fatuously I filtered out the relationship by not including it in get() parameters. I had just to do the following:
$myTelephones = Telephone::with('directorate')
->haveNoEmployeeId()
->where('directorate_id', $directorateId)
->get(['id', 'tel', 'description', 'directorate']);

Resources