Get the amount of the bill in the class method - php

Sorry for my English.
I want to make a record that would be deduced me the sum of all my orders, that is, folded string of orders and drew grouped by orders.
I have created a model "Sale", which comprises method AmountOrder
public function AmountOrder()
{
$AmountOrder = DB::table('goods')
->join('sale_lines', 'sale_lines.good_id', '=', 'goods.id')
->where('sale_id', $this->id)
->select(DB::raw('SUM(price*quantity) as total_sales'))
->value('total_sales');
return $AmountOrder;
}
and to deduce the code like this
#foreach ($sales as $sale)
<tr>
<td class="table-text"><div>{{ $sale->id }}</div></td>
<td>
{{ $sale->client->name }}
</td>
<td>
{{$sale->date}}
</td>
<td>
{{$sale->AmountOrder($sale)}}
</td>
<td>
{{$sale->debt($sale)}}
</td>
<td>
{{$sale->date_of_issue}}
</td>
</tr>
#endforeach
But the problem is that the query is performed on each line. I'm new to Laravel, but thought maybe you can solve this problem somehow more beautiful?
Thank you very much in advance!

You are probably talking about the Eager Loading.
From the docs:
When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.
However, you will be not able to use the Eager Loading now, with this code in the AmountOrder method.
A simple google search, also, led me to this example of Eager Loading with aggregate functions/relationships.
It will be probably a good start to think and implement your solution.

you have wrong in your select :
$AmountOrder = DB::table('goods')
->join('sale_lines', 'sale_lines.good_id', '=', 'goods.id')
->where('sale_id', $this->id)
->select(DB::raw('SUM(sale_lines.price*sale_lines.quantity) as total_sales'))
->value('total_sales');

My relationship
class Sale extends Model
{
//Получаем товар в этой продаже
public function good()
{
return $this->belongsTo('App\Good');
}
}
class Good extends Model
{
//В каких закупках был этот товар
public function purchases()
{
return $this->hasMany('App\Purchase');
}
//Продажи с этим товаром
public function sales()
{
return $this->hasMany('App\Sale');
}
}
Is it correct?

In my model i create method
public function AmountOrderRelation()
{
return $this->belongsTo('App\Good')
->selectRaw('sum(price) as aggregate, id')
->groupBy('id');
}
In controller
$new_sales = Sale::with('AmountOrderRelation')->get();
#foreach ($new_sales as $sale)
<tr>
<td class="table-text"><div>{{ $sale->id }}</div></td>
<td>
{{ $sale->AmountOrderRelation }}
</td>
</tr>
#endforeach
But my relations is null. What's my mistake?

I did it!
public function AmountOrder()
{
return $this->HasOne('App\SaleLines')
->join('goods', 'sale_lines.good_id', '=', 'goods.id')
->selectRaw(DB::raw('SUM(price*quantity) as aggregate, sale_id'))
->groupBy('sale_id');
}
public function getAmountOrderAttribute()
{
// if relation is not loaded already, let's do it first
if ( ! array_key_exists('AmountOrder', $this->relations))
$this->load('AmountOrder');
$related = $this->getRelation('AmountOrder');
// then return the count directly
return ($related) ? (int) $related->aggregate : 0;
}
And in controller
$sales = Sale::with('AmountOrder')->get();

Related

Laravel "belongsTo" function. Not exactly sure how this works. Help to access related model info from Blade template

I am having issues understanding the "belongsTo" method in a class I am working with.
I have an "Asset" model which wasn't written by me, but I'd guess it works, and it has this function where I am trying to access the 'name' property of the "AssetMake" table (Which foreign and primary key args look about right):
public function assetMake()
{
return $this->belongsTo(AssetMake::class, 'assetmake_id', 'id');
}
In a blade template that looks something like this, with the $asset variable injected in (and succesfuly already being used on the same page):
#foreach($assets as $asset)
<tr>
<td width="5%" class="filter_id">{{ $asset['unit_id'] }}</td>
<td width="20%" class="filter_type">{{ $asset['TypeName'] }}</td>
<td width="25%">{{ $asset['description'] }}</td>
<td width="20%">{{ $asset->assetMake()->get() }}</td>
</tr>
#endforeach
"AssetMake" looks like this, do I need a corresponding "hasMany" function?:
class AssetMake extends Model
{
use ModelDateSerializeNonISO;
protected $table = 'assetmake';
protected $primaryKey = 'id';
protected $hidden = ['updated', 'created'];
}
I have tried acessing the injected $asset variable in a blade template as such:
<td width="20%">{{ $asset->assetMake->get }}</td>
<td width="20%">{{ $asset->assetMake->get() }}</td>
<td width="20%">{{ $asset->assetMake()->get }}</td>
<td width="20%">{{ $asset->assetMake->name }}</td>
<td width="20%">{{ $asset->assetMake()->name }}</td>
The 'name' property of the assetmake table is what I really need access to here.
Is this some kind of lazy/eager loading problem? I'm just not sure exactly what's happening here, and why I can't access the property. I've checked in various sources, and nothing I've tried works, but I'm sure it's fairly straight forward. Any tips?
The way to access a related model is to call it as you would normally call a property. So something like $asset->assetMake->name should work.
Behind the scenes, I believe Laravel uses PHP's magic methods to create properties on the model based on the method names so that they point to the related model (parent or child).
Similarly, if you have a hasMany relationship like so:
public function children()
{
return $this->hasMany(Child::class, 'child_id',);
}
You can access the children just by calling $parent->children.
And if you need to access the Child query builder from the parent, you have to call the children() method.
E.g
$parent->children()->create($childData)
Ok, I worked it out. It was an issue with the controller. I'm still working this out and the magic in Laravel can be confusing to me. I added the line "->join('assetmake', 'assetmake.id', 'asset.assetmake_id')" to the controller query. And added to the select statement as well 'assetmake.name as AssetMakeName'
$assets = FleetFuel::where('fleet_fuel.customer_id', $user->customer_id)
->where('fleet_fuel.isOrphan', 0)
->where('fleet_fuel.hours', '>=', 0) // -1.00 = first ever record
->where('fleet_fuel.burn', '>=', 0) // -1.00 = first ever record
->join('asset', function($join) {
$join->on('fleet_fuel.unit_id', '=', 'asset.Unit_ID');
$join->on('fleet_fuel.customer_id', '=', 'asset.Customer_ID');
})
->join('assettype', 'assettype.ID', 'asset.assettype_id')
->join('assetmake', 'assetmake.id', 'asset.assetmake_id')
->select('fleet_fuel.unit_id', DB::raw('max(fleet_fuel.delivery) as lastfuel'), 'asset.description', 'asset.Rego', 'assettype.Name as TypeName', 'assetmake.name as AssetMakeName')
->groupBy('fleet_fuel.unit_id')->get();
return view('fleetFuel.assets',
[
'companyName' => $companyName,
'assets' => $assets
]
);
And then accesed it in the blade view:
<td width="20%" class="filter_make">{{ (isset($asset['AssetMakeName'])) ? ($asset['AssetMakeName']) : ("No make available")}}</td>

Laravel orderby with relationship

i'm trying to sort the student list by each level with using relationship method with OrderBy function but unfortunately i can't make it work any idea whats missing on my code?
Note:
every-time i remove the orderby my code will work but students level are not arrange accordingly
Controller:
$students=Student::with('level')->where(['status' => 'ENROLLED'])->get()->orderBy('level_name','asc');
View
<table>
<tr>
<th>Name</th>
<th>Level</th>
</tr>
#foreach($students as $std)
<tr>
<td>
{{$std->student_name}}
</td>
<td>
#foreach($std->level as $lv)
{{$lv->level_name}}
#endforeach
</td>
</tr>
#endforeach
</table>
You can't order by a relationship because under the hood laravel makes two seperate queries under the hood.
You can instead use a join, something like this (beware I guessed your table names, so you may have to update them).
$users = Student::join('levels', 'students.level_id', '=', 'levels.id')
->orderBy('levels. level_name', 'asc')->select('students.*')->paginate(10);
Try this:
Controller:
$students = Student::with(['level' => function (Builder $query) {
$query->orderBy('level_name', 'asc');
}])->where(['status' => 'ENROLLED'])->get();
In addition you can add orderBy() to relation method.
Student Model:
public function level()
{
return $this->relationMethod(Level::class)->orderBy('level_name', 'asc');
}
Try this
$students=Student::with('level')->where(['status' => 'ENROLLED'])->orderBy('level_name','asc')->get();

Is there a better way than doing multiple queries in my case?

I start in laravel and I would like to have your opinion on one point.
I have a controller. In this controller, I return a view and several functions that are all SQL queries.
My view must have all these queries because I display different types of foreach. Is this the right way to do or is there something shorter / more appropriate?
My controller :
protected function indexWeb()
{
return view('pages.web.program', [
'getAllCoursesBloc1' => $this->getAllCoursesBloc1(),
'getAllCoursesBloc2' => $this->getAllCoursesBloc2(),
'getAllCoursesBloc3' => $this->getAllCoursesBloc3(),
'getWebCoursesBloc1' => $this->getWebCoursesBloc1(),
'getWebCoursesBloc2' => $this->getWebCoursesBloc2(),
'getWebCoursesBloc3' => $this->getWebCoursesBloc3(),
$this->setMetasIndex()
]);
}
protected function getAllCoursesBloc1()
{
$courses = Course::where('bloc', 1)
->OrderBy('title', 'ASC')
->get();
return $courses;
}
protected function getAllCoursesBloc2()
{
$courses = Course::where('bloc', 2)
->OrderBy('title', 'ASC')
->get();
return $courses;
}
... and so on
An exemple of foreach in my view
#foreach($getWebCoursesBloc1 as $key => $course)
<tr class="link-row" data-href="{{ $course->slug }}">
<td class="program-table__orientation">{{ $course->orientation }}</td>
<td class="program-table__course">
<a href="{{ url('cours/'.$course->slug) }}" class="program-table__course__link">
<span class="program-table__course__name">{{ $course->title }}</span>
</a>
<span class="program-table__course__desc">{{ $course->shortdescription }}</span>
</td>
<td class="program-table__hour"><span>{{ $course->duration }}</span></td>
<td class="program-table__ects"><span>{{ $course->ects }}</span></td>
<td class="program-table__quad"><span>{{ $course->quadrimester }}</span></td>
</tr>
#endforeach
Thank you very much
Use whereIn() in Laravel's model.
public static function getAllCoursesByIds(array $ids)
{
return self::whereIn('bloc', $ids)
->orderBy('title', 'asc)
->get();
}
In controller you can get access by:
public function indexWeb()
{
return view('pages.web.program', [
'all_courses' => Course::getAllCoursesByIds([1,2,3,4,5]),
]);
}
Otherwise you can filter them by specific ids. In your view call $all_courses.
To get the Courses with "block" equals 1 use:
$all_courses->filter(function ($course, $key) {
return $course->bloc === 1;
});
What you're realizing is that all these DB calls are currently synchronous and there is no dependency between them. In theory, if you could call them asynchronously, the script would run quicker because it's rendering as soon as the last item returns.
To do this, you need to do the rendering in the client (javascript) instead of the server. Promises or Async/Await would probably work best. Ultimately your client would make all the async calls to your laravel based web service and once they're all completed it would render. You may find, that you don't even need to wait for all of them and the rendering can be asynchronous as well.
You could possibly accomplish this using only PHP with something like ReactPHP.

Laravel Eloquent : belongsTo relationship - Error: Trying to get property of non-object

First time to try laravel eloquent relatioinstip
I know it's really simple but I am getting this error don't know what's wrong with it
I have 2 tables in data base, news and news_image
in database
Tables:
news
id | header | details
news_image
id | image | news_id
And have 2 models News , newsImage
newsImage model :
class newsImage extends Eloquant {
protected $table = 'news_image';
public function news()
{
return $this->belongsTo('News');
}
}
News model
class News extends Eloquent
{
protected $table = 'news';
public $timestamps = false;
public function image()
{
return $this->hasMany('newsImage');
}
}
The view:
foreach($news as $new)
<tr>
<td> {{$new->id}} </td>
<td> {{ $new->header}}</td>
<td> {{ $new->details }}</td>
</td> {{$new->news->image}}</td>
</tr>
when I run this it's get error :
Trying to get property of non-object (View: /var/www/html/clinics/app/views/news/index.blade.php)
Any ideas on what could be causing this error?
First, assuming what you are passing to your view is an array or Collection of News objects, you should probably be using $new->image to access the News Item relation. By defining the function image() in your News model, you can access the relation with either the ->image or ->image() calls. In either case, what you need to call is probably
$new->image->first()->image
To break that down:
->image gets the Collection of NewsImage relations
->first() gets the first item in the Collection
->image (the secone one) gets the image field from that NewsImage
If the Collection has more than one item, you can instead loop over it to get all of the images as shown in the other answer.
There are a couple things I would change:
In your News model, change the relationship from "image" to "images" since it's a one to many relationship. It just keeps your code clean.
Your foreach loop in your view should loop through all the news models, but remember that each news model has multiple images, so you should have another loop inside your existing loop to display the images, i.e. foreach ($new->images as $image)
#foreach ($news as $new)
<tr>
<td> {{$new->id}} </td>
<td> {{ $new->header}}</td>
<td> {{ $new->details }}</td>
<td>
#foreach ($new->images as $image)
{{ $image->image }}
#endforeach
</td>
</tr>
#endforeach

Laravel Object Relation does not work in foreach loop

I have a typical model relation. I have the model QR, which hasMany Rating, and a Model Rating, which belongsTo Qr.
Now I want to output the Ratings, which belong to a single qr model, through a foreach loop like this:
<table>
<tr>
<th>ID</th>
<th>UnitID</th>
<th># of Ratings</th>
</tr>
#foreach($qrs as $qr->ratings)
<tr>
<td>{{$qr->id}}</td>
<td>{{$qr->unit_id}}</td>
<td>{{$qr->ratings->count()}}</td>
</tr>
#endforeach
</table>
This is my Controller:
public function index()
{
//
$unit = Unit::all()->first();
$qrs = Qr::all()->first();
return View::make('index')
->with('unit', $unit)
->with('qrs', $qrs);
}
Here are my two Models
Rating.php:
class Rating extends \Eloquent {
protected $guarded = [];
public function qr(){
return $this->belongsTo('Qr');
}
}
Qr.php:
class Qr extends \Eloquent {
protected $guarded = [];
public function unit(){
return $this->belongsTo('Unit');
}
public function ratings(){
return $this->hasMany('Rating');
}
}
I actually want to output the count of ratings, a Qr-Code has. I know it is possible to do it somehow like this:
{{Rating::where('qr_id', $qr->id)->count()}}
But I want to do it somehow like this in the foreach loop
{{ $Qr->rating->count() }}
If this is somehow possible.
I get the relation, if I just output the first() of Qr and then
var_dump($qrs->ratings->toArray())
But I don't know how to get the count Number of ratings in combination with the foreach loop. Any help would be dearly appreciated.
Couple of things wrong here:
// view:
#foreach($qrs as $qr->rating)
// should be:
#foreach($qrs as $qr)
// controller:
$unit = Unit::all()->first();
$qrs = Qr::all()->first();
// this way you get all Units then fetch first Unit from the collection,
// the same with Qrs, so change it to:
$unit = Unit::all(); // do you need it at all?
$qrs = Qr::with('ratings')->get();
This will solve the problem and in the foreach loop you will be able to access $qr->ratings->count() which will be Collection method.
At first you have used this:
#foreach($qrs as $qr->ratings)
You need to change it to this (as already stated in an answer):
#foreach($qrs as $qr)
Then in your index method you have used this:
public function index()
{
$unit = Unit::all()->first();
$qrs = Qr::all()->first();
return View::make('index')->with('unit', $unit)->with('qrs', $qrs);
}
In this case you need to get a collection of QR models and since Unit and Rating are related to Qr then you may use with and get() to get a collection of QR models like this:
public function index()
{
$qrs = Qr::with(array('unit', 'ratings'))->get();
return View::make('index')->with('qrs', $qrs);
}
Then you'll be able to loop the Qr models in your view like this:
#foreach($qrs as $qr)
<tr>
<td>{{ $qr->id }}</td>
<td>{{ $qr->unit_id }}</td>
<td>{{ $qr->ratings->count() }}</td>
</tr>
#endforeach

Categories