Laravel Custom Model Methods

Jeremy Harris picture Jeremy Harris · May 14, 2014 · Viewed 59.5k times · Source

Whenever I add additional logic to Eloquent models, I end up having to make it a static method (i.e. less than ideal) in order to call it from the model's facade. I've tried searching a lot on how to do this the proper way and pretty much all results talk about creating methods that return portions of a Query Builder interface. I'm trying to figure out how to add methods that can return anything and be called using the model's facade.

For example, lets say I have a model called Car and want to get them all:

$cars = Car::all();

Great, except for now, let's say I want to sort the result into a multidimensional array by make so my result may look like this:

$cars = array(
  'Ford' => array(
     'F-150' => '...',
     'Escape' => '...',
  ),
  'Honda' => array(
     'Accord' => '...',
     'Civic' => '...',
  ),
);

Taking that theoretical example, I am tempted to create a method that can be called like:

$cars = Car::getAllSortedByMake();

For a moment, lets forget the terrible method name and the fact that it is tightly coupled to the data structure. If I make a method like this in the model:

public function getAllSortedByMake()
{
   // Process and return resulting array
   return array('...');
}

And finally call it in my controller, I will get this Exception thrown:

Non-static method Car::getAllSortedByMake() should not be called statically, assuming $this from incompatible context

TL;DR: How can I add custom functionality that makes sense to be in the model without making it a static method and call it using the model's facade?


Edit:

This is a theoretical example. Perhaps a rephrase of the question would make more sense. Why are certain non-static methods such as all() or which() available on the facade of an Eloquent model, but not additional methods added into the model? This means that the __call magic method is being used, but how can I make it recognize my own functions in the model?

Probably a better example over the "sorting" is if I needed to run an calculation or algorithm on a piece of data:

$validSPG = Chemical::isValidSpecificGravity(-1.43);

To me, it makes sense for something like that to be in the model as it is domain specific.

Answer

Laurence picture Laurence · May 14, 2014

My question is at more of a fundamental level such as why is all() accessible via the facade?

If you look at the Laravel Core - all() is actually a static function

public static function all($columns = array('*'))

You have two options:

public static function getAllSortedByMake()
{
    return Car::where('....')->get();
}

or

public function scopeGetAllSortedByMake($query)
{
    return $query->where('...')->get();
}

Both will allow you to do

Car::getAllSortedByMake();