Laravel Query Builder - Use sum method on a generated attribute - php

Let's say I have these 2 models:
Order Model:
id
state (incomplete, complete)
Item Model:
id
order_id
type
is_worthy.
.
/**
* Returns the item's price according to its worthy
*/
public function getPriceAttribute()
{
return $this->is_worthy ? 100 : 10; // $
}
So far so good.
Now I want to summarize the price of the complete orders. So I'm doing this:
App\Item::whereHas('order', function ($query) {
$query->where('state', 'complete');
})->sum('price')
But the thing is, that I don't have in my items table the column price. Because the price attribute is generated in the Model.
So my question is, how can I summarize price of the complete orders?

There are 2 ways to do this:
1. Have PHP do all the work
$items = App\Item::whereHas('order', function ($query) {
$query->where('state', 'complete');
})->get();
$sum = $items->sum(function($item) {
return $item->price;
});
// In Laravel 5.4, you can replace the last line with $sum = $items->sum->price;
2. Have SQL do all the work
$items = App\Item::whereHas('order', function ($query) {
$query->where('state', 'complete');
})->select('*', DB::raw('IF(is_worthy, 100, 10) as price'))->sum('price');

Laravel
model
/**
* Returns the item's price according to its worthy
*/
public function getPriceAttribute()
{
return $this->is_worthy ? 100 : 10; // $
}
controller
retrun OrderItem::where('state', 'complete')->get()->sum('price');

Related

Laravel how to get sum price for domain prices table

I am using Laravel 7.0.
My domain_prices table has price, duration, addPrice columns.
I created DomainPrice model.
Domain price for specific duration is price + addPrice.
But for 5 years duration, I need to sum all prices and all addPrices for 1, 2, 3, 4, 5 years.
I set custom attribute to get totalPrice as following:
public function getTotalPriceAttribute()
{
return $this->price+$this->addPrice;
}
I wanted to make another custom attribute to get sumPrice as following:
public function getSumPriceAttribute()
{
$sumPrice = 0;
$prices = $this->where('Duration', '<=', $this->Duration)->get(); // I removed domain filter query here.
foreach($prices as $price)
{
$sumPrice += $price->totalPrice;
}
return $sumPrice;
}
But this didn't return exact results.
Please teach me with fancy approach. Thanks.
I think you used the wrong variable here when you sum your $sumPrice. you should change $subPrice in foreach loop to $sumPrice
public function getSumPriceAttribute()
{
$sumPrice = 0;
$prices = $this->where('Duration', '<=', $this->Duration)->get(); // I removed domain filter query here.
foreach($prices as $price)
{
$sumPrice += $price->totalPrice; // change $subPrice to $sumPrice
}
return $sumPrice;
}

Laravel return data that matches two tables

i have two different tables like these:
Table:products
id->1
name->pencil
siz->big
Table:colours
id->2
colour_name->red
product_id->1
Here is my codes in controller;
$products= Product::where('active', 1);
if ($request->has('size')) {
$products->whereIn('size', $request->input('size'));
}
$products= $products->paginate(10);
return view('pencil.index', compact("products"));
The results are filtered by request's size values. But the problem colours in different table, how can i do the correct query for colour filters ? Thank you.
You can do it nicely using Eloquent. So in your Product model class add this method:
public function colours()
{
return $this->hasMany(Colour::class);
}
and in your Colour model:
public function product()
{
return $this->belongsTo(Product::class);
}
Then in your controller or wherever you have the business logic you can do it like so:
Product::where('id', $productId)->colours; // this gives you list of all the colours for that product.
Getting list of colours based on the colour name:
$colours = Colour::where(
'colour_name', request('colour')
)->get();
then simply when iterating over the $colours you can use:
foreach($colours as $colour)
{
// $colour->product; is what you are looking for.
}
--- EDIT
Product::with('colours', function($query) use ($colour) {
$query->where('colour_name', $colour);
});

Laravel Eloquent - Using array in find() method

I have three tables - users, products and orders
There is a relation between users and orders (users has many orders).
orders table contains product_id and user_id column.
Now I want to access the product details of orders for a user.
What I am trying:
public function myOrders(){
$orders = Auth::user()->orders->pluck('product_id');
$products = Product::find($orders);
return view('shop.myorders', compact('products'));
}
But this is not working. Can anyone help me? What other way can be better to achieve this?
As mentioned, find() will always return 1 item, and expects a string/int for the parameter. You want to use where and get instead. With an array of ids, you can use whereIn.
public function myOrders(){
$orders = Auth::user()->orders->pluck('product_id');
$products = Product::whereIn('id', $orders)->get();
return view('shop.myorders', compact('products'));
}
I assume you have orders() relation defined in the Product model:
public function orders()
{
return $this->hasMany(Order::class)
}
Then you'll be able to load products from all user's orders:
$products = Product::whereHas('orders', function($q) {
$q->where('user_id', auth()->id())
})->get();

Laravel Eloquent using "with" with conditions

I have two tables, say Products and Biddings where one product can be bid by many users. Naturally I have two models:
class Product extends Model
{
public function biddings()
{
return $this->hasMany('App\Bidding');
}
}
class Bidding extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
}
So, say I want to get all products along with the highest priced bidding I did something like this.
$productBidding = DB::table('biddings')
->select('*', DB::raw('max(price) as price'))
->join('products', 'products.id', '=', 'biddings.product_id')
->groupBy('product_id')
->get();
That works well BUT I kinda want to do it Eloquent way. So how do I convert Query Builder way to Eloquent? I am currently on this but do not know how to put the "max" condition in.
$productBidding = Products::with('biddings')
->get();
$productbinding=Bidding:with('product')
->get();
foreach($productbinding as $productbind)
{
echo $productbind->product->name; // example
}
I would extract the highest bid to a separate function on the Product model, like so:
public function highestBid() {
return $this->biddings()->max('price');
}
Then fetch the products and get the highest bid:
$products = Product::get();
foreach ($products AS $product) {
echo $product->highestBid();
}

Laravel 4 Advanced Where - Unknown Column

I have a query which looks like this:
$items = Item::live()
->with('location')
->where('last_location_id', Input::get('last_location_id'))
->get();
The background of this is...
2 tables: Items & Cars.
The live scope is:
public function scopeLive($query)
{
return $query->whereHas('basic_car', function($q)
{
$q->whereNotNull('id')->where('sale_status', 'Live');
});
}
This basically checks the cars table for a matching id to that of the items 'car_id' field and will run some where clauses on the cars table.
I now however want to check another field on the cars table, but using the Input::get('last_location_id') from the original query.
$items = Item::live()
->with('location')
->where('last_location_id', Input::get('last_location_id'))
->orWhere('ROW ON THE CARS TABLE' = Input::get('last_location_id'))
->get();
This does't work, then I tried:
$items = Item::live()
->with('location')
->where('last_location_id', Input::get('last_location_id'))
->orWhere(function($query)
{
$query->where('cars.Location', Input::get('last_location_id'));
})
->get();
Which results in an unknown column 'cars.Location' error.
My next test was to create another scope:
public function scopeLiveTest($query)
{
return $query->whereHas('basic_car', function($q)
{
$q->whereNotNull('id')->where('sale_status', 'Live')->where('Location', 1); // hardcoded ID
});
}
And replacing the live() scope with that works but I dont get the affect of the orWhere in the query itself and I also cannot specify a ID from the Input.
How can I do this?
You can pass a parameter to scope like this:
$items = Item::liveAtLocation(Input::get('last_location_id'))
->orWhere(function( $query ) { // to get the OR working
$query->live()
->with('location')
->where('last_location_id', Input::get('last_location_id'));
})
->get();
And for the scope:
public function scopeLiveAtLocation($query, $location_id)
{
return $query->whereHas('basic_car', function($q) use ($location_id)
{
$q->whereNotNull('id')->where('sale_status', 'Live')->where('Location', $location_id);
});
}

Categories