Getting sum of field through polymorphic relationship in Laravel - laravel

I have two models, Payments_Distribution and Donation.
In my Donation model:
public function payments() {
return $this->morphToMany(Payments_Distribution::class, 'payable');
}
And I can save a payment distribution to the donation model using the following:
$distribution = new Payments_Distribution;
$distribution->payment_id = $payment->id;
$amount = $request->payment_details['amount'][$i];
$donation->payments()->save($distribution);
But I'm stuck on how to retrieve the sum of all the associated records' amount fields in the Payment_Distribution model table.
Would it be something like:
$donation->payments()->______ ->sum('amount');
Or something else? I'm still a bit new to polymorphic relationships.

In your code, you are not saving amount to the Payments_Distribution instance before using the ->save() method. Replace:
$amount = $request->payment_details['amount'][$i];
With:
$donation->amount = $request->payment_details['amount'][$i];

Related

Laravel Model hasMany - getting too may results

I'm learning Laravel, so I'm quite new.
I have 2 Models: House and Translation.
My House Model:
use HasFactory;
protected $guarded = ['id'];
public function trans(){
return $this->hasMany(Translation::class);
}
}
My Translation Model:
function House(){
return $this->belongsTo(House::class);
}
}
When I do in the controller something like ($id=2 e.g) :
$house = House::find($id)::with('trans')->get();
I get a result with all houses (there are currently 2 in the DB).
When I just do the query "House::find($id)->get()" it works fine.
What part am I missing?
::with('trans') returns completely new query and forgets everything about your ::find($id)
you need to use load method.
$house = House::find($id);
$house->load('trans');
What happens is, House::find($id) is a method that returns the element by its primary key.
Then, the ::with('trans') gets the result, sees the House class and starts creating a new query builder for the Model.
Finally, the ->get() runs this new query and the end result is what is return for the $house value.
You have two options that will result to what you want to do.
First one is, to find the house entry and then load its relation
$house = House::find($id);
$house->load('trans');
The second option is this:
$house = House::where('id',$id)->with('trans')->first();
The second one is a query builder that results to the first element with id = $id,
and load its relation with translations.
You can check for more details in the laravel documentation. They have a very well-written documentation and the examples help a lot.

Laravel: Load only pivot additional columns without relation

I have the following structure:
Charge
id
amount
created_at
..
Payment
id
amount
created_at
..
and a pivot table charge_payment, since one charge can be covered partially by multiple payments.
charge_payment
charge_id
payment_id
amount
The amount column on the pivot table defines the amount that the given Payment covers for the Charge.
And I need to get only the "paid" amount for a Payment.
I have the following models:
// Charge.php
class Charge extends Model
{
public function payments()
{
return $this->belongsToMany('App\Payment')->withPivot('amount');
}
}
// Payment.php
class Payment extends Model
{
public function charges()
{
return $this->belongsToMany('App\Charge')->withPivot('amount');
}
}
I want to be able to get only the paid amount with:
$payment = Payment::find(..);
$paid_amount = $payment->charges->sum('pivot.amount');
However, with this approach the related models are loaded from the database and I won't be needing them.
Is there a way to load only the additional pivot column without the related models?
Thank you very much!
Firstly, if one Payment can be always related only to one Charge, I would advise you to change the relationship from many-to-many to one-to-many (it will be just more correct and simpler).
Than you can simple use aggregate function (in your case withSum) which will return you only resulting values without relationship Models.
$payment = Payment::withSum('payments', 'amount')->find(..);
{{ $payment->payments_sum_amount }}

Is laravel seeding as hard as I see it or I'm stumbling with something that's not that complicated?

The last few days I've been rocking my head against the wall with the seeders. I can't seem to get the hang of it.
The relationships are very simple:
A Brand hasMany products and each product belongs to a single brand.
A Category hasMany products and each product belongs to a single category.
Given that, I'm creating 5 categories at the beginning so I can retrieve a random one later.
I'm also creating 10 brands, and for each brand I'm creating 50 products and make them belong to that brand. Then I create the relationship with the product and the category, retrieving a random category for each product.
Im getting this error:
PDOException::("SQLSTATE[HY000]: General error: 1364 Field 'brand_id' doesn't have a default value")
I dont understand why I'm getting this error because I'm creating the relationship prior to creating the products:
$brand->products()->saveMany(factory(App\Product::class, 50).
public function run()
{
$users = factory(\App\User::class, 1000)->create();
$categories = factory(\App\Category::class, 5)->create();
factory(App\Brand::class, 10)->create()->each(function ($brand) {
$brand->products()->saveMany(factory(App\Product::class, 50)->make()->each(function ($product) use ($brand) {
$product->category()->associate($this->getRandomCategory());
$product->save();
}));
});
}
private function getRandomCategory() {
return \App\Category::all()->random();
}
private function getRandomUser() {
return \App\User::all()->random();
}
I don't know if I'm making a big deal out of seeding but it just seems complex to me. Maybe I'm taking a wrong approach using the factories. Is there any great tutorial for seeding out there?
Thanks in advance!
This is actually not a seeding problem. The PDO-driver already tells you about the issue:
brand_id does not a have a default value
Probably Laravel assumes, that the id column does not need a default and therefore does not insert it with an id. But the column seems to have no default definition in the database (should be smth. like AUTO_INCREMENT). And that's the reason why you receive an error from the database.
The problem was this one:
The saveMany method gets called after the each function is done, so I was kinda saving the product before it added the brand relationship. Thats why it couldnt assign the foreign_key brand_id. This is the block of code working:
public function run()
{
$users = factory(\App\User::class, 1000)->create();
$categories = factory(\App\Category::class, 5)->create();
factory(App\Brand::class, 10)->create()->each(function ($brand) {
$brand->products()->saveMany(factory(App\Product::class, 50)->make()->each(function ($product) use ($brand) {
$product->category()->associate($this->getRandomCategory());
}));
});
}
private function getRandomCategory() {
return \App\Category::all()->random();
}
private function getRandomUser() {
return \App\User::all()->random();
}

How can I link 2 existing models in my laravel code?

I have two models customer and orders. They are already fecthed separately
$customers = customer::all();
$orders = orders::all();
customerID=1 has orderID : 1, 2,4 customerID=2 has orderID : 3,5,9
They are related (hasMany, belongsTo) but the problem is inside my for a certain reason they are separated but I want to send them as response in API using toJson or ToArray as one data having the orders nested to their correct customers.
How can I achieve that linking to have at the end one variable $customersWithOrders that should be transformed to JSON ?
I am using laravel 5.5
I don't know what the context is. Defining relationships as other answers mentioned is a good solution.
In addition, I recently read a pretty good article about this specific scenario.
So you can also do something like this, if you have already retrieved customers and orders:
$customers = Customer::all();
$orders = Order::all();
return $customers->each(function ($customers) use ($orders) {
$customer->setRelation('orders', $orders->where('customer_id', $customer->id));
});
If you already have a relation you just use it. For example, in model Customer.php:
public function orders()
{
return $this->hasMany(Order::class);
}
Then you'd get customer orders by calling $customer->orders
If you already have defined relations, you can simply fetch data with eager loading
// in customer model
public function orders()
{
return $this->hasMany(orders::class, 'orderID');
}
// in controller
$customersWithOrders = customer::with('orders')->get();
return response()->json(['customersWithOrders' => $customersWithOrders]);
// in js
for (let customer in response.customersWithOrders){
let orders = customer.orders
}

How to find a model using pivot table data in Laravel?

i have a tournament and a club model.i use many to many relationship between them.now i want to find a club model using pivot table.
i've tried this:
$tournament = Tournament::find(1);
$club = $tournament->clubs->wherePivot('team_as_1','1');
return $club;
but it shows:Method Illuminate\Database\Eloquent\Collection::wherePivot does not exist.
My tournament model:
public function clubs(){
return $this->belongsToMany('App\Club','tbl_club_tournament')->withPivot('team_as_1','team_as_4','team_as_5','team_as_6');
}
My club model:
public function tournament(){
return $this->belongsToMany('App\Tournament','tbl_club_tournament')->withPivot('team_as_1','team_as_4','team_as_5','team_as_6');
}
i want to find a club where team_as_1 = 1.
Try doing
$tournament = Tournament::find(1);
$club = $tournament->clubs()->wherePivot('team_as_1','1')->get();
return $club;
With the current approach you're calling method wherePivot on a collection (but that method doesn't exist on the collection class), however by calling the function $tournament->clubs(), that returns a query builder object on which you can call wherePivot()
Edit:
Seems you only need one item, so you should probably do
$club = $tournament->clubs()->wherePivot('team_as_1','1')->first();
Use Below
$tournament = Tournament::find(1);
$clubs = $tournament->clubs()->wherePivot('team_as_1','1')->get();
return $clubs;
return $this->hasManyThrough('App\Club', 'App\Tournament');

Resources