Sum Values in a foreach loop in laravel controller - php

How to sum data
After getting the previous calculations on controller Laravel
private $nn;
public function detailproject($code_project)
{
$countdata = count($listdata);
$countdata = 15 / $countdata;
foreach ($listdata as $obj ) {
$this->nn = $obj->percent * $countdata / 100;
$this->nn +=($obj->persen);
}
dd($this->nn);
}
How to do this?

You could use array_reduce() or reduce(). Since it's a Laravel question, I'll go with reduce()
$collection = collect($listdata);
$percentage = 0.15 * $collection->count();
$sum = $collection->reduce(function ($carry, $item) use ($percentage) {
return $carry + ($item->percent * $percentage);
}, 0);
dd($sum);

if you are returning after saving data use this method where you pull data from existing columns and show them on blade file..
//initialize percentage if constant for every record on DB
//if not constant pull($Percentage) from DB as column as shown below.
//$x; $y are specific columns found in table in DB.
// replace mathematical signs where necessary.
// if needed as per row mask the formulae in your for each loop
$percentage = ''
$total = array_sum(array_map(function($x, $y) { return $x * $y; },
$carry, $item)) * ($percentage);

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;
}

Adding items into array Laravel using for loop

I am trying to get all categories that have products from the database and push them into another array.
I have four 3 categories and two of them have products.
Here is my code:
$categories = Category::all();
$count = count($categories);
$categoriesWithProducts = array();
for($i = 0; $i < $count; $i++) {
if($categories[$i]->products->count() > 0) {
array_push($categoriesWithProducts, $categories[$i]);
}
return response()->json($categoriesWithProducts);
}
I get an array with just one item instead of two.
Where am i going wrong?
Although error is obvious (mentioned in comment) you could rewrite the whole thing:
$categories = Category::withCount('products')->get(); // you load count to not make n+1 queries
$categoriesWithProducts = $categories->filter(function($category) {
return $category->products_count > 0
})->values();
return response()->json(categoriesWithProducts);
Of course you could make it even simpler:
return response()->json(Category::withCount('products')->get()
->filter(function($category) {
return $category->products_count > 0
})->values()
);
But in fact the best way would be using Eloquent relationships so you could use:
return response()->json(Category::has('products')->get());

Getting a specific eloquent object out of a collection in Laravel

I have a function that looks for possible boxes that can carry the article.
public static function get_possible_boxes($article,$quantity)
{
$i = 0;
$possible_boxes = array();
$total_weight = $articles->grams * $quantity;
$boxes = Boxes::all();
foreach($boxes as $box)
{
if($total_weight+ $box->grams < $box->max_weight)
{
$possible_boxes[$i] = $box;
$i++;
}
}
return collect($possible_boxes);
}
This gives me a collection with boxes that can carry my items.
Now I should check if the ID of the box selected by the customer exists. If it does not exist, it will pick the first valid one.
This is where I am stuck. I have tried to use puck:
public function someotherfunction(){
...
$boxes = get_possible_boxes($something,$number);
$valid_box = $boxes->where("id", $request->selected_box)->pluck("id");
if(!$valid_box){
$valid_box = $boxes[0]
}
...
This works if the selected box cannot be used. The function pluck only gives me the id, clearly it is not the function I am looking for and I have already read the Laravel documentation.
So the question is, how do I get the correct eloquent model ?
You're looking for the first() method.
$valid_box = $boxes->where("id", $request->selected_box)->first();
Alternatively, if you rework your get_possible_boxes() method to return a Illuminate\Database\Eloquent\Collection instead of a plain Illuminate\Support\Collection, you could use the find() method, like so:
Function:
public static function get_possible_boxes($article,$quantity)
{
$total_weight = $article->grams * $quantity;
$boxes = Boxes::all()->filter(function ($box) use ($total_weight) {
return $total_weight + $box->grams < $box->max_weight;
});
return $boxes;
}
Find:
$boxes = get_possible_boxes($something, $number);
$valid_box = $boxes->find($request->selected_box) ?? $boxes->first();
And you could probably squeeze out a little more performance by adding the weight condition as part of the SQL query instead of filtering the collection after you've returned all the boxes, but I left that up to you.
What you want is probably filter.
$valid_box = $boxes->filter(function($box) use ($request){
return $box->id == $request->selected_box;
});
if($valid_box)...
I should note that if you don't want $valid_box to be a collection, you can use first instead of filter in the exact same way to only get the object back.
It could be done in many ways but I would rather use the following approach:
$boxes = get_possible_boxes($something,$number)->keyBy('id');
$valid_box = $boxes->get($request->selected_box) ?: $boxes->first();

Laravel , geeting comma separated values as ID for another model

so i have this input from invoice_table, "order_numbers", with values something like this : 91,92,93
in controller :
$invoice->order_numbers = Input::get('order_numbers');
What i need is to find that order numbers ( 91,92,93 ) in orders_table and updated it's value
This is what i try in controller :
$invoice->order_numbers = Input::get('order_numbers');
$orderIds = explode(',', $invoice->order_numbers);
$cnt = count($orderIds);
for ($i = 0; $i < $cnt; $i++) {
$order = Order::findOrFail($orderIds);
$order->is_billed = '1';
$order->save();
}
but i got this error :
BadMethodCallException in Macroable.php line 74:
Method save does not exist.
Can somebody help me what to do ? Thanks
You can change all your code to:
$orderIds = explode(',', request('order_numbers'));
Order::whereIn('id', $ordersIds)->update(['is_billed' => 1]);
Your code will generate N * 2 queries (200 queries for 100 IDs) and this code will generate just one query for any number of IDs.
update() method uses mass assignment, so make sure is_billed is in $fillable array.

How to assign a dynamic property in a model via a SQL query in Laravel 5

I'm using Laravel 5.3 to build an API and I have an model for products. Whenever I retrieve a product, I want to retrieve the product's rating and it's recommended rate. I also have a model for reviews and products have many reviews.
$product = Product::where('slug', $slug)->with('reviews')->first()->toArray();
Rating is computed by looping through $product->reviews in the controller, adding up the score of each review, then dividing it by the total number of reviews.
if (count($product['reviews']) > 0) {
$i = 0;
$totalScore = 0;
foreach ($product['reviews'] as $review) {
$totalScore = $totalScore + $review['Rating'];
$i++;
}
$product['averageReviewRating'] = $totalScore / $i;
} else {
$product['averageReviewRating'] = null;
}
Recommended rate is computed with a SQL query.
$product['recommendedRate'] = round(DB::select("
select ( count ( if (Recommend = 1,1,NULL) ) / count(*)) * 100 as rate
from Review where PrintProduct_idPrintProduct = " . $product['idPrintProduct']
)[0]->rate);
This leaves me with $product['averageReviewRating'] and $product['recommendedRate'] with the data I want but seems very sloppy. I would like to just be able to do something similar to this below and have those two values assigned to each object of a collection, than access them via $product->averageReviewRating and $product->recommendedRate or even not include them in with and have those values eagerly assigned.
$product = Product::where('slug', $slug)->with(['Reviews', 'RecommendedRate', 'AverageReviewRating'])->first();
Anyone know a way to do this with ORM? I've looked high and low and have not found anything.
You can do this way
protected $appends = [
'reviews',
'recommendedRate',
'averageReviewRating'
];
public function getReviewsAttribute() {
return $this->reviews()->get();
}
public function getRecommendedRateAttribute() {
if (count($this->reviews) > 0) {
$i = 0;
$totalScore = 0;
foreach ($this->reviews as $review) {
$totalScore = $totalScore + $review->Rating;
$i++;
}
return $totalScore / $i;
} else {
return null;
}
}
public function getAverageReviewRatingAttribute() {
return round(DB::select("
select ( count ( if (Recommend = 1,1,NULL) ) / count(*)) * 100 as rate
from Review where PrintProduct_idPrintProduct = " . $this->idPrintProduct
)[0]->rate);
}
then simply call Product::where('slug', $slug)->first()->toArray();
P.S. This is just the way you can do, I might miss part of logic or names..
The way to get the sum in Laravel Eloquent is using the Aggregate sum and for average avg
https://laravel.com/docs/5.4/queries#aggregates
If you want to add a custom property to your model for that, you can use
class Product {
function __construct() {
$this->{'sum'} = DB::table('product')->sum();
$this->{'avg'} = DB::table('product')->avg();
}
}
edit: to set the attributes, you can use the built in function https://github.com/illuminate/database/blob/v4.2.17/Eloquent/Model.php#L2551

Categories