coming from this relationship from the docs:
https://laravel.com/docs/9.x/eloquent-relationships#advanced-has-one-of-many-relationships
/**
* Get the current pricing for the product.
*/
public function currentPricing()
{
return $this->hasOne(Price::class)->ofMany([
'published_at' => 'max',
'id' => 'max',
], function ($query) {
$query->where('published_at', '<', now());
});
}
how can I make such an relation with a specific date?
The relation down below will work
/**
* Get pricing for the product of one specific date.
*/
public function priceOfDay(Carbon $date)
{
return $this->hasOne(Price::class)->ofMany([
'published_at' => 'max',
'id' => 'max',
], function ($query) {
$query->where('published_at', '<', $date());
});
}
but how can I use it with Eloquent? How can I pass the date to this:
Product::with('priceOfDay')->get();
update
I now use the one to many relation with a closure
->with(['prices' => function ($query) use ($month) {
$query->where('published_at', '<', $month)
->orderByDesc('published_at')
->orderByDesc('id')
->first();
}])
it works with the little drawback of having a collection instead of an object as relation, but it fills my needs for the moment.
It would be nice if there was something like
->with(['relation', $param])
update 2
since there seems to bo no direct solution here the workarround i came up with:
->first() does not work in the query, you will end up getting all prices, so I finished with an each()
->with(['prices' => function ($query) use ($month) {
$query->where('published_at', '<', $month)
->orderByDesc('published_at')
->orderByDesc('id');
}])
->get()
->each(function ($product) {
$product->price = $product->prices->first()->price;
})
**
How can I make this code easy . i use this query() function for many section
i want to get event by filter. my filter based on tags and category(both are in pivot table)
**
public function index(Request $request)
{
$customQuery = Event::where('status', '1');
if ($request->vehical_type) { //vehical filter
$customQuery->where('vehical_type', '=', $request->vehical_type);
}
if ($request->tag) { //tag filter
$id = $request->tag;
$customQuery->whereHas('tags', function (Builder $query) use ($id) {
$query->where('tag_id', $id);
});
}
if ($request->category) { //category filter
$id = $request->category;
$customQuery->whereHas('categories', function (Builder $query) use ($id) {
$query->where('category_id', $id);
});
}
$events = $customQuery->get(); //get event according to filters
$tags = Tag::whereHas('events', function (Builder $query) { //get all tags of events
$query->where('event_id', '>', 0);
})->get();
$categories = Category::whereHas('events', function (Builder $query) { //get all categories of events
$query->where('event_id', '>', 0);
})->get();
return view('frontend.event.index', compact('events', 'tags', 'categories'));
}
You could use when for conditionals in the query and short hand closures with fn to put them in a single line.
whereRelation instead of whereHas could make those queries a bit shorter too.
public function index(Request $request)
{
$events = Event::query()
->where('status', '1')
->when(
$request->vehical_type,
fn($query) => $query->where('vehical_type', $request->vehical_type)
)
->when(
$request->tag,
fn($query) => $query->whereRelation('tags', 'tag_id', $request->tag)
// or fn($query) => $query->whereHas('tags', fn($tags) => $tags->where('tag_id', $request->tag))
)
->when(
$request->category,
fn($query) => $query->whereRelation('categories', 'category_id', $request->category)
// or fn($query) => $query->whereHas('categories', fn($category) => $category->where('category_id', $request->category))
)
->get();
$tags = Tag::query()
->whereRelation('events', 'event_id', '>', 0)
// or ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
$categories = Category::query()
->whereRelation('events', 'event_id', '>', 0)
// or ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
return view('frontend.event.index', compact('events', 'tags', 'categories'));
}
You could also maybe use a query scope to put the search in the Event model.
# Event.php
public function scopeSearch(Builder $query, array $filter = [])
{
return $query
->when(
array_key_exists('vehicle_type', $filter),
fn($query) => $query->where('vehical_type', $filter['vehicle_type'])
)
->when(
array_key_exists('tag', $filter),
fn($query) => $query->whereRelation('tags', 'tag_id', $filter['tag'])
// or fn($query) => $query->whereHas('tags', fn($tags) => $tags->where('tag_id', $filter['tag']))
)
->when(
array_key_exists('category', $filter),
fn($query) => $query->whereRelation('categories', 'category_id', $filter['category'])
// or fn($query) => $query->whereHas('categories', fn($category) => $category->where('category_id', $filter['category']))
);
}
public function index(Request $request)
{
$filter = [
'vehicle_type' => $request->vehicle_type,
'tag' => $request->tag,
'category' => $request->category,
];
$events = Event::query()
->where('status', '1')
->search($filter)
->get();
$tags = Tag::query()
->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
$categories = Category::query()
->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
return view('frontend.event.index', compact('events', 'tags', 'categories'));
}
You can use whereRelation for getting instead of using whereHas.
$customQuery->whereRelation('tags', 'tag_id', $id)
Using this structure you can shortan your code and optimize.
there is other relationship query method introduced in newer version check here
// Get event according to filters
$events = Event::where('status', '1')
->when($request->get('vehicle_type'), function ($query, $vehicleType) {
$query->where('vehical_type', '=', $vehicleType);
})
->when($request->get('tag'), function ($query, $tagId) {
$query->whereHas('tags', function ($query) use ($tagId) {
$query->where('tag_id', $tagId);
});
})
->when($request->get('category'), function ($query, $categoryId) {
$query->whereHas('categories', function ($query) use ($categoryId) {
$query->where('category_id', $categoryId);
});
})
->get();
You can use the when method for these types of conditions. You can view the documentation here.
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);
})
$studentIds = ExamRoutineDetail::where('routine_id', $routineId)
->distinct()
->pluck('student_id')
->all();
$data = Student::whereIn('id', $studentIds)
->where('school_id', $schoolId)
->where('grade_id', $gradeId)
->with([
'routine_detail' => function ($query) use ($routineId) {
$query->where('routine_id', $routineId);
},
'routine_detail.routine',
'routine_detail.routine.routine_info' => function ($query) use ($routineId) {
$query->where('routine_id', $routineId);
},
'routine_detail.routine.routine_info.student_marks' => function ($query) use ($studentIds) {
$query->where('student_id', $studentIds);
},
])
->get();
I want to use the student's id in the final where condition in the last layer of the nested eagerloading i.e. routine_detail.routine.routine_info.student_marks.
so something like this
'routine_detail.routine.routine_info.student_marks' => function ($query) use ($studentIds) {
$query->where('student_id', $id);
},
where id would be equal to the id of the student in context, from the main Student:: .... model.
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.