Add Select Get Value - php

I want to get order status name based on order_status_id
I have order statuses in the array:
$orderStatuses = [
1 => 'Waiting',
2 => 'Delivered',
3 => 'Rejected'
];
I need to get the order status name and order_status_id.
$orders = Order::limit(50)->get();
I am now only getting order status name from looping through each order like:
foreach($orders as $order){
$order->order_status_name = $orderStatus[$order->order_status_id];
}
Is there any way to get the order status name without using foreach.
What I tried:
Order::addSelect("$orderStatuses[".'order_status_id'."]". " as order_status_name");
I am unable to get the result. Is there any way to get the result from the eloquent query or do I have to use foreach?

You can create an accessor in the Order model:
private $orderStatuses = [
1 => 'Waiting',
2 => 'Delivered',
3 => 'Rejected'
];
protected $appends = ['status'];
public function getStatusAttribute()
{
return $this->orderStatuses[$this->order_status_id];
}
Then use it in your code as :
$order->status;
More on this here.
-- EDIT
$orders = Order::limit(50)->get();
foreach($orders as $order)
{
$order->status; // as this is computed property.
}

#nakov answer is correct if you want to go with model but if you want to fetch status based on value you can use case in query :
$data = Order::select("*",\DB::Raw("case when order_status_id = 1 then 'Waiting' when order_status_id = 2 then 'Delivered' when order_status_id = 3 then 'Rejected' end as status"))
->limit(50)
->get();
It will provide you status field in your collection
foreach($orders as $order){
$order->order_status_name = $order->status;
}

Related

Why is my order_id in my pivot table not being updated but everything else is?

I have two models, a marketsegment model and a product model, both have a many to many relation with eachother.
Example in MarketSegment.php:
public function products()
{
return $this->belongsToMany(Product::class);
}
Now I post the following array to a function that updates the pivot table:
products[]:
6
products[]:
11
I want to update market_segment_product to contain all products belonging to a market segment and add the sort order of them for the column order_id. As the order_id I want to use the keys of the above array, so the full data example would be:
market_segment_id - 7
product_id - 6
order_id - 0
market_segment_id - 7
product_id - 11
order_id - 1
I have the following function to update the pivot table:
public function updateProducts(Request $request, $id)
{
$marketSegment = MarketSegment::find($id);
$products = $request->input('products');
$order = [];
$i = 0;
foreach ($products as $id) {
$order[$id] = $i;
$i++;
}
$data = [];
foreach ($products as $id) {
$data[$id] = ['order_id' => $order[$id]];
}
$marketSegment->products()->sync($products, $data);
return [
'error' => false,
'message' => 'Producten gewijzigd'
];
}
But this updates everything except the order_id which stays 0 for all rows. Why doesn't it update the order_id ? I am using laravel 6.

Laravel Eloquent Multiple Where with count

Following is the SQL query that I need to perform on laravel eloquent. SQL returns expected output.
SELECT
orders.id,
orders.`status`,
order_type,
COUNT(order_type) as count
FROM
orders
WHERE
orders.`status` = 0 && order_type = 1
ORDER BY
orders.id DESC
what I have tried on laravel is below
$receved = Order::select('status', 'order_type')->where('status',0);
$relase = $receved->where('order_type', 1)->get();
$bulk = $receved->where('order_type', 2)->get();
$distiribute = $receved->where('order_type', 3)->get();
return response()->json([
'success' => true,
'message' => 'Statement Updated',
'orderStatment' => [
'relaseCount' => count($relase),
'bulkCount' => count($bulk),
'distiributeCount' => count($distiribute)
],
], 200);
I seeking recommendation/suggestion to operate this in a correct way
The output I getting on laravel is
'orderStatment' => [
'relaseCount' => 14,
'bulkCount' => 0,
'distiributeCount' => 0
],
the output of expectation and SQL produce is
'orderStatment' => [
'relaseCount' => 14,
'bulkCount' => 5,
'distiributeCount' => 4
],
There are 8 Different type of status and 3 different types of order_type available on Table I want to get each order_type count of every status
You might have better luck doing it all in one query, then getting the data back out.
$receved = Order::select('status', 'order_type', DB::raw('COUNT(id) as order_count'))->where('status',0)
->groupBy('order_type')
->get();
This will give you a collection of all of the order types and their counts in one query. After that, you can get the data back out.
$bulk = $relase = $distiribute = 0;
foreach($receved as $rec) {
if($rec->order_type == 1) $relase = $rec->order_count;
elseif($rec->order_type == 2) $bulk = $rec->order_count;
elseif($rec->order_type == 3) $distiribute = $rec->order_count;
}
The problem you're facing is due to the fact that all of the following statements are manipulating the same query builder object:
$receved = Order::select('status', 'order_type')->where('status',0);
$relase = $receved->where('order_type', 1)->get();
$bulk = $receved->where('order_type', 2)->get();
$distiribute = $receved->where('order_type', 3)->get();
So the actual queries created will be something like this:
All start with: select status, order_type from orders where status = 0 and
order_type = 1;
order_type = 1 and order_type = 2;
order_type = 1 and order_type = 2 and order_type = 3;
This is why the last two queries return 0. It's expected once you see the resulting query.
You can verify this by logging the query (see this answer for details, or the docs here).
$receved is actually getting the where clauses attached to it each time. So you're not just starting with the original statement, but building onto it each time you call where.

How to get latest record on a relationship in Laravel

Users have plans stored in the invoices table. These plans are monthly based.
What I need to do
I want to add a new row for user if his plan expire date has reached and they didn't renew their plans (I don't want to update old one)
The issue is
Each user has unlimited rows in invoices table as they renew each month. Now when I try to retrieve their latest row and check the expiring date it gets other rows of those users as well.
Example
My user has 3 rows in invoices
two of them already expired and renewed, the current one is id=3
when I try to expire this id=3 and create id=4 for this user
it gets all 3 rows and send 3 emails to the user.
Code
public function handle()
{
$invoices = Invoice::where('plan_expire', '<=', Carbon::now())->get();
$current = Carbon::now();
$expiredatetime = $current->addDays(30);
$useType = Type::where('name', 'Free')->first();
foreach($invoices as $invoice)
{
Invoice::create([
'user_id' => $invoice->user->id,
'type_id' => $useType->id,
'amount' => $useType->price,
'status' => 'Approved',
'plan_expire' => $expiredatetime->toDateTimeString(),
]);
Mail::to($invoice->user->email)->send(new UserPlansReset($invoice));
}
}
User model
public function invoices()
{
return $this->hasMany(Invoice::class);
}
Invoice model
protected $fillable = [
'user_id', 'type_id', 'amount', 'status', 'plan_expire',
];
protected $casts = [
'plan_expire' => 'datetime',
];
public function user()
{
return $this->belongsTo(User::class);
}
Question
Do you have any idea how I can only get users latest row in invoices table?
Update
based on answers below I changed my code to:
$current = Carbon::now();
$expiredatetime = $current->addDays(30);
$useType = Type::where('name', 'Free')->first();
$users = User::all();
foreach($users as $user){
$latestInvoice = $user->invoices()->latest()->first();
if(!empty($latestInvoice) && $latestInvoice->plan_expire <= Carbon::now()){
Invoice::create([
'user_id' => $user->id,
'type_id' => $useType->id,
'amount' => $useType->price,
'status' => 'Approved',
'plan_expire' => $expiredatetime->toDateTimeString(),
]);
Mail::to($user->email)->send(new UserPlansReset($user));
}
}
Now this function will return
Expected response code 220 but got an empty response
and wont send emails.
Change in Invoice model, add plan_expire in $dates variable instead of $casts :
protected $dates = ["plan_expire"];
You can try like this :
$users = User::all();
foreach($users as $user){
$latestInvoice = $user->invoices()->latest()->first();
if($latestInvoice->plan_expire->isPast()){
//create invoice and mailed it
}
//other steup
}
For Email send return empty response issue , You can check this question click here
Find expired invoices, group by user id and order by plan_expire and select first record in each group.
MySQL server version < 8 don't have window functions that may make it easier to do row numbering in matched rows.
A workaround is to set client variables that can be used to number invoices by the same user starting from 1 and selecting only the first ones.
$now = Carbon::now();
$nowDS = $now->toDateTimeString();
$expired_invoices = "
SET #rownum := 0;
SET #userid := NULL;
SELECT *, uid as user_id, plan_expire
FROM (
SELECT
*,
#rownum := CASE
WHEN #userid = uid
THEN #rownum + 1
ELSE 1
END AS rn,
#userid := user_id AS uid,
num
FROM invoices AS i
WHERE plan_expire <= $nowDS
ORDER BY user_id, plan_expire DESC
) AS num_invoices WHERE rn = 1;
"
$invoices = DB::select($expired_invoices);
Now, $invoices can be iterated over and mail sent to the owner of it.
$expiredatetime = $now->addDays(30);
$useType = Type::where('name', 'Free')->first();
$users = User::all();
foreach ($invoices as $invoice)
{
Invoice::create([
'user_id' => $invoice->user_id,
'type_id' => $useType->id,
'amount' => $useType->price,
'status' => 'Approved',
'plan_expire' => $expiredatetime,
]);
$user = $users->find(['id' => $invoice->user_id]);
Mail::to($user->email)->send(new UserPlansReset($user));
}

How to get price and sum the price as a total price according to date?

THIS IS MY CODE
$filter = DB::table('detail_clothes')
->get(['id', 'clothes_detail_date', 'clothes_price'])
->groupBy(function($date){
return Carbon::parse($date->clothes_date)->format('m/Y');
});
$result = [];
$clothes_total_price = 0;
$clothes_date = null;
foreach ($filter as $dn => $dn_value) {
$clothes = Clothes::where('clothes_date', $dn)
->first();
foreach ($dn_value as $k => $dnval) {
$clothes_total_price += $dnval->clothes_price;
$result[$dn]['clothes_total_price'] = $clothes_total_price;
}
$date_temp = date_format(date_create_from_format('Y-m-d', $request->clothes_detail_date),'m/Y');
}
I have Two Model : Clothes and Detail Clothes
Clothes : id, clothes_date, clothes_total_price
DetailClothes : id, clothes_detail_date, clothes_price
example::
when i input shirt price it will go to detail clothes and store it there , and it also store in clothes as clothes_total_price
it will display all records according to the month, but when i sum it , it doesnt show according what i want,
what i want for example:
first, if i input the price this month 1000 twice, the total price should be 2000, and if i input the price for next month 1000 twice , the total price should be 2000 not 4000
second, if i input the date example: 2017-08-25 , it will store to both model, but spesifically for CLOTHES model it will always update the date according to month and year to the latest submit,
example:
at Detail Clothes model it should be like this::
1st submit : clothes_detail_date : 2017-08-25, clothes_price : 1000
2nd submit : clothes_detail_date : 2017-08-01, clothes_price : 2000,
expected result:
at Clothes model it should be like this::
clothes_date : 2017-08-25, clothes_total_price: 3000
note* at Clothes Model it will only show 1 row of record according to month and year , and it will never show 2 record at the same month and year
Can Anyone Help Me??????
I think you forgot to reset $clothes_total_price to zero. Also I moved 1 line from inner foreach to outer.
foreach ($filter as $dn => $dn_value) {
$clothes_total_price = 0;
$clothes = Clothes::where('clothes_date', $dn)
->first();
foreach ($dn_value as $k => $dnval) {
$clothes_total_price += $dnval->clothes_price;
}
$result[$dn]['clothes_total_price'] = $clothes_total_price;
$date_temp = date_format(date_create_from_format('Y-m-d',
$request->clothes_detail_date),'m/Y');
}
EDIT: Additional answer in SQLFiddle
You group by a month, take the max date from that month, and you sum the price in that month:
INSERT INTO
Clothes (clothes_date, clothes_total_price)
SELECT * FROM (
SELECT
MAX(clothes_detail_date) new_clothes_date
,SUM(clothes_price) new_clothes_total_price
FROM DetailClothes
GROUP BY DATE_FORMAT(clothes_detail_date,'%Y%m')
) newTable
ON DUPLICATE KEY UPDATE
clothes_date=newTable.new_clothes_date
,clothes_total_price=newTable.new_clothes_total_price
;
I already figure it out how to answer this question
DetailClothes Model
public function scopeStoreDetailClothes($query, $request){
$data = $request->all();
DetailClothes::create($data)->save();
$date = Carbon::parse($request->clothes_detail_date);
$filter = DetailClothes::whereMonth('clothes_detail_date', '=', $date->month)
->whereYear('clothes_detail_date', '=', $date->year);
$total = (object) [
'clothes_price' => $filter->sum('clothes_price'),
];
$detail_clothes = DetailClothes::whereMonth('clothes_detail_date', '=', $date->month)
->whereYear('clothes_detail_date', '=', $date->year)
->orderBy('clothes_detail_date', 'desc')
->first();
$clothes = Clothes::whereMonth('clothes_date', '=', $date->month)
->whereYear('clothes_date', '=', $date->month)
->first();
Clothes::updateOrCreate(
[
'clothes_date' => isset($clothes->clothes_date) ? $clothes->clothes_date : null
], [
'clothes_date' => isset($detail_clothes) ? $detail_clothes->clothes_detail_date : $request->clothes_detail_date,
'clothes_total_price' => $total->clothes_price
]);
}

Getting null array PHP

i have a database named "products" which has a column "categories". This table contain four category of products namely electronic,Decoration,clothes and vehicle. My target to show these category with their count ie:if there are four products belongs to category electronic, then output should be like this :electronic=4 and so on
My code
public function category()
{
$arrayCategorys = ['electronic','Decoration','clothes','vehicle'];
$data = [];
foreach($arrayCategorys as $arrayCategory)
{
$sql = "SELECT count(id) FROM products WHERE categories='$arrayCategory'";
$records = \DB::select($sql);
$data = array_merge_recursive($data, [
"{$arrayCategory}" =>isset($records[0]->count),
]);
$data=array_filter($data);
dd($data);
}
}
I want show output like this
'electronic'=>'4',
'Decoration'=>'2',
'clothes'=>'2',
'vehicle'=>'1' according to data in database
but iam getting nothing ,[]
You can GROUP BY your categories like this way when you COUNT
SELECT categories,COUNT(*)
FROM products
GROUP BY categories;
For Idea: http://www.w3resource.com/mysql/aggregate-functions-and-grouping/aggregate-functions-and-grouping-count-with-group-by.php
EDIT: Though i am not familiar with laravel5 syntax but this may work for you
$result = DB::table('products')
->select('products.categories',
DB::raw('count(products.id) as category_count')
)
->orderBy('products.id', 'asc')
->groupBy('products.categories')
->get();
You used isset($records[0]->count) but the column name for the count will be count(id). Name the count as count like this "SELECT count(id) AS count FROM products WHERE categories='$arrayCategory'". And you wont be able to get the count just by checking if it is set. Remove the isset and just use $records[0]->count. The code should look like:
public function category()
{
$arrayCategorys = ['electronic','Decoration','clothes','vehicle'];
$data = [];
foreach($arrayCategorys as $arrayCategory)
{
$sql = "SELECT count(id) AS count FROM products WHERE categories='$arrayCategory'";
$records = \DB::select($sql);
$data = array_merge_recursive($data, [
"{$arrayCategory}" =>$records[0]->count,
]);
$data=array_filter($data);
dd($data);
}
}

Categories