Laravel call relation from model in when() conditional clauses - laravel

I am creating product filtering and now I have problem when I want to filter product category by name.
I am not sure if is possible to call relation inside when() conditional clauses.
In the product controller, I create:
$results = Product::query();
// Conditional filter
$results->when($request->has('product_code'), function ($q) use ($request) {
return $q->where('product_code', 'like', '%'.$request->query('product_code').'%');
});
$results->when($request->has('status'), function ($q) use ($request) {
return $q->where('status', $request->query('status'));
});
$results->when($request->has('price'), function ($q) use ($request) {
return $q->where('price', $request->query('price'));
});
// Filter by category NAME
// HERE IS PROBLEM
$results->when($request->has('category_name'), function ($q) use ($request) {
return $q->category->where('name', $request->query('cat_name'));
});
// I also try
// This return SQLSTATE[42S22]: Column not found: 1054 Unknown column 'category.name' in 'where clause' (SQL: select count(*) as aggregate from `products` where `category`.`name` = Apple)
$results->when($request->has('category_name'), function ($q) use ($request) {
return $q->where('category.name', $request->query('cat_name'));
});
$results = $results->paginate(20);
Model:
class Product
{
public function category()
{
return $this->hasOne('App\Models\Category', 'id', 'category_id');
}
}

for this filtering do this:
$filter = [];
if($request->product_code!= null)
array_push($filter, ['product_code', 'like', "%$request->product_code%"]);
if($request->price)
array_push($filter, ['price', $request->price]);
// and so on ...
then you have array of conditions, just call where and pass the array:
$results = Product::where($filter);

How about that?
$category_ids = Category::where('category_name', $request->query('category_name'))->pluck('id');
$results = Product::select("*")->when($request->has('category_name'), function ($query) use ($request, $category_ids) {
return $query->whereIntegerInRaw('category_id', $category_ids);
})->get();

Related

Laravel How to get `->sum('count')` in `whereHas` subquery?

I have 3 model Transaction , Cart , Acceptedcart.
in Cart model I have transaction_id and in Acceptedcart model have cart_id.
in Transaction.php my relationship to carts:
public function carts()
{
return $this->hasMany(Cart::class);
}
in Cart.php my relationship to accepted carts :
public function accepted_carts()
{
return $this->hasMany(Acceptedcart::class);
}
And the query to get the transactions where acceptedcart->sended== false:
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) {
$query->where('sended', false);
})->get();
Now I want to get sum() of count column in acceptedcart, where I can set the sum()?
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) {
$query->where('sended', false);
})->sum('count);
Or
$transactions = Transaction::whereHas('carts.accepted_carts', function ($query) {
$query->where('sended', false)->sum('count');
})->get();
is there Only one way that foreach on the ->get() result ?
Try this
Transaction.php
public function accepted_carts()
{
return $this->hasManyThrough(Acceptedcart::class, Cart::class);
}
Query
$transactions = Transaction::query()
->whereHas('accepted_carts', fn ($query) => $query->where('sended', false))
->withCount([
'accepted_carts' => fn ($query) => $query->select(DB::raw('SUM(count) as accepted_carts_sum'))
])
->get();

How to filter by date in Eloquent relationship

I've two tables first_levels and second_levels the first_levels have a relationship with themselves as parent and child and in the second table, I store the transactions.
my Model:
public function children()
{
return $this->hasMany(first_level::class, 'parent_id', 'Nominal')
->with(['children', 'transactions'])
->withsum('transactions', 'debit')
->withsum('transactions', 'credit');
}
public function transactions()
{
return $this->hasMany(second_level::class, 'first_level_id', 'id');
}
my controller:
function getGeneralLedger(Request $request)
{
$items = first_level::with('children')
->where('parent_id', 0)
->where('company_id', $request->user()->company_id)
->get();
return response()->json(['data' => $items]);
}
using this model and controller I can get all the data from the first and second tables but when I want to filter the second table based on the created_at column I'm unable to do it.
I tried this method but it didn't work.
function getGeneralLedger(Request $request)
{
$items = first_level::with('children')
->where('parent_id', 0)
->where('company_id', $request->user()->company_id)
->wherebetween('children.transactions.created_at', [$request->from, $request->to])
->get();
return response()->json(['data' => $items]);
}
I get this error
Column not found: 1054 Unknown column 'children.transactions.created_at' in 'where clause' (SQL: select * from `first_levels` where `parent_id` = 0 and `company_id` = 1 and `children`.`transactions`.`created_at` between 2022-01-10 and 2022-02-09)",
try
function getGeneralLedger(Request $request)
{
$items = first_level::with('children')
->where('parent_id', 0)
->where('company_id', $request->user()->company_id)
->whereHas('children.transactions', function ($q) use ($request) {
$q->wherebetween('created_at', [$request->from, $request->to]);
})
->get();
return response()->json(['data' => $items]);
}
Source: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

Why is the model loading while whereHas is false?

I have this query:
$result = PortingItem::whereHas('porting', function ($query) {
$query->whereIn('status', [
Porting::STATUS_REQUESTED,
Porting::STATUS_ACCEPTED,
Porting::STATUS_DELAYED,
]);
})->where(function ($query) use ($numbers) {
$query->whereBetween('phone_number_start', [$numbers[0], $numbers[1]])
->orWhereBetween('phone_number_end', [$numbers[0], $numbers[1]]);
})->orWhere([
['phone_number_start', '<=', $numbers[0]],
['phone_number_end', '>=', $numbers[1]],
])->get();
The PortingItem model still returns the query result while the porting relation is empty. I don't understand why this happens.
This is my Porting model relation
public function items()
{
return $this->hasMany(PortingItem::class);
}
This is my PortingItem model relation:
public function porting()
{
return $this->belongsTo(Porting::class);
}
You should always group orWhere calls in order to avoid unexpected behavior when global scopes are applied.
$result = PortingItem::whereHas('porting', function ($query) {
$query->whereIn('status', [
Porting::STATUS_REQUESTED,
Porting::STATUS_ACCEPTED,
Porting::STATUS_DELAYED,
]);
})->where(function ($query) use ($numbers) {
$query->where(function ($query) use ($numbers) {
$query->whereBetween('phone_number_start', [$numbers[0], $numbers[1]])
->orWhereBetween('phone_number_end', [$numbers[0], $numbers[1]]);
})->orWhere(function ($query) use ($numbers) {
$query->where('phone_number_start', '<=', $numbers[0])
->where('phone_number_end', '>=', $numbers[1]);
});
})->get();
https://laravel.com/docs/8.x/queries#logical-grouping

Laravel remove parent if related collection

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.

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

Resources