avoiding duplicated queries in job handle function - laravel

this handle function counts the number of available cities and areas to each state, then saves the results in a log file
need to avoid the duplicated queries in this function
public function handle()
{
$statesIds=State::pluck('id')->toArray();
foreach($statesIds as $stateId){
$statesIds=State::pluck('id')->toArray();
$statecitiesIds=City::where('stateId',$stateId)->pluck('id')->toArray();
$citiesAreasIds=Area::whereIn('cityId',$statecitiesIds)->pluck('id')->toArray();
$stateName=State::where('id',$stateId)->value('name');
Log::info($stateName.' had '.count($statecitiesIds).' cities and ' .count($citiesAreasIds) .' areas' );
}
}
}

You can use Eloquent: Relationships
https://laravel.com/docs/8.x/eloquent-relationships
$states = State::query()->with(['cities' => function($query) {
return $query->with('areas');
}]);
foreach ($states as $state) {
foreach ($state->city as $city) {
Log::info($state->name.' had '.count($state->cities).' cities and ' .count($city->areas) .' areas' );
}
}
And add relationships to your Model
// State Model
public function cities {
return $this->hasMany(City::class, 'stateId', 'id');
}
And City Model
// City Model
public function areas {
return $this->hasMany(Area::class, 'cityId', 'id');
}

Related

Search Query by Child field Eloquent relation

My Product Model is
public function IncomeRepo(){
return $this->hasMany(Income::class,'Product');
}
My Income Report Model Is
public function ProductData(){
return $this->belongsTo(Product::class,'Product','id');
}
My Query is
public function SearchIncomeData(Request $request){
$GetFromDate = $request->FromDate;
$GetToDate = $request->ToDate;
$ProductData = Product::with('IncomeRepo')->whereBetween('created_at', [$GetFromDate, $GetToDate])->get();
return view('Admin.Report.ProductSalesReport',compact('ProductData'));
}
When I return $ProductData it return products table created_at Data. BUT I nee Income table created_at data which be multiple
How can I get it?
My expectation show incomes table created_at data
If you want to filter data by child tables date then you need to use whereHas relationship.
$GetFromDate = $request->FromDate;
$GetToDate = $request->ToDate;
$ProductData = Product::with('IncomeRepo')
->whereHas('IncomeRepo',function($que) use($GetFromDate,$GetToDate) {
$que->whereBetween('created_at',[$GetFromDate, $GetToDate])})->get();
return view('Admin.Report.ProductSalesReport',compact('ProductData'));
In controller. (Use whereBetween)
public function SearchIncomeData(Request $request)
{
$GetFromDate = $request->FromDate;
$GetToDate = $request->ToDate;
$ProductData = Product::with(['IncomeRepo' => function ($query) use ($GetFromDate, $GetToDate)
{
$query->whereBetween('created_at', [$GetFromDate, $GetToDate]);
}
])->get();
return view('Admin.Report.ProductSalesReport', compact('ProductData'));
}
In view
foreach ($ProductData as $product)
{
foreach ($product->IncomeRepo as $income)
{
echo $income->created_at;
}
}

Laravel Using nested with

I couldn't do what I wanted to do with Laravel, actually what I want to do is as follows,
I send getTruck id and list truckHistory with witdh, and I want to pull trukInvoice information with truckHistory invoice_id. But i am getting error where am i doing wrong?
Mysql Connection is as follows.
http://localhost:3000/truck/1
"trucks" table column "plate"
"invoice_details" column "plate_no"
"invoice_details" column "invoice_id"
"invoice" column "id"
Truck Controller
public function getTruck($id)
{
$truck = Truck::find($id)->with([
'truckHistory' => function($query){
// return $query->with(['trukInvoice']);
}
])->first();
return $truck;
}
Truck Model
public function companys()
{
return $this->belongsTo(Contact::class, 'company_id', 'id');
}
public function getCompanyNameAttribute()
{
return $this->companys()->first()->name;
}
public function truckHistory(){
return $this->hasMany(InvoiceDetail::class,'plate_no','plate');
}
public function trukInvoice(){
return $this->belongsTo(Invoice::class,'invoice_id','id');
}
Try this:
$truck = Truck::leftJoin('invoices', 'trucks.invoice_id', 'invoices.id')
->leftJoin('invoice_details', 'trucks.plate_no', 'invoice_details.plate')
->select('*')
->first();
or
$truck = Truck::with(['invoices' => function ($query) {
$query->whereHas('invoice_details', function ($q){
$q->whereNotNull('invoice_details.plate');
});
}])->first();
Check the documentation on restraining eager loads.

Laravel Eloquent how to get all parents

I have relation like this:
DB relation
I have a code in my model that retrieves me just one parent:
public function AllParents()
{
return $this->belongsToMany($this, 'parent', 'product_id', 'parent_id')
->select('parent', 'name');
}
I get it in my controller like this:
private function product(Product $product)
{
return $product->Product()
->with('AllParents')
->get();
}
Finally I need data like this:
Product1/Product_2/Product_3
I think I need a loop, but how to do it in Eloquent?
Just change relationship. You have mentioned pivot table name wrong one.
public function AllParents()
{
return $this->belongsToMany(Product::class, 'Product_parent', 'product_id', 'parent_id') ->select('parent', 'name');
}
and then you can access
\App\Models\Product::with('AllParents')->get()
In your Product Model. You have define relationship like this.
public function allParents()
{
return $this->belongsToMany(Product::class, 'product_parents', 'product_id', 'parent_id')->select('name');
}
And, In Controller you can get all the parents with eager loading.
Product::with('allParents')->find($productId);
And, In View you can use foreach loop to iterate every parent object.
#foreach ($product->allParents as $parentProduct)
{{ $parentProduct->name }}
#endforeach
I did like this:
I modified my controller
private function product(Product $product)
{
$allParents = [];
$parent = null;
$parent->$product->Product()->with('AllParents')->first()->id;
while ($parent != null) {
array_push($allParents, Product::all->find($parent));
$parent = Product::all()->find($parent) - first();
}
}

Laravel, sort result on field from relation table?

I have a list with gamers and another table with game stats.
My list code is:
$gamers = Gamer::with(['lastGameStat' => function($query) {
$query->orderBy('total_points', 'DESC');
}])->paginate(20);
relation:
public function lastGameStat() {
return $this->hasOne(GameStat::class, 'gamer_id', 'id')->orderBy('created_at', 'DESC');
}
in relation table I have field: total_points and with this code I thought it's possible to sort list of gamers by total_points $query->orderBy('total_points', 'DESC');
It doesn't work, can somebody give me an advice here how can I sort the result on a field from relation table?
I guess you'll need either another relation or custom scopes to fetch various game stats of a gamer.
Second relation
Gamer.php (your model)
class Gamer
{
public function bestGameStat()
{
return $this
->hasOne(GameStat::class)
->orderBy('total_points', 'DESC');
}
}
Custom scopes
Gamer.php
class Gamer
{
public function gameStat()
{
return $this->hasOne(GameStat::class);
}
}
GameStat.php
use Illuminate\Database\Eloquent\Builder;
class GameStat
{
public function scopeBest(Builder $query)
{
return $query->orderBy('total_points', 'DESC');
}
}
In your controller:
$gamersWithTheirLatestGameStatistic = Gamer::with(['gameStat' => function($query) {
$query->latest();
}])->paginate(20);
$gamersWithTheirBestGameStatistic = Gamer::with(['gameStat' => function($query) {
$query->best();
}])->paginate(20);
Be aware as this is untested code and might not work.

Return collection based on model method result

I have a User model with a Credits relation.
public function credits()
{
return $this->hasMany('App\Credit');
}
I'd like to return all users where their credit balance is greater than 0. Right now, I have two methods; one to retrieve the total credits the user has amassed and another to retrieve the credits the user has spent.
public function creditsIncome()
{
return $this->credits->where('type', 0)->sum('amount');
}
public function creditsExpense()
{
return $this->credits->where('type', 1)->sum('amount');
}
To get the balance, I have a third method:
public function creditsBalance()
{
return $this->creditsIncome() - $this->creditsExpense();
}
Is there any way to do something like User::where('creditsBalance', '>', 0);?
You can use a modified withCount():
User::withCount([
'credits as income' => function($query) {
$query->select(DB::raw('sum(amount)'))->where('type', 0);
},
'credits as expense' => function($query) {
$query->select(DB::raw('sum(amount)'))->where('type', 1);
}
])->having(DB::raw('income - expense'), '>', 0)->get();

Resources