Laravel eloquent model set condition at belongsTo method - laravel

I have a model class ServiceAgentRel. Where agent_id belongs to user table. I am fetching all column with service_id 3.
$agent_data = App\ServiceAgentRel::where(['service_id'=>3])->with('agent')->get();
Using this code I can get all services with service_id 3 But I need to set a condition on user table if user status (status corresponding to that agent_id) is inactive no row will be fetched.
My main requirement is, I have to set a condition on a relation function agent(). Also is there any way to check it from controller?
class ServiceAgentRel extends Model {
public function agent(){
return $this->belongsTo('App\User', 'agent_id', 'id');
}
}
I know it is possible to do this task by a simple join, but I want to know if it is possible by eloquent model function.
Thanks
enter image description here

for that you need to use whereHas,like that
$agent_data = App\ServiceAgentRel::where(['service_id'=>3])->with('agent')
->whereHas('agent',function($query) {
$query->where('status', 'active');
})->get();

Hi you can do like this
$agent_data = App\ServiceAgentRel::where(['service_id'=>3])->first();
echo $agent_data->agent->name;

You can use this statement:
$agent_data = App\ServiceAgentRel::where(['service_id'=>3])
->with(['agent' => function($query) {
$query->where('agent.status', 'active');
}])->get();

Related

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();

Laravel: With and whereHas to filter second relation hasOne

i'm trying to filter the table using "with" and "whereHas" for the relation and have it follow a second second relation.
Is it possible to do it with "with" or would it only be possible with "Joins"?
Ticket >> StatusHistory (Last record) >> StatusName = 'new'
ticket
-id
-name
status_history
- ticket_id
- status_name_id
- timestamps
status_names
- id
- name (new, close, paused)
<?
class Ticket extends Model
{
public function latestStatus()
{
return $this->hasOne(StatusHistory::class, 'ticket_id', 'id')->latest();
}
class StatusHistory extends Model
{
public function statusName()
{
return $this->hasOne(StatusName::class, 'id', 'status_name_id');
}
This usually works well if there is only one Status history record, but if there are more, it returns values that should not be there.
example: ticket_id 1 has in history first status new and them status paused
With this sentence he returned the ticket to me even so he no longer has the last status in "new".
Ticket::with('latestStatus')
->whereHas('latestStatus.statusName', function($q){
$q->where('name', 'new');
})
According to the documentation (https://laravel.com/docs/8.x/eloquent-relationships#constraining-eager-loads) it is possible. It would look like this:
Ticket::with(['latestStatus' => function($q){
$q->where('name', 'new');
}])->get();
So that the subquery is linked to the relation you are trying to load
To access the first relationship you just use:
$ticket = Ticket::find($id);
$ticket->latestStatus
By having a "hasOne" relationship established, this will return the related record, which from what I see also has a hasOne relationship, so you can do the following:
$ticket->latestStatus->statusName
In this way, you are accessing the second relationship and working it as usual.
However, this is not the only way, as Laravel also offers access to chained relationships through the "has-one-through" method, which according to the documentation is defined as:
"...this relationship indicates that the declaring model can be matched with one instance of another model by proceeding through a third model."
class Ticket extends Model{
public function statusName()
{
return $this->hasOneThrough(StatusName::class, StatusHistory::class);
}
}
Take into account that for this you must follow the conventions established by Laravel. I leave here the related links, I am sure they will be very helpful. Greetings.
Relationships: one-to-one
Relationships: has-one-through

Filter many to many relationship based on child existence and column value

I've been searching for a while and couldn't find an answer, here's what I have:
1- ShowCategory (id & title)
class ShowCategory extends Model
{
public function shows()
{
return $this->belongsToMany(Show::class, 'category_show');
}
}
2- Show (id, title & active)
class Show extends Model
{
public function categories()
{
return $this->belongsToMany(ShowCategory::class, 'category_show');
}
}
So there's a many to many relationship, what I need is retrieving all ShowCategory elements that has at least one Show related to it, and to filter each ShowCategory->shows by show.active, only return shows that are active
Here's what I'm trying to do:
$categories = ShowCategory::whereHas('shows', function($query) {
$query->where('shows.active', '=', true);
})->get();
It only filters ShowCategory that includes shows and if only one of those shows are active, it returns the category with all shows inside, even if others are not active, I need to filter those who are not active.
What should I do? Thanks in advance
This requires a combination of whereHas() and with(). First, whereHas() will filter the ShowCategory model to those that have an active Show, while the with() clause will limit the results of the relationship to only return active ones:
$categories = ShowCategory::whereHas("shows", function($subQuery) {
$subQuery->where("shows.active", "=", true); // See note
})->with(["shows" => function($subQuery){
$subQuery->where("shows.active", "=", true);
}])->get();'
Note: You should be able to use active instead of shows.active, but depends on if that column is on multiple tables.
Using this query, you will get a Collection of ShowCategory models, each with their active Show models already loaded and available via ->shows:
foreach($categories AS $category){
dd($category->shows); // List of `active` Shows
}
This is what you need.
$categories = ShowCategory::whereHas('shows', function($query) {
$query->whereActive(true);
})->get();
Try, this can be a possible way to retreive related results.
// This will only return ShowCategory which will have active shows.
/* 1: */ \ShowCategory::has('shows.active')->get();
// So, logically this will only have active shows -__-
$showCategory->shows
Laravel allows to extends foreign relation by using this . notation as a condition for retreival.
Update
You should update the \ShowCategory model as
public function shows(){
return $this->belongsToMany(Show::class, 'category_show')->where('active', true);
}

Why is the ID replaced with a value from another table? Laravel BelongsTo

I have 4 tables. Championships, Users, Roles and users_roles.
One user belongs to championship as judge. But I have to select only users who have role 'Judge'.
For this, I created new column in championships table which is called "main_judge" and created new relationship
class Championship extends Model
{
...
public function mainJudge()
{
return $this->hasOne('App\User', 'id', 'main_judge');
}
...
}
Then I add to query some code
$query->join('users_roles', 'users.id', '=', 'users_roles.user_id')
->join('roles', 'users_roles.role_id', '=', 'roles.id')
->where('roles.alias', '=', 'judge');
when I print query as sql I got (see screen)
http://joxi.ru/a2X45M1Sw0RpE2
and after $query->get() instead of user ID i got a role ID (see screen)
http://joxi.ru/bmoxMaDs3NVoE2
I would suggest using eloquent rather than the query builder as it will remove the need to manually define any joins.
You should just be able to do this:
$championship = Championship::find($id);
$judge = $championship->mainJudge;
If you then dd($judge) you should end up with the appropriate User object.

Laravel filter using conditions

I have a eloquent model called product. I need to use where condition depends on the status of column in same table. This is my code
public function product_list(Request $request,Datatables $datatables){
$product = Product::where('supplier_id',$request->supplier_id)->where('product','!=',3);
return $datatables->eloquent($product)->filter(function ($query) use ($request) {
if($query->is_from_portalsite==1){
$query->where('status','>',1);
}
})->make(true);
}
I need to check the where condition if the column is_from_portalsite equals to 1. how can I check that in laravel.
Try this (assuming is_from_portalsite is boolean):
$query->where('is_from_portalsite',0)->orWhere('status','>',1);

Resources