Laravel remove parent if related collection - laravel

I have a model with a related collection
now im doing this query
$data = DeliveryPartner::when($filter, function ($q) use ($request) {
})
->with(['orders' => function ($query) {
$query
->where('delivery_partner_invoice_id', '=', '')
->orWhereNull('delivery_partner_invoice_id')
->whereIn('status', ['payment-accepted', 'completed', 'full-refund', 'partial-refund']);
}])->get();
Now i am wondering. If the orders returns empty is it posible to remove this parent from the collection?
I Know i can do this after the eloquent query with a loop. But is it possible to do this in the query?

we cant completely remove that parent ( with index ) BUT you can set those to null using transform() like this;
$data = DeliveryPartner::when($filter, function ($q) use ($request) {
})
->with(['orders' => function ($query) {
$query
->where('delivery_partner_invoice_id', '=', '')
->orWhereNull('delivery_partner_invoice_id')
->whereIn('status', ['payment-accepted', 'completed', 'full-refund', 'partial-refund']);
}])->get()->transform(function($item){
if(!$item->orders->count() ){
return;
}
return $item;
});
Note: this will not completely remove those parents but it will set them to empty.

Related

How to filter by relation column Laravel

How to filter by relation column
tried this
->whereHas('customer',function ($query) use ($order){
$query->orderBy('first_name', $order);
})
and this
->with(['customer' => function ($query) use ($order) {
$query->orderBy('first_name', $order);
}])
Both did not work
with() are using eager loading, which turns this into two queries.
You need to use join() instead of with()
$orders = Order
::join('customers', 'order.customer_id', '=', 'customers.id')
->orderBy('customers.first_name')
->get();
OR
You may use sortBy() or sortByDesc() methods of Collection.
For example:
$orders = Order
::with('customer')
->get()
->sortBy('customer.first_name');
request {{host}}/admin/showcases?filterBy=companies:name it order by relation column companies
if simple {{host}}/admin/showcases?filterBy=name
it will be only orderBy("name")
->when(str_contains($filterBy, ':'),
function (Builder $query) use ($filterBy, $order, $columns) {
$table = explode(':', $filterBy)[0];
$key = Str::singular($table) . "_id";
$column = explode(':', $filterBy)[1];
$selfTable = $this->getTable();
$query->leftJoin($table, "$selfTable.$key", "$table.id")
->when($columns !== ['*'],
function ($query) use ($columns, $selfTable) {
$columns = array_map(function ($column) use ($selfTable) {
return "$selfTable.$column";
}, $columns);
$query->select($columns);
},
fn($query) => $query->select(["$selfTable.*"]))
->orderBy("$table.$column", $order);
},
function ($query) use ($filterBy, $order) {
$query->orderBy($filterBy, $order);
})

Laravel query with relationship where have all ids

I try to do a query where I get a room where I have all the services.
With my current code I get the room that has at least one of the services from the array, because I am using whereIn.
$rooms = Room::select([
'rooms.id',
'rooms.available_from',
'rooms.available_till',
'rooms.description',
'rooms.room_type_id',
'room_types.name as room_types_name',
])
->leftJoin('room_types', 'room_types.id', 'rooms.room_type_id')
->with('services','reserved_rooms')
->when($request->services, function ($query) use ($request) {
$query->whereHas('services', function ($q) use ($request) {
$q->whereIn('id', $request->services);
});
})
->orderByDesc('id')
->get();
If you want to match all services, you can use for loop to create AND query.
Try below code:
->when($request->services, function ($query) use ($request) {
foreach ($request->services as $key => $service) {
$query->whereHas('services', function ($q) use ($service) {
$q->where('id', $service);
});
}
})
->when($request->services, function ($query) use ($request) {
$query->whereHas('services', function ($q) use ($request) {
$q->selectRaw('count(distinct id)')->whereIn('id', $request->services);
}, '=', count($request->services)
);
})
Changed it,not tested but this is the general idea: get the rows where the COUNT of distinct ids is equal to the length of array.The array should be unique.

Laravel - Filter collection with closure on relationship

Wondering if there is a way to use closure on a relationship in order to filter the whole line if there isn't a value which corresponds?
Example code:
foreach ($paiementMethods as $value) {
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods' => function($query) use ($value)
{
$query->where('id', $value);
}])
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')->get();
$giftCardsCollection = $giftCardsCollection->merge($giftCards);
}
}
In this example, if $query->where doesn't find a row for the payement.payementMethods which matches the $value, I want the giftCard to return null. The result I get is the giftCard with only the relation on payement.payementMethods being empty.
My other solution would be to query the giftCard and after that checking the $value to see if I have to include the giftCard in the collection or not.
Best regards
I think using whereHas, it can be solved
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods'])
->whereHas( 'payement.payementMethods', function($query) use ($paiementMethods) {
$query->whereIn('id', $paiementMethods);
})
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')
->get();

Laravel search with relations

I have the following relations in my Laravel application
class Item extends Model
{
public function category()
{
return $this->belongsTo('App\Category');
}
}
and
class Category extends Model
{
public function item()
{
return $this->hasMany('App\Item');
}
}
I want to implement search functionality so I have created the following Eloquent query:
$items = Item::where('item_type', '=', 'type1')
->where(function($query) use ($q) {
$query->where('item_name','LIKE','%'.$q.'%')
->orWhere('item_description','LIKE','%'.$q.'%');
})
->paginate(10);
This is working as expected and returns the search results for 'q' based on the name and the description of the item.
As a next step, I would like to also search for the category_name. Because of the relation, I have the category_id stored in the Items table, but I would like to use the category_name in my Eloquent query.
Anyone could provide some help?
Based on feedback received, I tried:
Suggestion 1:
$items = Item::where('item_type', '=', 'type1')
->where(function($query) use ($q) {
$query
->where('item_name', 'LIKE' ,'%'.$q.'%')
->orWhere('item_description', 'LIKE' ,'%'.$q.'%');
})
->whereHas('category', function (Category $query) use ($q) {
$query->where('category_name', $q);
})
=> this gives following error message:
Argument 1 passed to
App\Http\Controllers\ItemController::App\Http\Controllers{closure}()
must be an instance of App\Http\Controllers\App\Category, instance of
Illuminate\Database\Eloquent\Builder given
Suggestion 2:
$items = Item::where('item_type', '=', 'type1')
->where(function($query) use ($q) {
$query
->where('item_name', 'LIKE' ,'%'.$q.'%')
->orWhere('item_description', 'LIKE' ,'%'.$q.'%');
})
->whereHas('category', function ($query) use ($q) {
$query->where('category_name', $q);
})
=> this does not result any search result anymore (also not for item_name and item_description).
Solution
$items = Item::where('item_type', '=', 'type1')
->where(function($query) use ($q) {
$query
->where('item_name', 'LIKE' ,'%'.$q.'%')
->orWhere('item_description', 'LIKE' ,'%'.$q.'%');
})
->orWhereHas('category', function ($query) use ($q) {
$query->where('category_name', $q);
})
->sortable(['id' => 'desc'])
->paginate(10);
As you already described relation to Category in your Item model, you have to use just whereHas method:
$items = Item::where('item_type', '=', 'type1')
->where(function($query) use ($q) {
$query->where('item_name','LIKE','%'.$q.'%')
->orWhere('item_description','LIKE','%'.$q.'%');
})
->orWhereHas('category', function ($query) use ($q) {
$query->where('category_name', 'LIKE', "%$q%");
})
->paginate(10);
You could add a whereHas and constrain it. For example:
$items = Item::where('item_type', '=', 'type1')
->where(function($query) use ($q) {
$query->where('item_name','LIKE','%'.$q.'%')
->orWhere('item_description','LIKE','%'.$q.'%');
})
->whereHas('category', function($query) {
$query->where('category_name', 'name');
})
->paginate(10);

Callback function of with() returns empty collection

I have three tables: realties, room_types and realty_room_type:
realty_room_type
----------------
id
realty_id
room_type_id
room_type
----------------
id
code
In my Realty model I set a rooms() relationship:
public function rooms()
{
return $this->hasMany(Room::class);
}
I am trying to eager load the rooms() relationship using the with() method. I want to custom what is returned from the relationship, so I am passing a callback function like this:
$realty = Realty::
where('id', $realtyId)
->with([
'rooms' => function ($query) use ($realtyId) {
$query
->leftJoin('room_types', 'room_types.id', '=', 'realty_room_type.room_type_id')
->selectRaw('code, COUNT(*)')
->groupBy('code');
}
])
->get()
);
The problem is I get an empty collection when accessing the relationship using $realty->rooms. Any idea why?
However if I dump and die the statements of the callback function like this:
Realty::
where('id', $realtyId)
->with([
'rooms' => function ($query) use ($realtyId) {
dd($query
->leftJoin('room_types', 'room_types.id', '=', 'realty_room_type.room_type_id')
->selectRaw('code, COUNT(*)')
->groupBy('code'));
}
])
->get()
);
I get what I'd like to be in the rooms() relationship.
Thank you in advance.
You don't need to return inside callback function and call get(). Here you can find the details.
$realty = Realty::
where('id', $realtyId)
->with([
'rooms' => function ($query) use ($realtyId) {
$query
->leftJoin('room_types', 'room_types.id', '=', 'realty_room_type.room_type_id')
->selectRaw('code, COUNT(*)')
->groupBy('code');
}
])
->get();

Resources