Laravel belongsToMany with OR condition - php

How do I create brackets around my orWhere:
public function categories()
{
return $this->belongsToMany('App\Category', 'user_category')->orWhere('default', 1);
}
So it is converted to this:
where (`user_category`.`user_id` = ? or `default` = 1)
Currently the brackets here are missing and mess up the whole query. I tried for example:
public function categories()
{
$join = $this->belongsToMany('App\Category', 'user_category')
->orWhere('default', 1);
return $this->where(function ($query) use ($join) {
return $join;
});
}
But here I am loosing my model and getting Call to undefined method Illuminate\Database\Query\Builder::...

You can use advanced where clause like:
Model::where(function ($query) {
$query->where('a', '=', 1)
->orWhere('b', '=', 1);
})->where(function ($query) {
$query->where('c', '=', 1)
->orWhere('d', '=', 1);
});
Or nested clause like:
Model::where(function($query)
{
$query->where('a', 'like', 'keyword');
$query->or_where('b', 'like', 'keyword');
})
->where('c', '=', '1');

Are you trying to get all the categories related to an user and the categories where the default field is 1?
If that is the case:
public function categories()
{
return $this->belongsToMany('App\Category');
}
public function relatedCategories()
{
return App\Category::all()->where('default',1)->merge($this->categories);
}
The relatedCategories() method should return a collection with the desired categories. Take in care that the non-related categories but with default=1 will not have the pivot object, because these categories doesn't exist in your pivot table.

Related

laravel join select max of joined column

I have 3 table products, details and
detail_colors
I want select max "stock" from "detail_colors" and
max "price" from "details"
$products = Product::
join('details', function (JoinClause $join) {
$join->on('products.id', '=', 'details.product_id');
})
->join('detail_colors', function (JoinClause $join) {
$join->on('products.id', '=', 'detail_colors.product_id');
})
->select('products.*', DB::raw('max(details.price) as price'), DB::raw('max(detail_colors.stock) as stock'))
and its not working.
I use laravel 8.*
Can't you use aggregate functions on relationships?
$products = Product::query()
->withMax('details', 'price')
->withMax('detail_colors', 'stock')
Or you can define the relationship as such:
public function details()
{
return $this->hasOne(Details::class)->ofMany('price', 'max');
}
public function details()
{
return $this->hasOne(DetailColors::class)->ofMany('stock', 'max');
}

Laravel nested relation filter

Have a query, how I can filter results by translation relation (by name column)
$item = Cart::select('product_id','quantity')
->with(['product.translation:product_id,name','product.manufacturer:id,name'])
->where($cartWhere)
->get();
my model
Cart.php
public function product($language = null)
{
return $this->hasOne('App\Models\Product','id','product_id');
}
Product.php
public function translations()
{
return $this->hasMany('App\Models\ProductTranslation','product_id','id');
}
Update v1.0
do like this, but query takes too long time
$item = Cart::select('product_id','quantity')
->with(['product.translation', 'product.manufacturer:id,name'])
->where($cartWhere)
->when($search,function ($q) use ($search) {
$q->whereHas('product.translation', function (Builder $query) use ($search) {
$query->where('name', 'like', '%'.$search.'%');
$query->select('name');
});
}
)
->get() ;
Inside the array within your with() method, you can pass a function as a value.
Cart::select('product_id','quantity')
->with([
'product', function($query) {
$query->where($filteringAndConditionsHere);
}
]);
https://laravel.com/docs/7.x/eloquent-relationships#eager-loading

Laravel Filter using various relations

I am doing a filter using relations here is my controller code:
$userList = User::with(['role' ,'userMetaData','userBet','userComission','userPartnership'])
->where('deleted', '=', '0')
->when($request->parent_id, function ($builder, $parent_id) {
return $builder->where('parent_id', $parent_id);
})
->when($request->role_id, function ($builder, $role_id) {
return $builder->where('role', $role_id);
})
->when($request->to && $request->from , function ($builder) use ($request) {
return $builder->whereBetween('exposure_limit', [$request->from, $request->to]);
})
->when($request->city, function ($builder) use ($request) {
return $builder->whereHas('userMetaData', function($query) use ($request){
$query->where('city', $request->sport);
});
})
->orderBy('created_at', 'DESC')
->get();
In this case(in my code) i am trying to use whereHas() to filter a data from another table(within relations) by eloquent but it's something i am missing:
here in your case, when you use Wherehas to userMetaData it'll filter and gives you only those users who's has city as $request->sport..
In another case, you've used with('userMetaData') which means whatever users you got in filter return all userMetaData.
->when($request->city, function ($builder) use ($request) {
return $builder->whereHas('userMetaData', function($query) use ($request){
$query->where('city', $request->sport);
})->with(['userMetaData' => function($q) use ($request) {
$q->where('city', $request->sport);
}]);
})
Remove userMetaData from User::with(['role','userBet','userComission','userPartnership'])

How to get Billing Address from Eloquent model with where clause?

For example I can use:
$address = $user->address
which will return the addresses for the user.
// User.php (model)
public function address()
{
return $this->hasMany(Address::class, 'refer_id', 'id');
}
public function billingAddress()
{
return $this->address()
->where('type', '=', 1)
->where('refer_id', '=', $this->id)
->first();
}
However, I would like to return the BillingAddress for the user depending on this where clause. How do I do it?
EDIT:
If I use this inside... OrderController#index it returns correctly
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address', 'payment')->get();
return new OrderResource($orders);
However, If I change it to:
$orders = Order::with('order_fulfillment', 'cart.product', 'user.billingAddress', 'payment')->get();
return new OrderResource($orders);
I get this error:
Symfony\Component\Debug\Exception\FatalThrowableError
Call to a member function addEagerConstraints() on null
One option is you can use whereHas in your query. For example,
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address', 'payment')
->whereHas(
'address', function ($query) {
$query->where('type', '=', 1)
->first();
}
)->get();
return new OrderResource($orders);
This is one option. try to dd($orders) an find if its working.
You had an another option like this, in your model
public function address()
{
return $this->hasMany(Address::class, 'refer_id', 'id');
}
Add relations like
public function billingAddress()
{
return $this->hasOne(Address::class, 'refer_id', 'id')->where('type', 1);
}
And
public function shippingAddress()
{
return $this->hasOne(Address::class, 'refer_id', 'id')->where('type', 2);
}
Then in your query,
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address','user.billingAddress', 'user.shippingAddress', 'payment')->get(); return new OrderResource($orders);

Use variable in relationship

I have some customfield functionality on my site where users can add custom fields to a model.
I've just found that if you enter data into one of the fields the same field won't show up for another model because of the way I get the empty fields for a model
public function Customfield()
{
return $this->hasMany(Customfield::class);
}
public function getEmptyCustomfields($model)
{
return $this->has('customfield', '<', 1)
->select('customfieldslabels.id as label_id', 'customfieldslabels.datatype as datatype', 'customfieldslabels.label_name as label_name',
'customfieldslabels.customfield_tab_id as customfield_tab_id', 'customfieldstabs.name as name')
->join('customfieldstabs', 'customfieldstabs.id', '=', 'customfieldslabels.customfield_tab_id')
->where('customfieldstabs.model', '=', $model)
->get();
}
public function getEmptyCustomfieldsByTab($tabIDm)
{
return $this->has('customfield', '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
This is what I had originally and I realised that if a label has a field that is assigned to another model then the relationship exists and won't return as empty for another model.
So I'm trying to also check against the model ID now but I'm not quite sure how to use the model ID while checking the relationship
public function Customfield()
{
return $this->hasMany(Customfield::class);
}
public function customfieldByModel($modelID)
{
return $this->has('customfield' => function ($query) use ($modelID){
$query->where('model_id', '=', $modelID);
})->get();
}
public function getEmptyCustomfields($model, $modelID)
{
return $this->has($this->customfieldByModel($modelID), '<', 1)
->select('customfieldslabels.id as label_id', 'customfieldslabels.datatype as datatype', 'customfieldslabels.label_name as label_name',
'customfieldslabels.customfield_tab_id as customfield_tab_id', 'customfieldstabs.name as name')
->join('customfieldstabs', 'customfieldstabs.id', '=', 'customfieldslabels.customfield_tab_id')
->where('customfieldstabs.model', '=', $model)
->get();
}
public function getEmptyCustomfieldsByTab($tabIDm, $modelID)
{
return $this->has($this->customfieldByModel($modelID), '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
I would like to return empty fields for one model that they haven't been filled in for yet.
They return just find once there is data for a model assigned to a field as it doesn't need to check for empty fields anymore.
UPDATE
I've tried using a left join which I think will work but I can't get to the method because I get an error saying: 'The method name must be a string'
I changed this
public function getEmptyCustomfieldsByTab($tabID, $modelID)
{
return $this->has($this->customfieldByModel($modelID), '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
To this:
public function getEmptyCustomfieldsByTab($tabID, $modelID)
{
return $this->has('customfieldbymodel', '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
But now I can't send the $modelID as a parameter. Is it possible to sned a parameter while doing a has?
MY SOLUTION
I have created a protected variable on the model that just gets reassigned everytime.
protected $modelID;
public function customfieldByModel()
{
return $this->hasMany(Customfield::class)->where('model_id', '=', $this->modelID);
}
public function getEmptyCustomfields($model, $modelID)
{
$this->modelID = $modelID;
return $this->has('customfieldByModel', '<', 1)
->select('customfieldslabels.id as label_id', 'customfieldslabels.datatype as datatype', 'customfieldslabels.label_name as label_name',
'customfieldslabels.customfield_tab_id as customfield_tab_id', 'customfieldstabs.name as name')
->join('customfieldstabs', 'customfieldstabs.id', '=', 'customfieldslabels.customfield_tab_id')
->where('customfieldstabs.model', '=', $model)
->get();
}
public function getEmptyCustomfieldsByTab($tabID, $modelID)
{
$this->modelID = $modelID;
return $this->has('customfieldByModel', '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}

Categories