0

I am using Laravel 5. if I have written a function on Model class and takes it's object by laravel eloquent to any view file like cars.blade.php file and now if I call any model function from cars.blade.php

Like Model Class

Car.php

public function totalModels() {
    return App\Models\CarModel::where('id',$this->modelId)->count();
}

Cars.blade.php

<span>Available Models : {{ $car->totalModels() }}</span>

So My Questions are

When this function will call ?
Is this function slow the page ?
Is this a best practice to do it ?
if there is any foreach loop then how will this function will behave for each object ?

Thanks

tereško
  • 58,060
  • 25
  • 98
  • 150
Naveen Roy
  • 85
  • 12
  • This will be just fine to do, however I think you can achieve the same with relations on your models, where you can do something like: {{ $car->Models->count() }} – killstreet May 03 '19 at 07:58
  • What version of Laravel 5 are you using? Can you also show the code for your controller and the rest of the blade file? – Rwd May 03 '19 at 08:04

2 Answers2

2

The method you're searching for is withCount:

Create a relation to App\Models\CarModel in the car model and eager load it with withCount to prevent sending too many queries in the loop and slowing down the page too much:

Car.php

namespace App\Models;

class Car
{
    // ...

    public function models()
    {
        return $this->hasMany('App\Models\CarModel', 'id', 'modelId');
    }

    // ...
}

CarsController.php

namespace App\Http\Controllers;

class CarsController extends Controller
{
    // ...

    public index()
    {
        $cars = App\Models\Car::withCount('models')->get();

        return view('cars', compact('cars'));
    }

    // ...
}

cars.blade.php

@foreach ($cars as $car)
    {{-- ... --}}

    <span>Available Models: {{ $car->models_count }}</span>

    {{-- ... --}}
@endforeach
Dan
  • 5,140
  • 2
  • 15
  • 30
1

Is this a best practice to do it ? You are coupling VIEW part of MVC architecture to the Model itself which is not good practice.

When this function will call?: This will run as soon as laravel templating engine will render that blade.

What will happen: It will make an extra call to the database get all the rows and then perform a collection count() which is much slower than mysql count().

Is this function slow the page ? Yes. Improve the query performance a bit at least:

App\Models\CarModel::select(DB::raw('count(*) as total_cars'))
->where('id',$this->modelId)
->pluck('total_cars');

This query is similar to what happens with withCount() method via a relationship.

If there is any foreach loop then how will this function will behave for each object ? If you are foreaching an object and doing a call to get the count then foreach itteration an extra call to the database will happen similar to N+1 problem

A better way of doing it, check @Dan answer.

Leo
  • 7,274
  • 5
  • 26
  • 48
  • 1
    Actually, his usage of `count` is perfectly fine. Yes, the N+1 problem still occurs with his method but he's not counting over the objects in the returned collection but instead, he's using the aggregate method of the query builder itself which results in a query like this: `SELECT COUNT(*) as aggregate FROM total_models WHERE modelId = :id`. Counting over the collection would be `CarModel::where('id', $this->modelId)->get()->count()`. – Dan May 03 '19 at 08:49
  • @Dan true, just got out of my mind when wrote the question. – Leo May 07 '19 at 07:33