Many to Many Relationship with 2 pivot table data search - php

Skills
-------
id name
1 PHP
2 Laravel
Qualifications
-----------------
id name
1 MBA
2 Graduate
3 Post Graduate
students
------------
id name
1 John
2 Smith
2 pivot tables
student_skills
student_id skill_id
1 1
1 2
2 1
student_qualifications
tutor_id qualification_id
1 2
1 2
2 2
In front-end the user can select multiple qualifications(checkboxes) and skills(checkboxes) according to the options selected we need to display the data.
For Example: How to get students with qualification graduate and MBA and skills Laravel and PHP

Here is an example on how you can do it ( it might be inaccurate due to the lack of details in your question but it should give you an idea)
(i think you better use a Mutli-select box instead of check-boxes for skills & qualification)
Assuming you want to search student by skills & qualification
And that you have the right Relations methods inside your models
//Don't forget to import Students model at top of the controller
public function whatever(Request $request)
{
$data = Student::with('qualifications', 'skills');
// assuming that the form will pass an array of skills names
//if the form passes an array of ID's of skills it becomes easier
if (!empty($request->skills)) {
foreach ($request->skills as $skill) {
$data->whereHas('skills', function ($query) use ($skill) {
$query->where('id', $skill);
})->get();
}
}
// same goes for qualifications
if (!empty($request->qualifications)) {
foreach ($request->qualifications as $qualification) {
$data->whereHas('qualifications', function ($query) use ($skill) {
$query->where('id', $qualification);
})->get();
}
}
// execute the query now
$data->get(); // or pagniate(10)
}
if you are passing an array of ID's instead of names
if (!empty($request->skills)) {
$data->whereHas('skills', function ($query) use ($skills) {
$query->whereIn('id', $skills);
})->get();
}
same goes for qualifications.
I hope you get the point here, you can Sort and stuff , this might not be the exact thing u need, but It will help you a lot if you get it.

Related

Get only 3 records using with from many to many relationship Laravel

I'm using laravel 7 and
I have 3 tables shown below. I want first three students data instead of all student. tables have many to many relationship.
groups
id
name
students
id
name
group_student_pivot
group_id
student_id
created_at
I have below relationship in models
Groups model
public function students()
{
return $this->belongsToMany(Student::class,'group_student_pivot')->withPivot(['status'])->withTimestamps();
}
Student model
public function groups()
{
return $this->belongsToMany(Group::class,'group_student_pivot')->withPivot(['status'])->withTimestamps();
}
$groups = Group::whereIn('id',$groupIds)->with('students')->get();
In above query I want first 3 students data instead of all students.
You can get 3 records like this:
$groups = Group::whereIn('id',$groupIds)->with('students', function($q){
$q->take(3);
})->get();
You can use with and whereHas method
$groups = Group::with('students')->whereHas('students', function($q){
$q->take(3);
})->whereIn('id',$groupIds)->get();

Laravel. OrderBy query with last item hasMany relationship

need some help with a query on Laravel(PHP)
what I have :
Two tables. Expedients & ExpedientRevs with a hasMany relationship beetween them.
Expedient Model:
public function ExpedientRevs() {
return $this->hasMany('App\ExpedientRev');
}
What I need:
A list of the expedients (Distinct Expedient) order DESC by the last Expedients Revisions (last id of ExpedientRev)
I mean, if I have in ExpedientRev:
id expedient_id ..........
--- --------------
1 1
2 2
3 3
4 3
5 1
My result should be the expedients in this order : 1,3,2 (no duplicated expedients)
Any help will be appreciated
Thanks
Simplest way to do that;
$expedients = Expedient::orderByDesc(ExpedientRev::select('id')
->whereColumn('expedient_revs.expedient_id', 'expedients.id')
->latest()
->take(1)
)->get();
This will get the latest records by ExpedientRev model. If you want to include ExpedientRev in your results. You can use latestOfMany.
In your Expedients model add this one;
public function rev()
{
return $this->hasOne(ExpedientRev::class)->latestOfMany();
}
So you can use like this;
$expedients = Expedient::orderByDesc(ExpedientRev::select('id')
->whereColumn('expedient_revs.expedient_id', 'expedients.id')
->latest()
->take(1)
)->with('rev')->get();

How to order by column in nested 2 level relationship in Laravel?

I have 3 tables: reports, fields and report_fields which is a pivot between the other 2. What i need to do is order report_field.field by the position column in the field table.
I tried ordering in the relation in the Models or when using with but I may be doing it wrong.
ex:
$query = Report::with([ 'reportFields.field' => function ($q) {
$q->orderBy('position', 'asc');
//$q->orderByRaw("fields.position DESC");
},
Can someone give a basic example of ordering a 2 level nested relationship?
Edit: I do not need to order by any column in the base table but the list of entries in the pivot table by an column in the second table.
Edit2:
To give an example how the output should be ordered:
Report
ReportField
Field.position = 1
ReportField
Field.position = 2
ReportField
Field.position = 3
You can add your needed ordering on the relation of the first table reports:
public function reportFields()
{
return $this->hasMany(ReportFields::class)
->select('report_fields.*')
->join('fields', 'report_fields.field_id', 'fields.id')
->orderBy('fields.position', 'asc');
}

Group by user id in Model relation

I have two models: Report and User. This is what I have in my User model
public function userReport() {
return $this->hasMany('App\Report', 'user_id','id');
}
And this is in Report model
public function user() {
return $this->hasOne('App\User', 'id', 'user_id');
}
Controller
public function details( $item_id ){
$report = Item::find($item_id)->report;
return view('details', compact('report'));
}
In view
{!! $report->user->name !!}
In view I show all the users who are reported single Item .. which I query by $item_id.
The problem is that if same user is reported single item 1+ time I see this user 1+ time in the table on the page.
Is it possible to somehow grouped by user_id or count the user_id and show User1 ( 4 time reported ) ...? Where should I group them?
Update: users table
id | username | password
reports table
report_id | id | user_id | date
item table
id | user_id | category | date_added | image
Update2: Image of records in db. Here user with user_id=3 has reported item_id=14 total of 14 times. User with user_id=5 has reported same item_id=14 total of 3 times. So I should see on page user_id=3 ( 14 ) and user_id=3 ( 3 ). Instead I see 17 times user_id=3. Bellow are images
And on page
There should be several ways how to solve your problem
One way is (your controller should look like)
public function details( $item_id ){
$report = Item::find($item_id)->report->unique('user_id');
return view('details', compact('report'));
}
Second way should be to use #foreach in view and there check for unique values.
Third way should be to use foreach in controller and prepare unique data with calculated summarizes inside controller and then pass that prepared data to view.
Which soulution you want to use is just a matter of choice.
Hope it helps you
Just try this. Hope it helps
Report::where('item.id', $item_id)
->select('item.*','users.*',DB::raw('count(reports.report_id) as total'))
->join('item', 'item.id', '=', 'reports.id')
->join('users', 'users.id', '=', 'reports.user_id')
->groupBy('reports.report_id','reports.id')
->get();

Laravel: Get not related items in a many to many relation

Is it possible to get all items not related to the specific instance, in a many to many relation in Laravel?
Example:
I have two models, User and Pet. They have a many to many relationship, because a User can have many pets, but a pet can belong to more users.
But I want a list of pets, which a specific user is not having.
How is that possible?
EDIT
The above is just an example, so not related to my current task. Just more simple to explain with users and pets. But to specify:
PETS TABLE:
ID TYPE
1 Dog
2 Cat
3 Rabit
4 Horse
5 Rat
6 Bat
7 Bird
USERS TABLE:
ID NAME
1 Martin
2 Peter
3 Viggo
PET_USER TABLE:
ID PET USER
1 1 1
2 3 1
3 5 1
Then Martin has a dog, a rabbit and a rat.
But I want a list of pets, that he does not have:
Cat, horse, bat and bird
You may try this (your question sounds a little confusing to me tho):
$pets = Pet::with('users')->whereDoesntHave('users', function($query) use ($id) {
$query->where('users.id', $id);
})->get();
Also, try this as well (if you want):
$pets = Pet::with('users')->whereHas('users', function($query) use ($id) {
$query->where('users.id', '!=', $id);
})->get();
There is no function from laravel to run this out of the box.
You have to join this manually:
$pets = Pet::leftJoin('pet_user', function($join) use ($userId){
$join->on('pets.id', '=', 'pet_user.pet_id');
$join->on('pet_user.user_id', '=', \DB::raw("'".$userId."'"));
})->whereNull('pet_user.pet_id')->get();
i would suggest this method if you already defined ManyToMany relationship on your models :
$user = User::find($user_id);
$pets = new Pet;
$exception = $user->profile->pluck('id')->toArray();
$pets = $pets->whereNotIn('id',$exception)->get();
My Solution: worked for me atleast.
Just use :
Pet::whereDoesntHave('user');
or
Pet::whereDoesntHave('user', function($qu) {
// ...(extended query filter logic)
});

Categories