How to define the following relationship - laravel

I am developing a p2p app with laravel. I have two tables namely users and loans.
Firstly, a user can be a lender or borrower.
Then users can have multiple loans and multiple loans belong to multiple users.
Also, a loan can belong to one borrower and also to multiple lenders.
To explain it further, the loan record will be created by the borrower(or the user). Then the system will distribute the loan and assign it to multiple lenders.
Example: Let's say, one borrower wants a loan of 3000. Our system will distribute the loan as 2000 and 1000 (or 1500 and 1500, or 2500 and 500, etc.). Then assign it to two lenders.
Now it could be more lenders or bigger amounts.
So how can I define something like this with laravel eloquent?
Here's what I thought of till now.
Users and loans will have a many-to-many relationship.
Loans table will have a lender_data column which will be an array that contains lender_id and amount.
But I can't really figure out a way to fetch all the loans of a single lender. So how can I do that?
That's a lot of words. Thank you for reading.

First of all, this question is quite vague and doesn't show any code which I think all questions should. Its harder to answer questions like this that don't necessarily have predefined answers.
Personally, I'd look into intermediate table models:
https://laravel.com/docs/8.x/eloquent-relationships#defining-custom-intermediate-table-models
That way you can have a Lenders table, a Loan table, a Users table, and this "in between" table that could be something like a LoanAmount table. The LoanAmount table is mostly a pivot table (allowing the many to many relationship between Lenders and Loans), however it can also store data like:
loan_id lender_id amount
1 1 1000
1 2 1000
Then the loan table would just be
user_id amount
1 2000
So a User can have many Loans, but it's the Loans that can have many LoanAmounts.

I'd go with next:
class User extends Model
{
public function loans()
{
return $this->belongsToMany(Loan::class)->using(LoanUser::class)->withPivot(['amount', 'percentage']);
}
}
class Loan extends Model
{
public function users()
{
return $this->belongsToMany(User::class)->using(LoanUser::class)->withPivot(['amount', 'percentage']);
}
}
class LoanUser extends Pivot
{
protected $with = [
'landers',
];
public function landers()
{
return $this->belongsToMany(Lander::class)->withPivot(['percentage']);
}
}
class Lander extends Model
{
public function loanUsers()
{
return $this->belongsToMany(LoanUser::class)->withPivot(['percentage']);
}
}
In loan_user pivot table you should make field called percentage that will go to user from full amount. In second pivot between LoanUser and Lander lander_loan_user you should also need percentage field that you would assign to each lander_loan_user relation. It would be second pivot table data.
After you save loan_user data, you would need to attach landers to first pivot model (second pivot table doesn't require pivot model per description). Since there are eager loaded landers to pivot model, when you query some user and their loan
$user = User::where(['loan.amount' => 3000])->first();
$user->pivot->landers;// will get you related landers
You already have full amount in first pivot table and with percentage from same table you know how much user (borrower) gets and in pivot's relation to landers table you will know how much each lander gets from that loan.
It is like "T" relation where upper ends of 't' letter are Loan and User, that crossroad is LoanUser pivot and lower end (base) of the letter 't' are landers.
To avoid hard time as much as possible, keep up with eloquent's convention (check good practice here) and for example, instead of borrower_id call that loan_id, also pivot table to be loan_user (pay attention on pivot singular).
This was written from top of head and not tested but this is the idea/way how task can/should be finished.

Related

How can I sum two fields from two different tables in laravel in api?

I want to add the price field from the enginestable with the buying_price field from the vehicles table where we have several purchases of vehicles and several engines and I want to sum the final cost for each purchases
I have the following tables
I want to add the price field from the enginestable with the buying_price field from the vehicles table where we have several purchases of vehicles and several engines and I want to sum the final cost for each purchases
I wrote the following command, but I get an error:
$purchase=DB::table('purchases')
->leftjoin('vehicles', 'vehicles.purchase_id', '=','purchases.id')
->leftjoin('engines', 'engines.purchase_id','=','purchases.id')
->leftjoin('suppliers', 'suppliers.id', '=', 'purchases.supplier_id')
->select('purchases.id','suppliers.name','purchases.purchase_date','vehicles.buying_price','engines.price')->get()
->collect('vehicles.buying_price','engines.price')->sum();
return $purchase
this is the the error:
In short, how do I add two values ​​from two different tables and show them in another table?
you can call back of sum instead of collect.
For example Try this:-
$purchase=DB::table('purchases')
->leftjoin('vehicles', 'vehicles.purchase_id', '=','purchases.id')
->leftjoin('engines', 'engines.purchase_id','=','purchases.id')
->leftjoin('suppliers', 'suppliers.id', '=', 'purchases.supplier_id')
->select('purchases.id','suppliers.name','purchases.purchase_date','vehicles.buying_price','engines.price')->get()
->sum(function($data){
return $data->buying_price + $data->price;
});

Laravel Eloquent - Sum of a column values for multiple records from related data

I have the following models: User, Order, OrderPayment
whereby each user has many orders, and each order has many order payments.
The orderPayment model has the attribute "total_paid"
I would like to get the sum of the user's total paid for all his orders.
eg:
user has 3 orders.
the first order has the two following payment records: 5$ and 4$.
the second order has one payment of 10$
the third order has two payment records of 1$ and 4$
the total sum i want is 5 + 4+ 10+ 1+ 4 = 24$.
I have tried the following but it's not working at all :
$user->orders->orderpayment->sum('total_paid');
but i get this error
Property [orderPayment] does not exist on this collection instance
Since you want to sum values from the OrderPayment model, it is easier to start there. Try to write it like this:
OrderPayment::whereHas('order.user', function($query) use ($userId) {
$query->whereId($userId);
})->sum('total_paid');
Make sure all the relations are defined well.
Try:
$user->orders->orderpayment()->sum('total_paid');

Laravel hasOne Relation 2 columns

I have 2 Models first one is(Plan) and the second is (PlanPrice)
I have this columns in table plan_price:
$table->float('price')->comment('Price for one month or one year depends
on country code');
$table->string('country_code')->default('EG');
What I want is to get a plan with price depends on the user country code.
I think you should do this:
return $this->hasOne(PlanPrice::class, 'plan_id')->where('country_code',
$what_ever_your_code_is);

Laravel eloquent deep count with relationship

I want to get count from deep table and the relationship is A->B->C->D and I want total count of D.
For example;
A: 3 Boss
B: 5 Managers
C: 8 Human Resources
D: 25 Employees
Imagine that every boss has managers and every manager has human resources and also every human resource has employees. How can I get total count every boss's employees' with Laravel. (For instance, first boss has 7 employees at the end.) Should I have to write hard sql code like joins or can I handle with eloquent?
By the way, my tables:
A: id, name
B: id, name
A and B has pivot table.
C: id, name
B and C has pivot table
D: id, name
C and D has pivot table
So far, I tried to:
$a = Boss::with("a.b.c.d")->where("id", 10)->first();
dd($a->b->c->d->count());
It just gave me d's count but I want to all of a's.
There is no native relationship for this case.
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class A extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function d() {
return $this->hasManyDeep(D::class, ['a_b', B::class, 'b_c', C::class, 'c_d']);
}
}
$count = A::find($id)->d()->count();

Sort by average value of an one to many related table column

I have 2 models; Post and Rating
The Rating model contains an amount column which specifies how high something has been rated. This is based on 5 star rating so the amount can be a value from 1-5
The Post model has a one to many relation with the rating model and function called Ratings that returns the hasMany.
I'd like to get the 5 latest posts based on the average rating. For the average rating I've created a function that can be seen below
Note: the plural(Ratings) returns the hasMany relation where as the singular(Rating) returns a value which is the average rating
public function Rating(){
return floor($this->Ratings()->avg('rating'));
}
Is it possible to retrieve posts ordered by the avg rating using the Eloquent QueryBuilder?
Currently I'm retrieving all posts and then using the sortBy method on the collection object in order get the ones with the highest average rating. The way I'm doing this can be seen below.
$posts = Post::all();
$posts = $posts->sortByDesc(function ($post, $key) {
return $post->Rating();
});
Now if I'd only want to show 5 I still have to retrieve and sort everything which doesn't seem very resource friendly(In my eyes. I don't have any proof of this or say it is true).
So my question is the following: Is this doable using Eloquent instead of sorting the FULL collection.
Sub question: Will doing this with Eloquent instead of sorting the collection have any impact on efficiency?
You may use query builder
DB::table('post')
->select('post.id', 'AVG(rating.amount)')
->join('rating', 'post.id', '=', 'rating.post_id')
->groupBy('post.id')
->orderByRaw('AVG(rating.amount) DESC');

Resources