How to calculate sum for belongsTo model laravel - php

I need to get sum of amount for belongsTo model on laravel
Here is my code
Controller:
$users = AffiliationUser::whereAffiliationId(Auth::user()->id)
->with(['user' => function ($q){
$q->withCount(['billings'])->with(['affiliation_transactions']);
}])
->paginate(3);
//dd($users);
return view('affiliation.users', [
'users' => $users,
'current_balance' => 0,
]);
AffiliationUser model:
public function user() {
return $this->belongsTo('App\Models\Users');
}
User model:
public function billings() {
return $this->hasMany('App\Models\UserBillingSchedules', 'user_id');
}
public function affiliation_transactions() {
return $this->hasMany('App\Models\AffiliationTransaction', 'user_id');
}
View:
#foreach ($users as $user)
<tr class="even pointer">
<td class="a-center ">{{ $user->user->id }}</td>
<td class=" ">{{ $user->user->email }}</td>
<td class=" ">{{ $user->user->card_holder }}</td>
<td class=" ">{{ $user->user->billings_count }}</td>
<td class=" ">{{ $user->user->affiliation_transactions->sum('amount') }}</td>
</tr>
#endforeach
It is working good for me, but i don't like idea to get it on view.
{{ $user->user->affiliation_transactions->sum('amount') }}
Which one solution i can use also?

You can calculate the sum with withCount():
$users = AffiliationUser::whereAffiliationId(Auth::user()->id)
->with(['user' => function ($q) {
$q->withCount([
'billings',
'affiliation_transactions as amount' => function ($q) {
$q->select(DB::raw('coalesce(sum(amount), 0)'));
}
]);
}])
->paginate(3);
{{ $user->user->amount }}

Laravel allows you to create custom attributes (using the get[attributename]Attribute method in your Models easily which can be used to reduce the amount of code you need to write. In this case, you can do this:
User Model:
public function getTransactionCountAttribute() {
return $this->affiliation_transactions->sum('amount');
}
Now this can be acccessed with the following method in your code:
$user->user->transaction_count
Also, here's a little more information about Mutators, as these are named. Hope they can be useful to you :)

In User Model create a method like:
public function sum_amount() {
return this.affiliation_transactions->sum('amount');
}
then in your view...
{{ $user->user->sum_amount }}

Related

How to solve this in Laravel 6? Trying to get property 'name' of non-object

My Model
class Purchase extends Model
{
public function supplier()
{
return $this->belongsTo(Supplier::class,'supplier_id','id');
}
public function unit()
{
return $this->belongsTo(Unit::class,'unit_id','id');
}
public function category()
{
return $this->belongsTo(Category::class,'category_id','id');
}
public function product()
{
return $this->belongsTo(Product::class,'product_id','id');
}
}
My Controller
class PurchaseController extends Controller
{
public function view()
{
$data['allData'] = Purchase::orderBy('id','desc')->get();
return view('backend.purchase.view-purchases', $data);
}
My View Page
#foreach($allData as $key => $purchase)
<tr>
<td>{{ $loop->index + 1 }}</td>
<td>{{ $purchase->purchase_no }}</td>
<td>{{ $purchase->product->name }}</td>
<td>{{ $purchase->unit->name }}</td>
<td>{{ $purchase->date }}</td>
and 2 more td for edit and delete
#endforeach
But there's still errors in all {{ $purchase-> example}}. I can't find the errors. If I check the dd() method right after the tr tag it works but it doesn't get the {{ $purchase-> example }}. I have the following error message:
Trying to get property 'name' of non-object (View: C:\xampp\htdocs\POS\resources\views\backend\purchase\view-purchases.blade.php).
enter image description here
Try loading the relations in the controller e.g.
$data['allData'] = Purchase::with('supplier', 'unit', 'category', 'product')->orderBy('id','desc')->get();
I would also advise you to change your controller view method body to the following.
$purchases = Purchase::with('supplier', 'unit', 'category', 'product')->orderBy('id','desc')->get();
return view('backend.purchase.view-purchases')->with(['purchases' => $purchases]);
So then in your view try to access it like the following.
#foreach($purchases as $purchase)
...
<td>{{ $purchase->purchase_no }}</td>
...
#endforeach

Call to undefined method Illuminate\Database\Query\Builder::with()

I'm trying to display the name of the category, but I get this error:
BadMethodCallException
Call to undefined method Illuminate\Database\Query\Builder::with()
AdminController.php
public function gamelist()
{
$categories = Category::all();
$home = DB::table('products')->with(['categories']);
return view('admin.gamelist', ['categories' => $categories, 'home' => $home, 'mode' => 'admin']);
}
Product.php
class Product extends Model
{
public function categories()
{
return $this->belongsTo('App\Category', 'category_id');
}
}
gamelist.blade.php
#foreach ($homes as $home)
<tr>
<td>{{ $home->id }}</td>
<td>{{ $home->name }}</td>
<td>{{ $home->categories->name}}</td>
<td>{{ $home->price }} €</td>
Can someone help me? Thank you
with is used to eager-load Eloquent relationships. By calling DB::table, you decided to use the query builder instead, and this one can't use Eloquent relationships.
You should replace
$home = DB::table('products')->with(['categories']);
by
$home = Product::with('categories')->get();

How to fix "laravel pagination NOT updating on search"

I'm making a table of orders that have a specific current step in this case the step is 'NESTEN' and some other where statements to get the orders back that I need.
Because I don't want a list with more than 400 orders on 1 page I want to use laravels pagination functionality that also give a performance boost on the list of more than 100.000 records. The laravel pagination works as is should but the problem comes when I want to use the filter I made.
I made a dropdown list that needs to filter based on material of the orders that are in the list. In the table I see the filtered orders but the pagination has the same page count and order count as before. So to the point, the problem is that the pagination is not updating after filtering the collection from the query.
What I already tried was some googling and found several solutions that didn't solve my problem or even caused more problems...
Also added a $orders->filter function to remove orders that don't meet up the filter requirements but no result...
To keep it understandable for now I added the code in the Route file.
My route is as followed
Route::get('orders/nesten', function(Request $request) {
$orders = ShopOrder::where([
['ItemCode', 'LIKE', 'CM%'],
['Exact', '=', null],
['Nesting', '=', null],
['IsOnHold', '!=', 1],
['ShopOrderRoutingStepPlanCount', '!=', 0]
])->paginate(50);
$filteredCollection = $orders->filter(function ($order) use($request) {
if($request->exists('material')) {
return $order->getCurrentStep() == 'Nesten'
&& $order->getMaterial() == $request->get('material');
}
return $order->getCurrentStep() == 'Nesten';
});
$orders->setCollection($filteredCollection);
return view('dashboard/actions/Nesten')->with('shopOrders', $orders);
});
In the ShopOrder Model I declared the functions ->getMaterial() and ->getCurrentStep() as
public function routingStepPlans() {
return $this->hasMany('App\Models\Exact\ShopOrder\RoutingStepPlan', 'ShopOrder', 'ID');
}
public function materialPlans() {
return $this->hasMany('App\Models\Exact\ShopOrder\MaterialPlan', 'ShopOrder', 'ID');
}
public function getCurrentStep() {
$current = $this->routingStepPlans()->where('LineNumber', ($this->timeTransactions()->count() + 1))->first();
if(isset($current->Description)) {
return $current->Description;
}
return 'Afgerond';
}
public function getMaterial() {
$material = $this->materialPlans()->where('ItemCode', 'LIKE', 'TAP%')->first();
if(isset($material->Description)) {
return $material->Description;
}
return '-';
}
and as last the view
<table class="table table-striped table-bordered no-width">
<thead>
<tr>
<th>Order nummer</th>
<th>SKU</th>
<th>Omschrijving</th>
<th>Aantal</th>
<th>Datum</th>
<th>Deadline</th>
<th>Materiaal</th>
<th>DXF?</th>
</tr>
</thead>
<tbody>
#foreach($shopOrders as $shopOrder)
<tr>
<td>{{ $shopOrder->ShopOrderNumber }}</td>
<td>{{ $shopOrder->ItemCode }}</td>
<td>{{ str_replace('Car Mats', '',$shopOrder->Description) }}</td>
<td>{{ $shopOrder->PlannedQuantity }}</td>
<td>{{ $shopOrder->PlannedStartDate }} </td>
<td>{{ $shopOrder->PlannedDate }}</td>
<td>{{ $shopOrder->getMaterial() }}</td>
<td>{{ $shopOrder->hasDxf() }}</td>
</tr>
#endforeach
</tbody>
</table>
{{ $shopOrders->total() }}
{{ $shopOrders->appends(['material' => Request::get('material')])->render() }}
I expect 1 page from pagination with orders/nesten?material=Saxony%20Zwart&page=1 as url since that material has 9 orders.
But currently it still has 151 pages, the same as just going to orders/nesten.
From what i see you're fetching all records from database and then filter them with Collection filter. Pagination is build from database query results, so you should update your query to do the filtering.
Update
Create abstract filter class
namespace App\Http\Filters;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Builder;
class AbstractFilter
{
protected $builder;
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function apply(Builder $builder)
{
$this->builder = $builder;
foreach($this->filters() as $name => $value) {
if(method_exists($this, $name)) {
call_user_func_array([$this, $name], array_filter([$value]));
}
}
return $this->builder;
}
public function filters()
{
return $this->request->all();
}
}
Extend that class for your request (NOTE - method names here are the request parameters for filters):
namespace App\Http\Filters;
class OrdersFilter extends AbstractFilter
{
public function material($value = null)
{
if (!is_null($value)) {
// return modified query here (return $this->builder->where....)
}
}
}
Add scope to your model (in ShopOrder model):
public function scopeFilter($query, OrderFilters $filter) {
return $filter->apply($query);
}
Update your query like this:
$orders = ShopOrder::whereLike('ItemCode', 'CM%')
->whereNull('Exact')
->whereNull('Nesting')
->where('IsOnHold', '!=', 1)
->where('ShopOrderRoutingStepPlanCount', '!=', 0)
->filter(new OrdersFilter($request))
->paginate(50);
And you can skip all collection filtering. Also you can add more filter params to OrdersFilter class.
NOTE: i wrote everything without testing, so there might be some minor errors. Also I haven't wrote materials filter without having a database structure, but your Model methods could be better.
UPDATE
for filter materials method i would use something like this (not 100% if it works, haven't tested):
public function material($value = null) {
if (!is_null($material)) {
return $this->builder->having('', function($query) use ($value) {
return $query->where('ItemCode', 'LIKE', 'TAP%')
->where('description', '=', $value);
})
->having('routingStepPlans', function($query) {
return $query->where('LineNumber', ShopOrder::timeTransactions()->count() + 1)
->where('description', '=', 'Nesten');
});
}
}
so that your pagination continues but keep your search
{{ $shopOrders->appends(Request::except('page'))->links() }}

Trying to get property of non-object when using One to Many relationship in Laravel

So I keep getting this error when trying to get the name of the user who created a post.
My models look like this:
class User extends Authenticatable {
use Notifiable, CanResetPassword;
public function posts() {
return $this->hasMany('App\Post');
}
}
&
class Post extends Model {
public function user() {
return $this->belongsTo('App\User', 'user_id');
}
}
I try to display the name by doing this in my view:
#foreach($posts as $post)
<tr>
<td>{{ $post->user->name }}</td>
</tr>
#endforeach
And my controller looks like this:
public function getAdminIndex() {
$posts = Post::orderBy('id', 'desc')->get();
$comments = Comment::all();
$likes = Like::all();
$users = User::all();
return view('admin.index', ['posts' => $posts, 'comments' => $comments, 'likes' => $likes, 'users' => $users]);
}
Can anyone please tell me what I'm doing wrong?
Thank you very much!
It means not all posts have user, so do something like this:
<td>{{ optional($post->user)->name }}</td>
Or:
<td>{{ empty($post->user) ? 'No user' : $post->user->name }}</td>

Laravel realtionship sometimes not functional

I have Laravel 5. framework for bacis e-shop, i try use relationship I have Order, Order_item, Product, Customer model
Order model has realationship with
class Order extends Model
{
protected $fillable = ['user_id', 'status'];
protected $dates = ['created_at'];
/**
* Get the items for the order.
*/
public function items()
{
return $this->hasMany('App\Order_item');
}
public function customer()
{
return $this->hasOne('App\Customer','id');
}
}
Order item
class Order_item extends Model
{
protected $fillable = ['order_id', 'product_id', 'quantity', 'price'];
public function product()
{
return $this->hasOne('App\Product','id');
}
}
in controller
public function detail($id)
{
$order = Order::with('customer','items')->findOrFail($id);
return view('admin.detail', ['order' => $order]);
}
and in view I have
<h2>Objednávka č. {{ $order->id }}</h2>
<h3>Zákazník:</h3>
{{ $order->customer->firstname }} {{ $order->customer->lastname }}
<p>{{ $order->customer->email }}</p>
{{ $order->customer->phone }}
<h3>Adresa:</h3>
<p>{{ $order->customer->street }}</p>
<p>{{ $order->customer->city }}</p>
<p>{{ $order->customer->psc }}</p>
<h3>Položky:</h3>
<table class="table table-bordered table-striped">
<thead>
<th>Název</th>
<th>Počet</th>
<th>Cena</th>
</thead>
<tbody>
#foreach($order->items as $item)
<tr>
<th>{{ $item->product->name }}</th>
<th>{{ $item->quantity }}</th>
<th>{{ $item->price }}</th>
</tr>
#endforeach
</tbody>
</table>
and now when i test the code for someone order is function but for someone no, the problem is on {{ $item->product->name }}
is my realationship ok? Its a better solution for my e-shop relationship
i post my complete code to github https://github.com/mardon/MaMushashop
Your order item table is a pivot table. There for the relationships to order and product should be declared as belongsToMany.
belongsToMany is used in Many To Many.
hasMany is used in a One To Many
hasOne is used in One To One
The naming of your table Order_item should be order_product to better reflect what it actually contains.
class order_product extends Model
{
protected $fillable = ['order_id', 'product_id', 'quantity', 'price'];
public function product()
{
return $this->belongsToMany('App\Product', 'order_product', 'order_id', 'product_id);
}
public function order()
{
return $this->belongsToMany('App\Order', 'order_product', 'product_id', 'order_id);
}
}
Do like this
$order = DB::table('order')
->join('customer', 'order.customer_id', '=', 'customer.id')
->select('order.*', 'customer.*')
->where('order.id', '=', $id)
->first();
$order_items = Order_item::where('order_id', $id)->get();
return view('admin.detail', ['order' => $order, 'order_items' => $order_items]);
And generate item like this
#foreach($order_items as $item)
<tr>
<th>{{ $item->product->name }}</th>
<th>{{ $item->quantity }}</th>
<th>{{ $item->price }}</th>
</tr>
#endforeach

Categories