Pushing Logic to Custom Collections

This is a technique that I recently found useful. Eloquent models allow you to specify a custom collection object to be returned – which sometimes can be a great place to put some business logic.

While refactoring WhichBeach, I used a custom collection to move some logic from the Beach model to a custom BeachCollection. This allowed me to test the logic in isolation.

Creating the Custom Collection

I created a new class extending Laravel’s Eloquent Collection:

In my model, I instructed Laravel to use my custom collection:

Adding the Logic

Now that I had a place to put my custom code, I could add any number of helper methods to be used throughout my application:

Edit: The above code block has been improved after an excellent suggestion by Joseph Silber in the comments.

This has given me the ability to write more fluent code when dealing with beaches:

Being able to write the line above is a big plus for me – the less cognitive load required to understand the intended output, the better.

Let me know of any good examples of using custom collections in the comments!

Share: Share on FacebookTweet about this on TwitterShare on LinkedIn
  • Joseph Silber

    We’ve had the where method on the collection object for a while now. This can significantly shorten the above methods:

    and the same for the second method:

    • Hi Joseph, you’re right – I’d never used that function before.

      I’ve updated the code to incorporate your suggestion – and I learnt something new. Thanks on both fronts!

    • Yitzchok Willroth

      Why should the caller know that is_major is a boolean (or even that it’s a file/column instead of the product of a calculation, API call, or whatever)? Defining that logic once on the collection (or model) allows your code to be more expressive (expressing intent rather than implementation) and prevents the logic from being repeated (and eventually bifurcated) throughout the codebase.

  • Pingback: Pushing logic to custom collections - murze.be()

  • Is there any reason you put these methods on the Collection class and not as scopes in the Eloquent model? As being in the collection means these filters act on a result set _after_ it’s been fetched from the database, as opposed to filtering the query to fetch specific records.

    • Hi Martin,

      In this particular case I’ve actually refactored *away* from scopes in favour of filtering the result set, for a number of reasons that aren’t very clear in the small example that I chose to share, here are a few of them:

      – I need to perform some business logic on different sets of filtered results
      – My “lowest scoring” logic is expanded to accept a minimum amount of beaches to return, and I prefer describing this sort of logic in PHP rather than mySQL.
      – I have 50 rows in my database – and this isn’t going to change – so the performance hit is negligible.

      Having said that, my instinct was first to use scopes, so I understand your point.

      Thanks for your feedback!

  • Daryl King

    +1 for Scopes instead

  • That simple looking approach opened a whole new world to me and solved a problem I had for some month now 🙂 Thank you for sharing!

  • Ganesh K

    Really great article, saved my day.