how to sum in subquery in laravel - laravel

i want to sum in addselect() function but it show me error.
I have 2 model as see there:
1.jewelItem model:
protected $table = 'jewel_items';
public function buyInvoice(){
return $this->belongsTo(BuyInvoice::class,'buy_invoice_id');
}
2.buyInvoice model:
protected $table = 'buy_invoices';
public function jewelsItems(){
return $this->hasMany(JewelsItems::class);
}
and every jewelItem has weight column.
my query:
$buyInvoice=BuyInvoice::addSelect(['allWeight'=>JewelsItem::whereColumn('buy_invoices.id','buy_invoice_id')->sum('weight')
])->get();
but it show me this error:
Column not found: 1054 Unknown column 'buy_invoices.id' in 'where clause' (SQL: select sum(`weight`) as aggregate from `jewel_items` where `buy_invoices`.`id` = `buy_invoice_id`)
how can i fix this without using Raw method, cause as here says "Raw statements will be injected into the query as strings" and it's vulnerable.

In newer version of laravel you can use withSum to get sum of weights for related jewelsItems
$buyInvoice=BuyInvoice::withSum('jewelsItems', 'weight')
->orderBy('jewelsItems_sum_weight')
->get();
Or in older versions you could use withCount for sum as
$buyInvoice= BuyInvoice::withCount([
'jewelsItems as allWeight' => function ($query) {
$query->select(DB::raw("sum(weight)"));
}
])->orderBy('allWeight')
->get();

you forgot use join in this subquery
JewelsItem::whereColumn('buy_invoices.id','buy_invoice_id')->sum('weight')

Instead of doing a custom count subquery, Laravel has syntaxic sugar for doing this, utilizing the method withSum(). An example of that could be.
$data = Model::query()->withSum('relation.subRelation','weight')->get();

Related

Use Pivot Table to Fetch Data from Main Table

I am using two tables and a pivot table
Table 1 named calendars.
Table 2 named calendar_groups.
Pivot table calendar_calendar_group.
I'm trying to get data from Table 1 based on a where value in the pivot table. Where calendar_groups_id = 1 then use calendar_id to get data from table 1. I can't get it to work.
$event = new Calendar();
$event->orderBy('start', 'asc')
->whereHas('calendar_groups', function ($q) {
$q->wherePivot('calendar_groups_id', '=', '1');
})->with('calendar_groups')
->first();
This gives me the following error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'pivot' in
'where clause'
This is the relationship:
public function calendar_groups()
{
return $this->belongsToMany(CalendarGroup::class);
}
Your help is very much appreciated.
I think #Tpojka is right here. If you're trying to get Calendar instances that belong to desired CalendarGroup then replace the code should look like this:
$event = new Calendar();
$group = 1;
$event->orderBy('start', 'asc')
->whereHas('calendar_groups', function ($q) use ($group) {
//$q->wherePivot('calendar_groups_id', '=', $group);
$q->where('id', '=', $group);
})->with('calendar_groups')
->first();
If I'm reading the documentation correctly wherePivot() should be used like this:
$event = new Calendar();
$event->calendar_groups()->wherePivot('some_pivot_column',1)->get();
But this would return you the CalendarGroup instances.
If you'd want to do it through Eloquent but without going all the way to the CalendarGroup then you'd probably need to create a Model (let's call it CalendarCalendarGroupPivot) for the pivot table and add another relation (hasMany('CalendarCalendarGroupPivot')) to your Calendar model.
Ok finally got it working.
I used your suggestions but still don't understand a little part of it.
When I use the suggestions made:
$event = new Calendar;
$event->orderBy('start', 'asc')
->whereHas('calendar_groups', function($q) {
$q->where('calendar_group_id', '=', '1');
})->with('calendar_groups')
->first();
I get an empty collection.
But if I run this:
$event = Calendar::orderBy('start', 'asc')
->whereHas('calendar_groups', function($q) {
$q->where('calendar_group_id', '=', '1');
})->with('calendar_groups')
->first();
I get the desired results
Can anybody tell me the difference between so I can learn from it?

Laravel Repositories whereHas -- multiple

I have the following repository Products and each product can have many Categories and many Bidders
What I am trying to achieve is the following (Without Repository)
$products = Products::whereHas('categories', function ($category) {
})->whereHas('bidders', function ($bidder) {
})->get();
This works fine, however, I am trying to make it so that repositories are in place and you can still do the whereHas query, so in my repository I created a method:
public function whereHas($attribute, \Closure $closure = null)
{
return $this->model->whereHas($attribute, $closure);
}
This works well, but only if I am using one of them in my main query, whereas if I use multiple:
$products = $this->products->whereHas('categories', function ($category) {
$category->where('id', '=', 1);
})->whereHas('bidders', function($bidders) {
})->get();
I am getting the following error:
Unknown column 'has_relation'
Column not found: 1054 Unknown column 'has_relation' in 'where
clause' (SQL: select * from products where exists (select * from
categories inner join products_categories on categories.id =
products_categories.categories_id where products.id =
products_categories.products_id and id = 1) and (has_relation
= sections))
The issue I'm seeing is that its returning a collection of items on the first whereHas which means it cannot compute the second one. Any ideas to where I am going wrong?
You can pass a closure with multiple relations to whereHas
$products = $this->products->whereHas(['categories', function
($category) {
$category->where('id', '=', 1);
},'bidders' => function($bidders) {
}])->get();
It will work as expected.

How to use query scope in join request Laravel?

I have the following request:
$objects = Object::with("translate")->where(function ($query) use ($request) {
$query->language();
})->with('images')->with("category")->orderBy('id', 'desc')->paginate($limit);
So, in model Object there is method: translate:
public function translate()
{
return $this->hasMany("App\ObjectTranslate", "objectId", "id");
}
So, also in this model is:
public function scopeLanguage($query)
{
$languageHeader = new ModelLibrary();
return $query->where('language', '=', $languageHeader->getLanguage());
}
When I try to call scope in main request:
$query->language();
I get SQL error:
Column not found: 1054 Unknown column 'language' in 'where clause' (SQL:
You need to join the query with ObjectTranslate's table. your scopeLanguage() function will not work , since you are trying to access the column language which is not available in Object model column.
Note : With() will just eager loading, which will load the eloquent defined function, you cannot directly access their column in where clause.
Modify your scopeLanguage function
public function scopeLanguage($query)
{
$languageHeader = new ModelLibrary();
return $query->join('object_translate_table','object_translate_table.objectId','=','object_table.id')->where('object_translate_table.language',$languageHeader->getLanguage());
}
$objects = Object::with("translate","images","category")
->language()
->orderBy('id', 'desc')
->paginate($limit);
This should work
Assumin ObjectTranslate model's table name is object_translate_table and Object model's table name is object_table

Laravel Eloquent Relations: ->latest()

What is the function of latest() in laravel?
Example:
public function activity()
{
return $this->hasMany('App\Activity')
->with(['user', 'subject'])
->latest();
}
From Build an activity feed in Laravel on line 44.
I've been looking in the laravel documentation, but I couldn't find it...
latest() is a function defined in Illuminate\Database\Query\Builder Class. It's job is very simple. This is how it is defined.
public function latest($column = 'created_at')
{
return $this->orderBy($column, 'desc');
}
So, It will just orderBy with the column you provide in descending order with the default column will be created_at.
->latest() fetches the most recent set of data from the Database. In short, it sorts the data fetched, using the 'created_at' column to chronologically order the data.
Add ->get() on your code like this:
public function activity()
{
return $this->hasMany('App\Activity')
->with(['user', 'subject'])
->latest()->get();
}
latest() function in Laravel used to get latest records from database using default column created_at.
latest()is the equivalent to orderBy('created_at', 'desc')

Get two polymorphic relationship results together

From the Laravel documentation - if I have this many-to-many polymorphic relationship:
class Tag extends Eloquent {
public function posts()
{
return $this->morphedByMany('Post', 'taggable');
}
public function videos()
{
return $this->morphedByMany('Video', 'taggable');
}
}
So I can do this:
$tag = Tag::find(1);
$posts = $tag->posts;
$videos = $tag->videos;
How could I get all the tags relationships as one result? i.e. in a one-to-many polymorphic relationship you do this:
$tag = Tag::find(1);
$taggable = $tag->taggable;
But that doesnt seem to work for me in the many-to-many relationship - I get this SQL error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'tag_groups.'
in 'where clause' (SQL: select * from tag_groups where
tag_groups.`` is null limit 1)
You'll have to merge the results yourself:
$taggable = $tag->posts->toBase()->merge($tag->videos);
This'll return an instance of Illuminate\Support\Collection.
An Eloquent collection does not make sense in this context.
You can't get all relations in one result but you may load them all eagerly using something like this:
$tag = Tag::with(['posts', 'videos'])->find(1);
$relations = $tag->getRelations();
Here $tag->getRelations() will return an array of loaded relations so you may access one using something like this:
$posts = $relations['posts']; // Collection of Post models
$videos = $relations['videos']; // Collection of Video models
You can merge them like:
$allRelations = array_merge($posts->toArray(), $videos->toArray());
Or using merge method of Illuminate\Support\Collection (As Joseph Silber mentioned)
$allRelations = $relations['posts']->toBase()->merge($relations['videos']);

Resources