Count data using Laravel eloquent query from multiple table - laravel

I have 3 table 'Admins', 'Agent', 'Books'
Admin can add multiple Agents, Agents can add multiple books.
Now I need to count the book for a single Admin. (Every table has the proper foreign key).
How can I achieve this?
My code
//In Controller
$data = Admin::latest()->withCount('datacount')->get();
//In Admin.php
public function datacount(){
return $this->hasMany(Agent::class, 'adminId', 'id');
}
//In Agents.php
public function datacount(){
return $this->hasMany(Books::class, 'AgentId', '???');
}
//In Book.php
public function datacount(){
return $this->belongsTo(???::class, 'AgentId', '???');
}
??? - I don't know which Id or class need to pass
Can anyone help to solve this issue, please?

Related

Laravel many to many and hasMany, N+1

I got a model Event that has many private classes
public function privateclasses()
{
return $this->hasMany(Privateclass::class);
}
This is working perfect
Model Privateclass and User is connected in table "privateclass_user" with foreign key "privateclass_id" and "user_id".
In model Privateclass.php:
public function users()
{
return $this->belongsToMany(User::class);
}
This is also working, but when I get the event the query count is high.
How do I Eager Load this?
$event = Event::with('users')->get(); <-- NOT WORKING
In short: I want all users connected to privateclass that belongs to an Event.
https://laravel.com/docs/9.x/eloquent-relationships#nested-eager-loading
To eager load a relationship's relationships, you may use "dot" syntax.
Looks like you need:
Event::with('privateclasses.users')
or:
Event::with([
'privateclasses' => [
'users'
]
])

Laravel eloquent for four tables

I'm new to Laravel. I am developing a project. and in this project I have 4 tables related to each other
-Users
-Orders
-OrderParcels
-Situations
When listing the parcels of an order, I want to get the information of that order only once, the user information of that order once again, and list the parcels as a table under it. so far everything ok. but I also want to display the status of the parcels listed in the table as names. I couldn't add the 4th table to the query. do you have a suggestion? I'm putting pictures that explain the structure below.
My current working code is
$orderParcels = Orders::whereId($id)
->with('parcels')
->with('users:id,name')
->first();
and my 'orders' model has method
public function parcels(){
return $this->hasMany(OrderParcels::class);
}
public function users(){
return $this->hasOne(User::class,'id','affixer_id');
}
Note[edit]: I already know how to connect like this
$orderParcels = DB::table('order_parcels as op')
->leftjoin('orders as o','op.orders_id','o.id')
->leftjoin('users as u','o.affixer_id','u.id')
->leftjoin('situations as s','op.status','s.id')
->select('op.*','o.*','u.name','s.situations_name')
->where('op.orders_id',$id)->get();
but this is not working for me, for each parcels record it returns me orders and user info. I want once orders info and once user info.
Laravel provides an elegant way to manage relations between models. In your situation, the first step is to create all relations described in your schema :
1. Model Order
class User extends Model {
public function parcels()
{
return $this->hasMany(OrderParcels::class);
}
public function users()
{
return $this->hasOne(User::class,'id','affixer_id');
}
}
2. Model Parcel
class Parcel extends Model {
public function situations()
{
return $this->hasOne(Situation::class, ...);
}
}
Then, you can retrieve all desired informations simply like this :
// Retrieve all users of an order
$users = $order->users; // You get a Collection of User instances
// Retrieve all parcels of an order
$parcels = $order->parcels; // You get a Collection of User instances
// Retrieve the situation for a parcel
$situations = $parcel->situations // You get Situation instance
How it works ?
When you add a relation on your model, you can retrieve the result of this relation by using the property with the same name of the method. Laravel will automatically provide you those properties ! (e.g: parcels() method in your Order Model will generate $order->parcels property.
To finish, in this situation where you have nested relations (as describe in your schema), you should use with() method of your model to eager load all the nested relation of order model like this :
$orders = Orders::with(['users', 'parcels', 'parcels.situations'])->find($id)
I encourage you to read those stubs of Laravel documentation :
Define model relations
Eager loading
Laravel Collection
Good luck !
Use join to make a perfect relations between tables.
$output = Orders::join('users', 'users.id', '=', 'orders.user_id')
->join('order_parcels', 'order_parcels.id', '=', 'orders.parcel_id')
->join('situations', 'situation.id', '=', 'order_parcels.situation_id')
->select([
'orders.id AS order_id',
'users.id AS user_id',
'order.parcels.id AS parcel_id',
'and so on'
])
->where('some row', '=', 'some row or variable')->get();

How to retrieve multiple relations with multiple tables in laravel eloquent

I'm using Laravel 5.8 to build a babysitting site. I have 4 tables with different relationships as below:
please see this image
The relationships are:
Babysitter->hasMany(session)
Sessions->hasOne(Review)
Sessions->hasOne(Kids)
Sessions->hasOne(Babysitter)
Sessions->hasOne(Parent)
I want to achieve 2 things:
First one
I want to show this result when listing all babysitters. I'm showing this information for each babysitter:
plsease see this image
See here what I couldn't achieve
plsease see this image
This is my code
Sitters::where('Status', 'active')->where('Verified', 1)->get();
Second one
Also, I've tried to show kids name with parent review as shown here:
plsease see this image
This is what i'm using
Sessions::select('Reviews.*', 'Sessions.Parent_id')->join('Reviews', 'Reviews.Session_id', '=', 'Sessions.id')->with('owner')->where('Trainer_id', session('user')->Id)->where('Status', '=', 'complete')->with('owner')->orderBy('Sessions.id', 'DESC')->get();
Here is Session.php Model
public function owner(){
return $this->belongsTo('App\Models\Parents', 'Parent_id');
}
As discussed change the relations:
Babysitter->hasMany(sesstion)
Sessions->hasOne(Review)
Sessions->belongsTo(Kids)
Sessions->belongsTo(Babysitter)
Sessions->belongsTo(Parent)
First one
in Babysitter.php declare the following attributes
class Babysitter extends Model
{
public function reviews()
{
$this->hasManyThrough(Review::class, Session::class);
}
public function getAverageReviewAttribute()
{
return $this->reviews()->avg('Rating');
}
}
Then you just need to call it on the model instance.
$babysitter = Babysitter::first();
return $babysitter->average_review;
Second one
Just use the relation
$babysitter = BabySitter::with(['sessions' => public function ($session) {
$session->with(['review','parent','kids']);
})->where('trainer_id', '=', session('user')->Id) //did not understand this condition
->first();
This assumes you have parent, kids and review relation declared on Session::class. (change the names if needed)
After a few days of searching & testing, this is what worked for me:
Inside (Sitters) Model, put this relation
public function sessions()
{
return $this->hasMany(Sessions::class, 'sitter_id')
->withCount('reviews')
->withCount(['reviews as review_avg' => function($query){
$query->select(DB::raw('AVG(Rating)'));
}]);
}
Also, inside (Sessions) Model, put this relation
public function reviews()
{
return $this->hasOne(Reviews::class, 'Session_id');
}
Now you query like this
return $sitters = Sitters::with('sessions')->get();
I hope this can help someone :)

Given a Laravel 5 Eloquent model, how can I update all models on a relationship in one query?

I have a model Company which hasMany Jobs. Company and Job represent mysql tables.
Simplified class here:
class Company extends Eloquent
{
public function jobs()
{
return $this->hasMany('App\Models\Job');
}
}
I want to add a function to this class to deactivate all the company's jobs by setting the is_active property on each job to 0. With the query builder I could accomplish this with one simple update query. Is there a way to do this using the models/relationships in one query instead of iterating through every job?
You can do this:
$company = Company::first(); // Or some $company where you want to update the jobs
$company->jobs()->update(['is_active' => 0]);
If you call $company->jobs() it will return the query object and you can chain query methods on it.
Then the method would look like this:
public function deactivateJobs()
{
return $this->jobs()->update(['is_active' => 0]);
}
As far as I know, there's no reason why you can't use the Job model inside the Company model. Would something like this work for you?
public function deactivateJobs()
{
App\Model\Job::where('company_id', $this->id)->update(['is_active' => false]);
}

How to add data to additional column in pivot table in laravel

I'm trying to build an app in Laravel 5.3, I want to add additional column data in the pivot table. Following is my code:
My Users model:
public function relations()
{
return $this->belongsToMany('App\Plan')->withPivot('child');
}
My Plan model:
public function relations()
{
return $this->belongsToMany('App\User')->withPivot('child');
}
In my controller I'm fetching the user data from Auth::user(); and for plans and child element I'm getting through request. I want to store this to my pivot table. Following is the code which I tried in my controller:
$user = \Auth::user();
$plan_id = $request->plan_id;
$childid = $request->child_id;
$plan = App\Plan::find($plan_id);
$user->relations()->attach($plan, ['child' => $childid]);
Help me out in this.
You should use attach() like this:
$user->relations()->attach($plan_id, ['child' => $childid]);
Try the save method as:
$user->relations()->save($plan, ['child' => $childid]);
Docs
Both save and attach work. Just that attach will return null while save will return $user object when I try with tinker

Resources