Akmal Arzhang
Akmal Arzhang

Reputation: 367

How to perform calculations in hasMany relationship in Laravel (Best Practices)

I know that there are many great functionalities within Eloquent and relationships in Laravel, however, there are times that we need to perform various calculations based on the relationship data. My main question is what are the best practices that I can perform those calculations.

As an example; I have the following tables;

The relationship order for the given scenario is in the following order: Student -> StudentClass -> StudentExam -> Subject.

Basically, my StudentExams model looks like this:

class StudentExam extends BaseModel
{
    .
    .
    .
    public function studentClass()
    {
        return $this->belongsTo(StudentClass::class, 'st_class_id', 'id');
    }
    
    .
    .
    .
}

And in my StudentClass, I need to perform a basic calculation to get the status and grades of the student in the given class, based on his/her performance from the StudentExam class.

Therefore in my StudentClass model, I created a model like bellow:

class StudentClass extends BaseModel
{
    .
    .
    .
    // Relationship: Student Exams
    public function studentExams()
    {
        return $this->hasMany(StudentExam::class, 'st_class_id', 'id');
    }

    // Calculate Semester Results
    public function semesterResult($total_credits = 0)
    {
        $credits_got = 0;
        $has_mark = 0;
        $status = 'failed';

        // Loop through the marks
        foreach ($this->studentExams as $exam) {
            // If student has a success mark, add credits to credits got
            if (($exam->total_marks ?? 0) >= $exam->success_mark) $credits_got += $exam->subject->credit ?? 0;

            // If there is a mark, increment the has_mark
            if ($exam->mark()) $has_mark++;
        }

        // If count of credits got is equal to or > 50% of the total_credits, assign the status to success
        if ($credits_got >= ($total_credits / 2)) $status = 'passed';

        return [
            'credits_got' => $credits_got,
            'has_mark' => $has_mark,
            'status' => $status
        ];
    }
    .
    .
    .
}

In my blade file inside the students foreach loop, I can basically just call the semesterResult passing the total_credits and I can get the credits_got (total credits with success mark), has_mark (number of subjects that student has mark) and status (passed or failed). Everything is working fine, however, I am imagining a scenario that a class might have 100 student and 10 exams, so more than 1,000 records would be included in these calculations given that I am also accessing subjects relationship to retrieve the credit for the given subject.

For your information, I have decided to add this method in StudentClass model because I will need these results in many pages of my application and perform other calculations based on these. I might also need to expand the return array with other stuff that I might need based on the calculations.

Are there better ways to handle such kind of calculations? Are there ways to handle this without actually loading all those records?

Upvotes: 0

Views: 396

Answers (1)

Snake MAGIC
Snake MAGIC

Reputation: 54

you can call to two model in one relation in laravel with eloqouent like that

return $this->belongsToMany(Model1::class, Model2::class, 'foreign_key_id1', 'foreign_key_id2');

Upvotes: -1

Related Questions