How to apply condition in relationship methods from controller? - laravel

I have three model MainCategory, Subcategory and Menu
Main category Model
protected $table="main_categories";
protected $fillable =['category'];
public function subCategories()
{
return $this->hasMany(SubCategory::class,'maincategory_id');
}
Sub Category Model
protected $table="sub_categories";
protected $fillable =['category','maincategory_id'];
public function foods()
{
return $this->hasMany(Menu::class,'subcategory_id');
}
Menu Model
protected $table="menus";
protected $fillable = [
'resturant_id',
'maincategory_id',
'subcategory_id',
'foodtype_id',
'food_name',
'slug',
'food_price',
'food_image'
];
public function mainCategory()
{
return $this->belongsTo(MainCategory::class,'maincategory_id');
}
public function subCategory()
{
return $this->belongsTo(SubCategory::class,'subcategory_id');
}
Problem is in my Controller
$data['main_category'] = MainCategory::with(['subCategories', 'menus'])
->whereHas('subCategories.foods', function ($q) use ($resturantid) {
return $q->where('resturant_id', $resturantid);
})
->whereHas('menus', function ($q) use ($resturantid) {
return $q->where('resturant_id', $resturantid);
})
->get();
I want to apply condition in subcategories foods() method where resturant_id is resturant.id.
But it is showing all the resturants data.
I have applied subquery with notation as well but did not help

I am not sure if this is want you want, but could you try the following:
$data['main_category'] = MainCategory::with([
'subCategories.foods' => function ($q) use ($resturantid) {
$q->where('resturant_id', $resturantid);
},
'menus'
])
->whereHas('subCategories.foods', function ($q) use ($resturantid) {
return $q->where('resturant_id', $resturantid);
})
->whereHas('menus', function ($q) use ($resturantid) {
return $q->where('resturant_id', $resturantid);
})
->get();
This will only load the foods from the subCategories where the resturant_id matches the $resturantid

Related

How to show Laravel model with belongsToMany connection if has specified connection?

I have this product model:
public function categories() {
return $this->belongsToMany('App\Category', 'product_categories');
}
And in my controller:
public function search(Request $request) {
return Product::with([
'categories' => function($categories) use ($request) {
// ...
}
]);
}
If I try to use $request in the categories function it's search only in categories, but shows all products.
How do I show only that products whitch has defined categories in $request->category_id?
you may use the whereHas keyword in laravel:
public function search(Request $request) {
return Product::with('categories')
->whereHas('categories', function ($query) use ($request){
$query->where('category_id', $request->category_id);
})->get();
}
Here is the docs
You can search it in following way:
public function search(Request $request) {
return Product::with('categories')
->whereHas('categories', function ($q) use (request) {
$q->where('id', $request->category_id);
});
}

How can I solve "Relation 'a' is not instance of HasOne or BelongsTo." in the laravel?

My laravel eloquent like this :
$query = ItemDetail::selectRaw('a.item_number, sum(abs(a.quantity)) as "total_quantity"')
->from('item_detail as a')
->join('items as b', 'b.id', '=', 'a.item_number');
if(isset($param['vendor'])) {
$query = $query->where('b.vendor_id', '=', $param['vendor']);
}
$query = $query->groupBy('a.item_number')
->paginate($paged);
return $query;
If the query executed, there exist error like this :
Relation 'a' is not instance of HasOne or BelongsTo.
How can I solve this problem?
Update
My item model like this :
class Item extends Model
{
...
protected $fillable = [
'name',
'vendor_id'
];
public function item_details()
{
return $this->hasMany(ItemDetail::class, 'id', 'item_number');
}
}
My item detail model like this :
class ItemDetail extends Model
{
....
protected $fillable = [
'item_number',
'name',
'posting_date'
];
public function item()
{
return $this->belongsTo(Item::class, 'id', 'item_number');
}
}
According to your few details, please confirm if this is what you want:
Item Model:
class Item extends Model
{
...
protected $fillable = [
'name',
'vendor_id'
];
public function item_details()
{
return $this->hasMany(ItemDetail::class, 'item_number', 'id');
}
}
ItemDetail Model:
class ItemDetail extends Model
{
....
protected $fillable = [
'item_number',
'name',
'posting_date'
];
public function item()
{
return $this->belongsTo(Item::class, 'item_number', 'id');
}
}
Controller Method:
$itemDetails = ItemDetail::whereHas('item', function($q) use ($param) {
if (isset($param['vendor']){
$q->where('vendor_id', '=', $param['vendor']);
}
})
->selectRaw('item.id', 'item_detail.item_number', 'sum(abs(a.quantity)) as total_quantity')
->groupBy('item_number')->paginate($paged);
View file:
#foreach($itemDetails as $itemDetail)
#dump($itemDetail->item_number)
#dump($itemDetail->total_quantity)
#endforeach
It makes more sense to access the main model you want and include in it, the relationships you need to include.
Here's a potential different solution:
$query = Item::with(['item_details' => function ($query) {
$query->groupBy('item_number')->selectRaw("item_number, sum(abs(a.quantity)) as 'total_quantity'");
}]);
if (isset($param['vendor'])) {
$query->where('vendor_id', $param['vendor']);
}
$itemsPage = $query->paginate($paged);
return $pages;
You can access the paged data if you do:
foreach ($itemsPage as $item) {
// $item is an instance of Item
// $item->item_details->total_quantity should have the sum of the item details
}
I can only guess because of too few information: your model is missing something like this:
public function a()
{
return $this->belongsTo(RelatedModel::class);
}

Relationships in Laravel Models

How can I write this without a join for a scope in a Laravel model as the 'id' field becomes ambiguous
/**
* Return events that social category name
*/
public function scopeWithSocialEvents($query)
{
return $query->join('categories', 'events.event_type_id', '=', 'categories.id')
->where('categories.name', 'social');
}
Use this:
public function eventType()
{
return $this->belongsTo(Category::class);
}
public function scopeWithSocialEvents($query)
{
return $query->whereHas('eventType', function($query) {
$query->where('name', 'social');
});
}

Laravel: Combining multiple query scopes on nested relationships without overriding the previous ones

I've got the following database structure for an online learning platform: A course consists of modules. A module consists of lessons and tasks. There are user specific information for each of these elements with the respective relationships defined on each model:
class Course extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('start_at', 'end_at');
}
public function modules() {
return $this->hasMany(Module::class);
}
// ...
}
class Module extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('start_at', 'end_at');
}
public function lessons() {
return $this->hasMany(Lesson::class);
}
public function tasks() {
return $this->hasMany(Lesson::class);
}
}
class Lesson extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('favourite', 'completed_at');
}
}
class Task extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('completed_at');
}
}
My goal is to load a complete course with the following scopes on the course model:
class Course extends Model {
// ...
public function scopeWithModules($query) {
return $query->with(['modules' => function ($q) {
$q->with(['user' => function ($q) { $q->where('user_id', auth()->user()->id); }])
->whereHas('user', function ($q) { $q->where('user_id', auth()->user()->id); });
}]);
}
public function scopeWithLessons($query) {
return $query->with(['modules.lessons' => function ($q) {
$q->with(['user' => function ($q) { $q->where('user_id', auth()->user()->id); }])
->whereHas('user', function ($q) { $q->where('user_id', auth()->user()->id); });
}]);
}
public function scopeWithTasks($query) {
return $query->with(['modules.tasks' => function ($q) {
$q->with(['user' => function ($q) { $q->where('user_id', auth()->user()->id); }])
->whereHas('user', function ($q) { $q->where('user_id', auth()->user()->id); });
}]);
}
// ...
}
Each of these scopes alone is working fine. But combining them will override the previous ones, so only the last of these scopes will be executed.
Executing this
$course = Course::whereSlug('learning-abc')
->withModules()
->withLessons()
->withTasks()
->firstOrFail();
will give me the course with modules and tasks (but no lessons and user information for the modules).
Of course I can write one single bulky scope like withModulesLessonsTasks() but I hope there is a more elegant solution to this. Any ideas?
Before I had:
$course = Course::whereSlug('learning-abc')
->with([
'modules.user',
'modules.lessons.user',
'modules.tasks.user'
])
->firstOrFail();
which was working fine except for filtering the auth()->user().

Subrelationships not using previous conditions

I'm using Laravel 4. I have the following models:
class User extends Eloquent {
protected $table = 'users';
public function questions()
{
return $this->hasMany('UserQuestion', 'user_id', 'user_id');
}
}
class UserQuestion extends Eloquent {
protected $table = 'user_questions';
public function user()
{
return $this->belongsTo('User', 'user_id', 'user_id');
}
public function subquestions()
{
return $this->hasMany('UserSubquestion', 'question_id', 'id');
}
}
class UserSubquestion extends Eloquent {
protected $table = 'user_subquestions';
public function question()
{
return $this->belongsTo('UserQuestion', 'question_id');
}
public function answers()
{
return $this->hasMany('UserAnswer', 'subquestion_id', 'id');
}
}
class UserAnswer extends Eloquent {
protected $table = 'user_answers';
public function subquestion()
{
return $this->belongsTo('UserSubquestion', 'subquestion_id');
}
}
I have the following query:
$results = User::with(['questions' => function($query) {
$query->where('status', '1');
$query->where('category', 'medicine');
}])
->with('questions.subquestions', 'questions.subquestions.answers')
->get();
However, the where conditions I'm applying to the questions relationship aren't being applied to the joined tables (subquestions and answers).
How can I make the conditions apply to them as well?
Note: The values of status and category in the conditions are dynamic (i.e. won't always be 1 or medicine).
Try doing your call like this instead:
$results = User::with(['questions' => function($query) {
$query->where('status', '1');
$query->where('category', 'medicine');
},
'questions.subquestions',
'questions.subquestions.answers'
])->get();
Note, this time the method with is only called once.

Resources