Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

FareedR's avatar

How to calculate in Model

I have model of User and Rating . i need to calculate user rating based on what they get from customer rate . how can i do it ? should i make calculation in User model or Rating model ?

protected $appends = ['star']
0 likes
31 replies
nolros's avatar

@fareedr assuming you have a DB column called star with some value then use Laravel get mutation.

https://laracasts.com/discuss/channels/laravel/how-to-calculate-in-model

To define an accessor, create a getFooAttribute method on your model where Foo is the "studly" cased name of the column you wish to access.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Get the user's first name.
     *
     * @param  string  $value
     * @return string
     */
    public function getStarAttribute($value)
    {
        return // whatever calculation you need to do. $value will be the value form the DB column.
    }
}

FareedR's avatar

Im so clueless about it , can you elaborate more about it ? Do i need to do like this for calculation?

//ratings
id | rater_id | user_id | rating | deal_id
1   1           2       3           1
1   1           2       4           2
1   1           2       5           3
1   1           2       1           4
1   1           2       2           5


// calculation 

$rating = Rating::where('user_id',$this->id)->get();
$totalDeal = $rating->count();
$totalRating = $rating->sum('rating');
$star = 5 

$ratingPercent = $totalRating / $totalDeal * ($star / 100) )

if($ratingPercent >= 100 ){
    $star = 5
}else if ( $ratingPercent >= 80){
    $star = 4 
}else if ( $ratingPercent >= 60){
    $star = 3
}else if ( $ratingPercent >= 40){
    $star = 2
}else if ( $ratingPercent >= 20){
    $star = 1
}else {
    $star = 0
}
return $star 
 

Sinnbeck's avatar

There is a ->avg('rating') method instead of ->sum('rating')

FareedR's avatar

@sinnbeck if im using avg , which part do i need to change ? can you show me plus , am i doing it correct ? first time using model for calculation

Sinnbeck's avatar
$ratingAvg = Rating::where('user_id',$this->id)->average('rating');
$star = ceil($ratingAvg);
FareedR's avatar

@sinnbeck my final code is here? am i correct ?

    $ratingAvg = Rating::where('user_id',$this->id)->avg('rating');
        $star = ceil($ratingAvg) ;
        
        return $star;
Sinnbeck's avatar

That should work yes :) You can shorten it a bit though

$ratingAvg = Rating::where('user_id',$this->id)->avg('rating');
return ceil($ratingAvg) ;
Sinnbeck's avatar

Oh wait I just noticed that 4.9 should be 4 in your example? Is that correct? If so change ceil() to floor() :) Personally I would probably prefer to have half stars and round to nearest like this

round($ratingAvg * 2) / 2;
FareedR's avatar
FareedR
OP
Best Answer
Level 3

@sinnbeck can i recap what i understand with you ?

//steps
1. table user must have "star" attribute
2. make a relation between Model User and Model Rating 
// User.php
 public function ratings()
    {
        return $this->hasMany(Rating::class);
    }
// Rating.php
public function user()
    {
        return $this->belongsTo(User::class);
    }
3. make a function getFooAttribute() and inside it can make calculation
public function getStarAttribute()
    {
        $ratingAvg = Rating::where('user_id',$this->id)->avg('rating');
        return ceil($ratingAvg);
    }
4. return ceil($ratingAvg) will define as star in table user .
Sinnbeck's avatar

In your provided example you dont use the relation at all, but instead just manually get ratings :)

FareedR's avatar

if im using relation i need to change like this ? am i right ?

public function getStarAttribute()
{
    $ratingAvg = $this->id->ratings->avg('rating');
    return ceil($ratingAvg);
}
Sinnbeck's avatar
public function getStarAttribute()
{
    $ratingAvg = $this->ratings()->avg('rating');
    return ceil($ratingAvg); //or floor. Look at my previous post!
}
FareedR's avatar

thankyou a lot @sinnbeck , now i understand using getFooAttribute . thankyou for your time and knowledge.

Sinnbeck's avatar

Any time. Always happy to help :)

1 like
FareedR's avatar

@sinnbeck btw im getting error :( i forgot that my model User using uuid . so error come out like this. do you know how to fix it ?

message: "Call to a member function ratings() on string"
FareedR's avatar

this one is related for display star to FrontEnd , im using JWT + React js

//User.php
protected $fillable = [
        'username', 'name', 'email', 'password','status','star'
    ];
protected $hidden = [
        'password', 'remember_token', 'wallet'
    ];
protected $appends = ['wallet_balance','star'];

public function ratings()
    {
        return $this->hasMany(Rating::class);
    }
public function getStarAttribute()
    {
        $ratingAvg = $this->id->ratings()->avg('rating');
        return round($ratingAvg);
    }

// API Controller .
    $user =  User::with('detail')->where('email', $request->get('email'))->get();
        return response()->json([
            'user'  => $user,
            'token' => $token,
        ],200);
Sinnbeck's avatar

You cannot get ratings on an id (integer or string). It should be on $this

public function getStarAttribute()
    {
        $ratingAvg = $this->ratings()->avg('rating');
        return round($ratingAvg);
    }
FareedR's avatar

okay . silly me for small mistake . i try to rate person A , but star doesn't update .

// this logic will fire if person B rate person A
$rating = new Rating ([
                'rater_id' => $user_id,
                'user_id' => $deal->post->user_id,
                'post_id' => $deal->post->id,
                'rating' => $request->get('rating'),
                'comment' => $request->get('comment')
            ],201);

table ratings
id | rater_id | user_id | rating | comment |
1   person B  person A    2     empty 
cyprous's avatar

Slightly offtopic - how did you (or how do people) come across this algorithms ? I can't remember having it at school. But the same principle applies to if you wanted to have quarters - simply round($ratingAvg * 4) / 4 ;

Sinnbeck's avatar

Are you trying to create a new record in the database?

$rating = (new Rating)->create([
                'rater_id' => $user_id,
                'user_id' => $deal->post->user_id,
                'post_id' => $deal->post->id,
                'rating' => $request->get('rating'),
                'comment' => $request->get('comment')
            ]);
FareedR's avatar

yup .. its like grab rating system .. passenger will rate driver, backend will process the new rating based on record in database ( based on what i know about grab ) system will update new star .

Person A rate Person B System will update and show new rating

Sinnbeck's avatar

@cyprous I think some people just used basic math. 2.4 * 2 would be 4.8 (and rounded 5). This would the be halfed to the correct value. If I had come up with the formula myself I would probably have worked my way backwards (find a number that gives me the correct value if divided/squared etc by another value)

Sinnbeck's avatar

@fareedr Did you notice my change in your code? You code just builds a Rating and fills it with data, but doesnt save it to the database. You can either use create() like i did or save() on the created model :)

FareedR's avatar

my mistake. i already put it "$rating->save();" . but still no change in database for attribute ('star') . but when i console.log star . it appears '2' .

Sinnbeck's avatar

So it doesn't add a new entry in the database? Try using my syntax with create

FareedR's avatar

it does add a new entry in the database , but for attribute ('star') doesn't update .

// table ratings
id | rater_id | user_id | rating |
1   1       2           2
// table users
id | star
2   2

but for table users still 0 . supposedly after rater rate user_id 2 , it should update on table users ('star')

Sinnbeck's avatar

Oh it doesnt update it.. The getStartAttribute gets the live data from the ratings table. No need to column :)

FareedR's avatar

so meaning , i dont have to put star in my table ? just appends ?

Sinnbeck's avatar

Yes. If you do $user->star it will get it for you automatically 😊

Next

Please or to participate in this conversation.