Laravel Eloquent Query Builder (Using query existence, using whereHas) - laravel

Tables
PROFILE
id address type approved fky_profile_vendor_id
VENDOR
id name
PRODUCT
id name price instock fky_prod_vendor_id
Relationship
PROFILE <-(one-to-one)-> VENDOR <- (one-to-many) -> PRODUCT
Query
Eloquent query to get all the products those are in stock
PRODUCT::where('instock','>',0)->get();
How can I get all the products in stock of a approved vendor?
Thanks
K

App\Profile
use Illuminate\Database\Eloquent\Model;
class Profile extends Model {
public function scopeApproved($query)
{
return $query->where('approved', 'y');
}
public function vendor()
{
return $this->belongsTo('App\\Vendor');
}
}
--
App\Vendor
use Illuminate\Database\Eloquent\Model;
class Vendor extends Model {
public function profile()
{
return $this->hasOne('App\\Profile');
}
public function products()
{
return $this->hasMany('App\\Product');
}
}
--
App\Product
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
public function vendor()
{
return $this->belongsTo('App\\Vendor');
}
}
How to use:
$vendors = Vendor::whereHas('profile', function ($q) { $q->approved(); })->with('products')->get();
$products = $vendors->map(function ($vendor)
{
return $vendor->products;
});
This will return a Collection of Productss of Vendors with approved Profile.

Related

Laravel How To Update Nested createMany

Been having a hard time on figuring out how to implement updating records on a nested createMany based on the store method. I have these models and relations:
User Model:
class User extends Model
{
public function orders() {
return $this->hasMany(Order::class);
}
}
Order Model:
class Order extends Model
{
public function user() {
return $this->belongsTo(User::class);
}
public function subOrders() {
return $this->hasMany(SubOrder::class);
}
}
SubOrder Model:
class SubOrder extends Model
{
public function order() {
return $this->belongsTo(Order::class);
}
public function subOrderProducts() {
return $this->hasMany(SubOrderProducts::class);
}
}
SubOrderProducts Model:
class SubOrderProducts extends Model
{
public function subOrder() {
return $this->belongsTo(SubOrder::class);
}
}
Here are the tables:
orders table:
id name
sub_orders table:
id order_id date price
sub_order_products table:
id sub_orders_id product_id
Then on the store method:
public function store(StoreOrderRequest $request) {
$order = auth()->user()->orders()->create($request->validated());
$order_subs = $order->subOrders()->createMany($request->orders);
$order_sub_products = $request->only('subproducts');
foreach ($order_subs as $key => $value) {
$order_sub->subOrderProducts()->createMany($order_sub_products[$key]['products']);
}
}
What I wanted to achieve is to update or create those sub orders and sub order products. If the sub order is already existing, then update, otherwise create a new record with those corresponding sub order products.
Here's what I've tried so far:
public function store(UpdateOrderRequest $request, Order $order) {
$order->update($request->validated());
$order_subs = $order->subOrders()->updateMany($request->orders);
$order_sub_products = $request->only('subproducts');
foreach ($order_subs as $key => $value) {
$order_sub->subOrderProducts()->updateMany($order_sub_products[$key]['products']);
}
}
It's not working as expected since the order subs is only a single record. What's the best way or the right process for updating/creating these records? Thanks.

creating query from other tables that has the ID of the primary table in laravel

Apology for the title. I'm really not sure how to name the title correctly base from my situation. I'm new in coding that's why I am not familiar with proper terminologies.
below are the tables I am working on right now.
I am displaying the details from loan_application table. I can able to include the loan_durations and users in my #foreach but I realized I need to include also the SUM of the AMOUNT from loan_interests table and the SUM of AMOUNT from LOAN PENALTIES which gives me an headache because I can't pull them out.
LOAN APPLICATION MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanApplication extends Model
{
public function user()
{
return $this->hasOne('App\User', 'id','user_id');
}
public function loanDuration()
{
return $this->hasOne('App\LoanDuration', 'id','loan_duration_id');
}
public function interest()
{
return $this->belongsTo('App\LoanInterest','loan_id', 'id');
}
public function penalty()
{
return $this->belongsTo('App\LoanPenalty','loan_id', 'id');
}
}
LOAN INTEREST MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanInterest extends Model
{
public function loanInterest()
{
return $this->belongsTo('App\LoanApplication','loan_id', 'id');
}
}
LOAN PENALTY MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanPenalty extends Model
{
public function loanPenalties()
{
return $this->belongsTo('App\LoanApplication','loan_id', 'id');
}
}
for my controller
public function collectorMembers($id)
{
$collectormember = CollectorMember::where('collector_id',$id)->get();
return view('dashboard.collector-members.collector-borrowers-list', compact('collectormember'));
}
This gives this result
the CollectorMember gets the info on this table
Can you help me please? thanks a lot in advance!
There is a way to accomplish what you're after, but first I think you need to revisit your schema and relationships.
Foreign key columns should be of the same type as the referenced column. For example loan_id on the loan_interests should be int(11) just like the id column on the loan_applications table
I think you may be confusing relationship types. For example a User hasMany LoanApplications and a LoanApplication belongsTo a User. A LoanApplication hasMany LoanPenaltys and hasMany LoanInterests. A LoanPenalty and a LoanInterest both belongsTo a LoanApplication
The user_id column on the loan_penalities table is redundant because a LoanPenalty belongsTo a LoanApplication and a LoanApplication belongsTo a User
I'd recommend storing currency amounts in cents and using unsigned integers as the column type (e.g. for interest_amount)
Consider the following schema (some columns not shown):
Then consider the following models with relationships:
class User extends Model {
public function loanApplications()
{
return $this->hasMany(LoanApplication::class);
}
public function collectors()
{
return $this->belongsToMany(Collector::class);
}
}
class Collector extends Model {
public function users()
{
return $this->belongsToMany(User::class);
}
}
class LoanApplication extends Model {
public function user()
{
return $this->belongsTo(User::class);
}
public function loanDuration()
{
return $this->belongsTo(LoanDuration::class);
}
public function loanInterests()
{
return $this->hasMany(LoanInterest::class, 'loan_id');
}
public function loanPenalties()
{
return $this->hasMany(LoanPenalty::class, 'loan_id');
}
}
class LoanDuration extends Model {
public function loanApplications()
{
return $this->hasMany(LoanApplication::class);
}
}
class LoanInterest extends Model {
public function loanApplication() {
return $this->belongsTo(LoanApplication::class, 'loan_id');
}
}
class LoanPenalty extends Model {
public function loanApplication()
{
return $this->belongsTo(LoanApplication::class, 'loan_id');
}
}
Then to list all loan applications in a Resource Controller:
class LoanApplicationController extends Controller {
public function index()
{
$loan_applications = LoanApplication
::with(['user', 'loanInterests', 'loanPenalties'])
->get();
$loan_applications = $loan_applications->map(function ($loan_application) {
$loan_application->loan_penalities_sum = $loan_application->loanPenalties->sum('penalty_amount_cents');
$loan_application->loan_interests_sum = $loan_application->loanInterests->sum('interest_amount_cents');
return $loan_application;
});
return view('dashboard.loan-applications.index', compact('loan_applications'));
}
}
And in your dashboard.loan-applications.index blade template:
<table>
<tr>
<th>Username</td>
<th>Total Interest</td>
<th>Total Penalty</td>
</tr>
#foreach ($loan_applications as $loan_application)
<tr>
<td>{{$loan_application->user->username}}</td>
<td>{{$loan_application->loan_interests_sum}}</td>
<td>{{$loan_application->loan_penalties_sum}}</td>
</tr>
#endforeach
</table>
Note the above example does not include pagination; all resources are loaded at once.
The above example also assumes there should be a many-to-many relationship between collectors and users, but I would imagine a Collector should be related to the loan_applications table, not to a User.

How to get data from table related through pivot table?

I have 4 tables: countries, activities, country_activities and packages.
countries and activities are related through pivot table country_activity, and packages is related to country_activity.
Now, How do I eager load all packages related to each activity in a country?
class Country extends Model
{
public function activities() {
return $this->belongsToMany('App\Models\Activity','country_activities')->using('App\Models\CountryActivity')->as('country_activities');
}
}
class Activity extends Model
{
public function countries() {
return $this->belongsToMany('App\Models\Country','country_activities')->using('App\Models\CountryActivity')->as('country_activities');
}
}
class Package extends Model
{
public function country_activities() {
return $this->belongsToMany('App\Models\CountryActivity');
}
}
class CountryActivity extends Pivot
{
protected $table = 'country_activities';
public function packages() {
return $this->hasMany('App\Models\Package');
}
}
So, this worked for me.
class Country extends Model
{
public function activities() {
return $this->belongsToMany('App\Models\Activity','country_activities')->using('App\Models\CountryActivity')->withPivot(['id'])->as('country_activities');
}
Now, In my controller, I do this
$country = Country::with(['activities'=> function($q) {$q->where('name','Trekking');}])->where('name','Nepal')->first(['id','name']);
$country->activities->map(function ($i){
$i->country_activities->load('packages');
return $i;
});
I did something similar in a project i worked on. I'm not sure it will work but it's worth the shot:
$country = Country::find(1);
$country->activities = $contry->activities()->get()->each(function ($i, $k){
$i->packages = $i->pivot->packages;
//$i->makeHidden('pivot'); -> This is useful if you want to hide the pivot table
});
var_dump($country);

how to make join query between three tables in laravel

I want to build a query in laravel between three tables (regions, countries, packages) such that table are related together.
regions table contains (id, name, description)
countries table contains (id, region_id, name, description)
packages table contains (id, county_id, pkg_title, pkg_description, price)
I want to select all packages where region_id=1
how can I make query for this situation in laravel query builder. please help me about this question
Set your models as follows.
class Region extends Model
{
}
class Country extends Model
{
public function region()
{
return $this->belongsTo(Region::class);
}
}
class Package extends Model
{
public function country()
{
return $this->belongsTo(Country::class);
}
}
And state following query inside your method.
$region_id = 1;
$PackageWithRegions = Package::with([
'country' => function ($county) use ($region_id) {
return $county->with([
'region' => function ($region) use ($region_id) {
return $region->where('id', $region_id);
}
]);
}
])->get();
// $PackageWithRegions is a collection of packeges with regions where regiion_id = 1
More on eloquent relationships
You can use Eloquent model relationship to prform this, like below
In region controller file
$region = Region::where(['id'=>1])->with(['country'])->get(); ///fetch region with country calls relation declared in region model
In Region.php model
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Region extends Model {
protected $table = 'regions';
public function country(){
return $this->hasOne('App\Models\Country','region_id')->with(['packages']); ///this will fetch country with all pacckages on matching region_id, join of package with country is declared in country model.
}
}
In Country.php model
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Country extends Model {
protected $table = 'countries';
public function packages(){
return $this->hasMany('App\Models\Package','county_id'); //join of country with packages on county_id
}
}
In Package.php model
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Package extends Model {
protected $table = 'packages';
}
You can see in Laravel doc (https://laravel.com/docs/4.2/eloquent) in section Has Many Through that if you have a model like:
countries
id - integer
name - string
users
id - integer
country_id - integer
name - string
posts
id - integer
user_id - integer
title - string
Then you can access to last relation in this way:
class Country extends Eloquent {
public function posts()
{
return $this->hasManyThrough('Post', 'User');
}
}
Or using customs relations IDs:
class Country extends Eloquent {
public function posts()
{
return $this->hasManyThrough('Post', 'User', 'country_id', 'user_id');
}
}
So, you can access to the posts of a country:
$posts = Country::get(2)->posts;
// with where:
$posts = Country::where('name', '=', 'USA')->get()->posts;

Laravel Sum of relation

I want to return the sum of "amount" from my payments table. There can be many payments for one invoice. The below "->sum('amount') does not work, it returns:
Call to a member function addEagerConstraints() on a non-object.
How to return the sum of all payments for each invoice in my relation?
Invoices Model:
class Invoices extends Eloquent {
public function payments()
{
return $this->hasMany('Payments')->sum('amount');
}
}
Expenses Model:
class Payments extends Eloquent {
public function invoices()
{
return $this->belongsTo('Invoices');
}
}
My table "payments" holds the foreign key of my tables invoices, which is invoices_id.
Starting by Laravel 8 you can simply use withSum() function.
use App\Models\Post;
$posts = Post::withSum('comments', 'votes')->get();
foreach ($posts as $post) {
echo $post->comments_sum_votes;
}
https://laravel.com/docs/8.x/eloquent-relationships#other-aggregate-functions
class Invoices extends Eloquent {
public function payments()
{
return $this->hasMany('Payments');
}
}
class Payments extends Eloquent {
public function invoices()
{
return $this->belongsTo('Invoices');
}
}
In your controller
Invoice::with(['payments' => function($query){
$query->sum('amount');
}])->get();
;
You can show this package
$invoices = Invoices::withSum('payments:amount')->get();
First decide which Invoice (for example id 1)
$invoice = Invoices::find(1);
Then eager load all the corresponding payments
$eagerload = $invoice->payments;
Finally assuming you have the amount field in your Invoice model you can simply find the sum using the method below:
$totalsum = $eagerload->sum('amount');
This is also possible. we can do by model itself.
class Invoices extends Eloquent {
public function payments()
{
return $this->hasMany('Payments')
->selectRaw('SUM(payments.amount) as payment_amount')
->groupBy('id'); // as per our requirements.
}
}
}
Note
SUM(payments.amount)
payments is tableName
amount is fieldName
I found a simple way to acomplish this in here, you can use withPivot() method.
You can redefine a bit your relation to something like following
public function expenses()
{
return $this->belongsToMany('Expenses', 'invoices_expenses')
->withPivot('name', 'amount', 'date');
}

Resources