Laravel join query with conditions - laravel

I have 4 tables.
User table:
id col1 col2
CoursesAssigned table:
id user_id course_id approved
CourseInfo table:
id parent_id
CourseParents table:
id start_date end_date
I think the table names and its column names are self explanatory.
I have 2 kinds of users - i) assigned ii) unassigned. I show them in 2 different pages.
While showing the assigned students I need those students from users table for each of whom there is at least one row in CoursesAssigned table where user_id is his own user id and the approved field is 1 and the course_id in that row has its own parent_id (from CourseInfo) with end_date (from CourseParents) greater than or equal to today.
For showing unassigned students, I need those students from users table, for each of whom -
either
there is NO row in CoursesAssigned table where the user_id is his own user id and the approved column has a value 1. That is for an unassigned user, there may exist a row with his own user id but the approved field contains 0.
or
there may be rows in CoursesAssigned table with the user_id being his own user id and the approved field having a value 1 but the parent_id obtained from CourseInfo has from CourseParents an end_date which is less than today's date.
I can write a query for assigned students like:
$date=date('Y-m-d');
$records = User::join('CoursesAssigned','users.id','=','CoursesAssigned.user_id')
->join('CourseInfo','CourseInfo.id','=','CoursesAssigned.course_id')
->join('CourseParents','CourseParents.id','=',
'CourseInfo.parent_id')
->where('CoursesAssigned.approved','=',1)
->where('CourseParents.end_date','>=',$date)
->select('users.id','users.col1','users.col2')
->orderBy('users.id','desc');
But that should not produce the correct result as that does not check CoursesAssigned table for at least 1 row that meets all mentioned criteria. Q1) Or should it ?
Q2) What is about the query that fetches only the unassigned students ?
EDIT : The answer can be in ORM, query builder or even raw MySql for Laravel format.
EDIT2 : Let me clarify the scenario here :
I need to fetch both assigned and unassigned users separately.
To obtain assigned users I have 1 rule: How can I get those users who have at least 1 approved course in CoursesAssigned table and the parent (obtained from CourseInfo table )of that course has the end_date (in CourseParents table) greater than or equal to today.
To obtain unassigned students I have 2 rules :
Rule 1: Get those tudents who do not have any approved course (i.e. all courses have approved =0). They are unassigned students
Rule 2: Get those students who have approved courses but none of the approved courses meet the criteria of those for assigned students . That means there is no approved course there that has a parent whose end_date is greater than or equal to today.They are also unassigned students.

I'm still not completely sure about your table relationships but from my guess, I came up with the following solution, first create the relationships using Eloquent models:
User Model (for usres table):
namespace App;
use App\Course;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
public function courses()
{
return $this->hasMany(Course::class);
}
}
Course Model (for CoursesAssigned table):
namespace App;
use App\CourseInfo;
use Illuminate\Database\Eloquent\Model;
class Course extends Model
{
protected $table = 'CoursesAssigned';
public function courseInfo()
{
return $this->belongsTo(CourseInfo::class);
}
}
CourseInfo Model (for CourseInfo table):
namespace App;
use App\CourseParent;
use Illuminate\Database\Eloquent\Model;
class CourseInfo extends Model
{
protected $table = 'CourseInfo';
public function courseParent()
{
return $this->belongsTo(CourseParent::class, 'parent_id');
}
}
CourseParent Model (for CourseParents table):
namespace App;
use Illuminate\Database\Eloquent\Model;
class CourseParent extends Model
{
protected $table = 'CourseParents';
}
Get the assigned users:
$assignedUsers = User::whereHas('courses', function($query) {
$query->where('approved', 1)
->with(['courses.courseInfo.courseParent' => function($query) {
$query->where('end_date', >= \Carbon\Carbon::now());
}]);
})->get(); // paginate(...) for paginated result.
This should work if my assumption is correct. Try this for assignedUsers first then let me know and then I'll look into it for the other requirements. Also make sure that you do understand about Eloquent relationships between models and implement everything correctly (with correct namespace).
Note: This answer is incomplete and need further info because the answer is a result of direct conversation with OP over phone (OP called me because I was reachable) so some changes will be made overtime if needed and will be continued step by step until I can come up with a solution or leave it.

Related

Laravel: How to get the latest record in group of records with where condition?

I have two tables which are named as students and cities. students table has a primary key which is related to the cities table.
Students table:
In the frontend, I would like to have the data of the cities table with these requirements:
The data of the students table must be grouped by city_id
If there are more than one records with the same city_id in the students table, select only the latest record of the group.
Search in the latest records and select only students who are inactive.
Here is the relationship function of the city model:
public function student()
{
return $this->hasOne(Student::class, 'city_id', 'id')->orderByDesc('id');
}
This is my controller function:
$data = City::whereHas('student', function($query){
$query->where('is_active', 0)
})->with('student')->get();
Expected result: Considering the sample data, the query must return nothing.
Current result: It returns the third row as there is an inactive student record in the second row. So in this case where condition doesn't work properly.
I can get expected result with this SQL query:
select *
from students s
where id = (select max(t2.id)
from students s2
where s.city_id = s2.city_id) AND is_active = '0';
How can I fix this logical error?
What about something like this?
public function inactiveStudent()
{
return $this->hasOne(Student::class, 'city_id', 'id')
->where('is_active', 0)
->orderByDesc('id');
}
$data = City::whereHas('inactive_student')
->with('inactive_student')
->get();
I'm not certain if it's inactive_student or inactiveStudent when you do the query.

Laravel : How to hide user's own profile from friend list?

There are three tables: users, profiles, friend_request
profiles table's column : profile_id, id (foreign key with users) , first_name,last_name
friend_request's table column : request_id, sender_id,to_user_id, request_status
logic : if profile_id exist in either sender_id column or to_user_id of friend_request table with request_status 2 then they are friends.
example : sender_id to_user_id request_status
5 6 2
$request_accept = DB::table('friend_request')->select('profiles.profile_id','profiles.first_name',
'friend_request.request_id')->leftjoin('profiles', function($join)
{
$join->on('friend_request.sender_id' , '=','profiles.profile_id');
$join->orOn('friend_request.to_user_id' , '=','profiles.profile_id');
}
)->where('to_user_id',$my_profile_id)->orwhere('sender_id',$my_profile_id)->where('interest_status','2')->whereNotIn('profiles.profile_id', function($q) use ($my_profile_id)
{
$q->select('profile_id')->from('profiles')->where('profile_id',$my_profile_id);
})->groupby('profiles.profile_id')->get();
wherenotin i snot working.
If I understand what you are asking...
Probably better to make these all models, with relationships, then you could do a much simpler query, for example like this.
Assume your friend_request table now has a FriendRequest model with a user relationship. The query below uses a $userId, assume this is the ID for the user whom you wish to get all the friend requests.
FriendRequest::where('to_user_id', $my_profile_id)->get();
If everything is set up correctly, the user will not be returned as they cannot send themselves a friend request.

Is it possible to join eloquent relationship query?

I have a users, departments, and positions table.
I want to select one department with all the users in that department with their position name.
Currently, I have this.
$department = DepartmentView::with('users')
->findOrFail($departmentId);
It returns me a department with users, but I want to join the users with positions table so I can also get the position name. (user table only has position id)
Assuming you have your relationships setup properly in your User model and the relationship is called position, it should be like this:
$department = DepartmentView::with('users.position')
->findOrFail($departmentId);
Look at eager loading -> nested eager loading.
You can do
$department = DepartmentView::with('users.position')->findOrFail($departmentId)
position is referred to the relationship set on the User model to get the user position.

Query on eloquent relationship

I have Book and Store models which have belongsToMany relationship.
In Book.php
public function stores(){
return $this->belongsToMany('App\Store')->withPivot('qty');
}
In Store.php
public function books(){
return $this->belongsToMany('App\Book')->withPivot('qty');
}
Now I just want to know the total number of books in store A and B together. How can I do it with eloquent ORM? I can get all books belonging to store A and B using whereHas but cannot go further to aggregate the qty field in the pivot table.
So you want the total qty of books by combination of store id and book id
The way you've described your DB structure, it looks like your pivot table has exactly these columns: book_id, store_id and qty
So all you really need to do is:
DB::table('book_stores')->get()

Laravel 4.2 - Update a pivot by its own id

I'm having some trouble with my pivot table. I've recognized too late, that it is possible, that some pivot rows doesn't have unique values in my project, means I've to add an auto_increment ID field to my pivot table.
This is my structure:
Order.php
public function items()
{
return $this->belongsToMany('Item', 'orders_items', 'order_id', 'item_id')->withPivot(['single_price', 'hours', 'prov', 'nanny_id', 'vat', 'vat_perc', 'invoice_id','id']);
}
orders_items
id, order_id, item_id, nanny_id, hours
I've conntected Orders and Items through a pivot table ('orders_items)'. It is possible, that one order has 2 or more same items in the pivot table. So I've to add an unique ID to identify and update them.
Now I try to update a pivot row. Problem is, if I have 2 or more items, he updates them all, not only one. This is my update command:
$order = Order::find($orderId);
$items = $order->items()->whereNull('nanny_id');
$free_item = $items->first();
$free_item->pivot->nanny_id = 123;
$free_item->pivot->save();
With this command, he updates all pivot rows from the order. I know the problem: Laravel uses here the wrong identifiers (it uses order_id and item_id as defined in my belongsToMany relationship - and they aren't unique). For example, Laravel tries to execute this code on save():
UPDATE orders_items SET [...] WHERE order_id = 123 AND item_id = 2;
I want, that Laravel changes the query to this one:
UPDATE orders_items SET [...] WHERE order_id = 123 AND item_id = 2 AND id = 45;
// Edit
Okay, this solution works:
$free_item->pivot->where('id',$free_item->pivot->id)->update('nanny_id',123);
But is there an easier way, f.e. adding a custom pivot model that adds the id automatically to save() and update() methods?

Resources