Get specific field from one to many table relationship with laravel eloquent? - laravel

I have table like this following image:
so, user have many balance_transactions and last inserted balance_transactions record will be user account balance. my question, how to make user model have property account_balance with value last inserted total in balance_transactions table
I was tried using something like this in user model
public function balance {
return $this->hasMany(App\BalanceTransaction::class);
}
public function account_balance {
return $this->balance()->orderBy('id', 'DESC')->limit(1);
}
And I get the data like this
$user = User::where('id', 1)->with('account_balance')->first();
return response()->json($user);
and the result look like this folowing json:
{
"id": 1,
"username": "john0131",
"full_name": "john doe",
"email": john#test.com,
"account_balance": [
{
"id": 234,
"user_id": 1,
"total": 7850
"added_value": 50
"created_date": "2020-02-28 12:18:18"
}
]
}
but what I want, the return should be like this following json:
{
"id": 1,
"username": "john0131",
"full_name": "john doe",
"email": "john#test.com",
"account_balance": 7850
}
my question, how to make something like that in laravel eloquent proper way? so I can get account_balance data only with simple code like $user = user::find(1);.
Thanks in advance

One way to tackle this is, you could use laravel Accessors
So in your User model you can create a method as follows
/**
* Get the user's balance.
*
* #return float
*/
public function getAccountBalanceAttribute()
{
return $this->balance->last()->total;
}
then wherever you want to use it you can use it by:
$user->account_balance;

I would suggest loading only one row from your transaction table with an eye on performance. Additionally you can append the value of the accessor to the serialised output of the model (e.g. __toArray()) and return the acutal value only if the relationship has already been loaded.
class User extends Authenticatable
{
protected $appends = ['account_balance'];
public function balance()
{
return $this->hasMany(App\BalanceTransaction::class);
}
public function latestBalance()
{
return $this
->hasOne(App\BalanceTransaction::class)
->latest();
}
public function getAcountBalanceAttribute()
{
if (! $this->relationLoaded('latestBalance')) {
return null;
}
return $this->latestBalance->total;
}
}

Related

How to appending a column db result with relation and some logic laravel

I have a problem here, I want to add one column from the result of the relation, namely the percentage column, this column is the result of pagebook / pageread * 100
this is my result db what I want
"id": 2,
"id_book": 2,
"id_user": 2,
"pageread": 120,
"books": {
"id": 2,
"pagebook":125
}
"percentage":96
this is my code in controller
$book= Read::with('books.authors')->where('id_user',$user->id)->get();
and this my code in model
public function books()
{
return $this->belongsTo(Book::class,'id_book','id');
}
you can do it in the model:
class YourModel ...{
protected $appends = ['percentage'];
public function getPercentageAttribute()
{
return /* the calculation that you need */
}
}
protected $appends = ['percentage'];
public function getPercentageAttribute()
{
$read= $this->pageread;
$book= $this->books->pagebook
return $read/$book*100
}

Laravel querying polymorphic relationships with nested many to many items

I have 4 tables with the following relationships:
class Note extends Model
{
public function noteable() {
return $this->morphTo();
}
}
class Expense extends Model
{
public function notes()
{
return $this->morphMany(Note::class, 'noteable');
}
}
class Review extends Model
{
public function notes()
{
return $this->morphMany(Note::class, 'noteable');
}
public function repairs()
{
return $this->belongsToMany(Repair::class);
}
}
class Repair extends Model
{
public function reviews()
{
return $this->belongsToMany(Review::class);
}
}
as you can see Note is in the relationship one to many polymorphic and Reviews is in many to many with Repairs.
I would like to take all Notes that Reviews also has Repairs. How do I do such an operation?
Following the documentation I am trying to do something like this:
$notes = App\Note::query()
->with(['noteable' => function (MorphTo $morphTo) {
$morphTo->morphWith([
Review::class => ['repairs']
]);
}])->get();
I would like to my query should return something like:
[
{
"id": 11,
"noteable_id": 4,
"noteable_type": "App\\Expense",
"noteable": {
"id": 4,
"name": "Expense",
"category": "general"
}
},
{
"id": 13,
"noteable_id": 5,
"noteable_type": "App\\Review",
"noteable": {
"id": 5,
"name": "Review 5",
"mileage": 120000,
"repairs": [..., ...] //what I need
}
}
]
To load your Repair models for your Reviews, try this:
if ($type == 'App\Review') {
$query->with('repairs')
}
EDIT :
I've just done some more reading on whereHasMorph and I think i was mistaken as to what it is doing. It is at it's most basic level a where clause, designed to constrain the results of the query. What I have suggested above would the the equivalent of joining something to a MySQL subquery. Not what we want!
What you want to do is actually under
Nested Eager Loading morphTo Relationships
(https://laravel.com/docs/6.x/eloquent-relationships#querying-polymorphic-relationships)

Laravel - getting a value from a relationship's attributes as an attribute of the current model

I have 2 models: Car and Condition
Car and Condition have a 1 to 1 polymorphic relationship. Condition gets joined onto Car:
class Car extends Model
{
// ...
public function condition()
{
return $this->morphOne(Condition::class, 'carable');
}
}
class Condition extends Model
{
// ...
public function carable()
{
return $this->morphTo()
}
}
This returns the following structure:
{ // car
"id": 1,
"condition": {
"age": "1 year",
"serviced": "yes"
}
}
I want to also return the age attribute on the car's level, i.e.
{ // car
"id": 1,
"age": "1 year",
"condition": {
"age": "1 year",
"serviced": "yes"
}
}
I want to do this by getting the condition->age attribute inside the car model. I've tried setting up the following in the Car class:
protected $appends = ["age"];
protected function getAgeAttribute()
{
return $this->getFinancialAttribute()->getAgeAttribute();
}
as well as some other variations thereof, with no success. Is there any way for me to do this elegantly?
You can try to add this code to your Car model:
protected $appends = ['age'];
protected function getAgeAttribute()
{
return $this->condition->age;
}
But be sure to eager load condition with your Car model to avoid the N + 1 query problem.
$cars = Car::with('condition')->get();
In your case you can eager load by default adding this line to your Car model:
protected $with = ['condition'];
BTW your relationship on the Car model should be like this:
public function condition()
{
return $this->morphOne(Condition::class, 'carable');
}

How to attach last records in relation with eloquent in Laravel

I have a group table, messages table, and users table.
The messages table belongs to one user and morphTo a group.
the groups table belongs to one user and morphMany messages.
I want to get all groups related to one user with the last messages "only the last message".
`users Model`
public function messages(){
return $this->hasMany('App\Message');
}
public function groups(){
return $this->belongsToMany('App\Group', 'group_user');
}
`Groups Model`
public function user(){
return $this->belongsTo('App\User');
}
public function messages(){
return $this->morphMany('App\Message', 'messagable');
}
`messages model`
public function user(){
return $this->belongsTo('App\User');
}
public function messagable(){
return $this->morphTo();
}
I want the result to be like that:
{
"id": 23,
"user_id": 2,
"name": "Group1",
"description": "5656",
"img": "images/1524958644.png",
"created_at": "2018-04-28 23:37:24",
"updated_at": "2018-04-28 23:37:24",
"last_messages":{
"id": 292,
"user_id": 1,
"messagable_type": "App\\Group",
"messagable_id": 23,
"message": "hi",
"created_at": "2018-04-29 07:48:55",
"updated_at": "2018-04-29 07:48:55"
}
}
I would use an accessor for this.
eg. In your Groups model
protected $appends = ['last_message'];
public function getLastMessageAttribute()
{
return $this->messages->orderBy('id', 'desc')->first();
}
You could also use orderBy with created_at instead of id
You can then retrieve it by using this as an example:
Group::where('user_id',2)->first()->last_message;

Laravel: using "morphMany" and joining another table?

I'm new to laravel too. I have a question about Eloquent:
table structures:
User: id, username
Posts: id, user_id, content
Likes: id, likeable_type, likeable_id, user_id
(Because of I want to make 'Likes' table extendable for comments, too.)
Models\Likes.php
class Likes extends Model
public function likeable()
{
return $this->morphTo();
}
Models\Post.php
class Posts extends Model
public function likes()
{
return $this->morphMany("\App\Models\Likes","likeable");
}
And when I call
$post = Posts::find($id)->likes()->get();
in my controllers, it will return like this:
"likes": [
{
"id": 1,
"likeable_type": "App\\Models\\Posts",
"likeable_id": 1,
"user_id": 1,
},
{
"id": 2,
"likeable_type": "App\\Models\\Posts",
"likeable_id": 1,
"user_id": 1,
}]
But how can I get results like this:
"likes": [
{
"id": 1,
"likeable_type": "App\\Models\\Posts",
"likeable_id": 1,
"user_id": 1,
"username":"chenhui",//join user on user.id = likes.user_id
}...
Many thanks and sorry for my poor english!
I believe in your Likes model you need
class Likes extends Model
public function user()
{
return $this->belongsTo('App\Models\User');
}
and then it should be:
$post = Posts::find($id)->likes()->with('user')->get();

Resources