Why and how to override Laravel’s built-in auth controller methods

Maybe like me you like to do things the ‘Laravel way’. So let’s say you’re still using the out-of-the-box Auth flow (can anyone recommend an easy, drop-in alternative?). You want to keep that flow without having to rewrite it, but you realise it doesn’t quite do everything you need.

However, as you’ll soon be aware, the logic for the full registration and login processes is quite fragmented. By the time you’ve followed the setup and got everything working, you find that your controllers are inheriting methods from Laravel core, but they don’t have all the functionality you want.

So you need to add to default functionality, but you don’t want to lose what you’re getting for free… and of course, you never want to edit core files!

Overriding should be simple though, right? I mean, we’re in the renaissance era of PHP, a fully OOP language and whatnot.

Let’s look at the getLogin()controller method as an example. It’s pretty simple: just load the right view.

Edit: This article was written around the time of Laravel 5.2. Sometime around the release of Laravel 5.3, this method got renamed to login(). Please bear that in mind and check the comments for the most up to date tips.

But this method is “inherited” from the AuthenticatesAndRegistersUsers trait (Edit: This trait is gone now), which probably inherits from the AuthenticatesUsers trait, which is buried within Laravel’s core.

The thing is this isn’t “inheritance” in the old-fashioned sense of the word — you can’t just override these methods. We can replace (or overwrite) them by creating the same method name in our class, but then we can’t use parent::getLogin() to call the upstream method, benefiting from all of the upstream functionality.

This will undoubtedly fail

This is because traits don’t exist in the traditional single-inheritance stack and don’t operate in the same way as extending classes — they’re more like class partials (or mixins), and any number of them can be combined within a class.

In that context, it’s better not to think of it as inheritance, but more as appropriation; we’re appropriating the methods in the trait (if they don’t already exist in our class!) and placing them in the context of the class that uses them. So they’re not “inherited”; they become part of the definition of the class that uses them.

As we’ve seen, this is problematic. But you’re in luck! There is a workaround.

Thankfully, the traits functionality built into PHP offers a 1920’s-neat workaround that still allows us to call the originally-defined function (the one in the trait), whilst “extending” it with our own functionality. Here’s how:

Here’s the ‘right’ way to do this. See the comments section for advice on doing this in Laravel 5.3+

As you can see, we’re basically aliasing the methods from the trait so that we’re not caught out for redefining methods. And then we can call the original method to still use that functionality. Beautiful. Thanks PHP devs!

It also shows great insight by Taylor and the other Laravel core devs — particularly with the focus on splitting this functionality into traits and method chaining. Without it, my example wouldn’t even be possible. Great work folks!

I’ve learned a lot from looking into the Laravel codebase over the years. It’s taught me some useful practices that have informed my coding style and improved the design of my applications. I highly recommend the occasional deep dive into someone else’s code, it can be very enlightening, especially if they’re a good developer.