Omranic's avatar

Article: The art of using Repositories in Laravel 5.3

I've just published a new article titled "The art of using Repositories in Laravel 5.3" Hope you find it useful :)

0 likes
22 replies
jekinney's avatar

Nice but still just a wrapper for eloquent? The benefits are a matter of opinion isn't it?

1 like
Omranic's avatar

While Eloquent implementation is available out of the box, it's not limited to it.

I've tried to make sure it's as generic as it could be, so you can implement same pattern for Query Builder, or even different DB or filesystem driver. The concept still the same.

And no, I don't think the benefits are matter of opinion, at least for the caching layer where you can get benefit of caching any result set whatever the query is or the data source :)

Feedback always welcome

MikeHopley's avatar

While it does look like a very good implementation, I'm sceptical of your claim to "save 70% of time, code, and hassle writing boilerplate CRUD, and developing complex caching logic."

I don't understand how your system saves me any time. How can it be easier than just using Eloquent directly?

-- EDIT -- I just realised that you might be comparing "using the package" to "creating your own complete repository implementation". In that case, yes, I'd much rather use your package than try to create something similar myself. So in that sense, it would save me time -- and also it's much higher quality than if I did it myself.

As for caching, I feel the main challenge is automating the cache logic (specifically cache expiry). That's why Russian doll caching is interesting.

Being able to swap out your data source behind the scenes and still get caching? That doesn't seem useful to me, because I can't imagine myself changing data sources. Okay, I suppose I do have some data coming in from other sources such as external APIs, but then I'd typically just "cache" that in the local database anyway.

Having said all that, I recognise that for some bigger projects, this level of abstraction could be useful. I just feel that for the vast majority of projects, it's overkill.

To me, it feels like dumping a huge amount of boilerplate abstraction into my app for intangible benefits. So yes, the benefits are very much a matter of opinion -- at least when you promote them as applying to all projects.

This isn't entirely a knee-jerk reaction, as I did look at your Conventions and practices document. Create an interface for every entity? Yuck. No thanks.

That all sounds very negative, and I didn't really want it too! Bear in mind that I'm not criticising your project, which is possibly the best implementation of repositories that I've seen. :) It's just that repository evangelism leaves a bad taste in my mouth.

martinbean's avatar

I really don’t get why repositories have been all the rage for the past couple of years or so. 90% of the examples and use cases have offered no benefit over a proper use of Eloquent, query scopes, and traits directly.

I’d rather write $events = Event::published()->future()->paginate(); than have to create an event repository interface, then a concrete implementation of that interface (which will just wrap Eloquent calls any way), create a binding in a service provider, and then have to type-hint that interface in my controller’s constructor. (In the case of the published() scope, I would move that to a Publishable trait, that automatically adds the published scope to queries so I don’t have to manually specify it and accidentally show un-published items on the public website).

The only time I’ve found myself using a repository is in my current day job. It’s an application that uses an API, and had raw API calls via Guzzle littered throughout controller actions. This made a good candidate to be re-factored and wrapped up into repositories as the “shape” (URI, parameters, response, etc) of these API calls could change at any time, so needed an abstraction layer between that and controllers.

2 likes
crnkovic's avatar

What's up with people using Repositories lately? Every other post here is regarding repository pattern. If you only use Eloquent, it's useless and you SHOULDN'T do it.

It's past Laravel 4 time...

Regarding the article, I assumed it's going to be some theory behind the repository pattern and how it can be used with PHP (and in this case Laravel). But it's only "how to use" (documentation) that could easily be put into Github readme. It's just wrapper for Eloquent and is delegating Eloquent methods with some caching. Model can do all that.

nate.a.johnson's avatar

@Omranic thanks for posting. I like your repository package. Don't take the comments here too harshly. I've been in this industry around 25 years and best practices come and go and come again. I'm not sure why people in the laravel community think the repository pattern is evil - they here a few prominent people in the community say it's an anti-pattern and then preach it like these people are never wrong and know all. Go to other circles like Java and you will see it used everywhere. I lived in Java for over a decade and then shifted over to laravel about 3 years ago. It's pretty funny how many common practices, patterns, and techniques that have been a staple in the Java world for years are this great new thing that people think were invented in php. I just chuckle to myself and am happy that people feel good re-discovering useful ideas in a new community.

Anyway, again, nice work on your package.

1 like
MikeHopley's avatar

I'm not sure why people in the laravel community think the repository pattern is evil - they here a few prominent people in the community say it's an anti-pattern and then preach it like these people are never wrong and know all.

I think it's generally a reaction against the repository fad of 2013, when everyone and their dog were promoting repositories as a best practice (in the PHP / Laravel community).

Personally I'd like to see the term "best practice" consigned to oblivion. Those two words seem to short-circuit critical thought.

The only problem I have with repositories is that I've never found them useful. But I have very limited experience. I'm sure they are sometimes useful, as Martin mentioned above.

2 likes
nate.a.johnson's avatar

I've been in many camps... used them religiously everywhere and not at all, etc. The camp I am in now, is using them when I need caching or when the database logic gets complex.

I like a simple one-line call to a repository in my controller or service rather than a complicated query/join which is typically followed by some sort or map/filter over the result set.

I also like them when I need to call an external API that I have no control over how it might change in the future. That keeps my code from changing anywhere I need to talk to the API. If the API changes, I can go to the repository, change it there, and be done.

4 likes
MikeHopley's avatar

Yes, one of the difficulties talking about repositories is that they can be used in very different ways. It's only the purist interface-all-the-things way that can be a trap.

I like a simple one-line call to a repository in my controller or service rather than a complicated query/join which is typically followed by some sort or map/filter over the result set.

Yes, I think this is a good use that is appropriate even for small projects.

I also like them when I need to call an external API that I have no control over how it might change in the future. That keeps my code from changing anywhere I need to talk to the API. If the API changes, I can go to the repository, change it there, and be done.

This also seems like a practical use. In fact, I believe I'm already doing that, except that I don't think of these classes as repositories. I think of them as API wrappers like VimeoApi. Funny how much the naming convention can change your perception...

nate.a.johnson's avatar

Yep, naming is important and I agree that a repository is too vague a term. I think a big problem is that people take the gang of four's book and writings as religious text that has to be followed to the letter for design patterns. I don't think that was every their intent.

Omranic's avatar

This also seems like a practical use. In fact, I believe I'm already doing that, except that I don't think of these classes as repositories. I think of them as API wrappers like VimeoApi. Funny how much the naming convention can change your perception...

Totally agree. Just if we can call these things anything other than repositories may be it would be perceived differently :D

Omranic's avatar

Off record, is there any naming recommendations/suggestions/conventions other than Repository for such functionality we've here?

ohffs's avatar

I think they were much more widely applicable when we were all busy embedding direct SQL calls in our code - before there were a lot of good ORM's available. Which is kind of the situation we're in just now with HTTP API calls where, as mentioned above, they're still very useful.

These days, for DB stuff, I don't see a lot of advantages over just using your ORM of choice - coupled with some helper methods which kind of act like a repository would have. So instead of having a 'PostRepository' with a load of methods, I'd just go with an eloquent model and add on any methods that seem a bit nasty. Eg,

class Post extends Eloquent
{
  public function someComplexChainedMethod($param)
  {
    return $this->with('comments')->where('whatever', '=', $param)->where(....)->approved()->get();
  }
}

Wrapping it in a 'repository' seems a bit redundant. I'm quite content doing a call to Post::find($id) rather than $this->postRepo->findById($id) :-) If there are more than a couple of ->'s then I'll think about wrapping it though.

On the 'interface all the things' front I saw a great talk by Sandi Metz (which I can't find now sadly) where she was going through some Java code that used interfaces everywhere and was pointing out that there was inevitably only one actual implementation - it just meant hunting through yet another set of folders for no actual gain. I think for frameworks/libraries they are a lot more useful - but for application code I don't really see the need 99% of the time.

Omranic's avatar

@ohffs OK, what about caching result set of this -complex- query? Will it be easy to do so using only Eloquent? Can you do so for multiple different queries, with different logic without redundancy?

The granular caching thing is the main selling point of this package, and not just the wrapping. I agree that in some simple apps, may be it's better to stick with Eloquent without this layer, but when it comes to complex logic, with long queries, or api calls with data to be cached you'll recognize the need for this solution.

Again, it's not about the Repository Pattern debate, it's more about the functionality it offers including of course the main caching features, regardless it's considered a Repository or not. Naming doesn't matter for me, and if there's more relevant naming I'd be happy to rename it to clear any confusion, but still up until now this is the most relevant up to my knowledge.

2 likes
nate.a.johnson's avatar

By definition, a repository is a place where things are stored. So a cache, a way to access a database, a way to access an API, to me, are all good ways to think of a repository. It's just unfortunate the term has so much negativity connected to it.

2 likes
ohffs's avatar

@Omranic I wasn't really thinking about your package in particular - more the general thrust of the following conversation. You might well be better thinking about a different name for your package to avoid having this conversation every time it comes up - I imagine it'll get quite annoying ;-) Caching is, in my experience anyway, quite application specific so I tend to handle that myself. I've seen applications use caching almost everywhere and then running slower than just hitting the DB :-)

2 likes
nate.a.johnson's avatar

You want to know what a good design pattern / name might be? Facade. A facade is used to wrap a complicated piece(s) of code with a simple interface. That said, Facade is probably not a good name for something in laravel :)

1 like
MikeHopley's avatar

The granular caching thing is the main selling point of this package, and not just the wrapping.

The caching argument is something that I find more appealing.

However, as @ohffs said, I would expect caching to be application-specific. Your package doesn't seem to solve the caching problems I might actually encounter.

In my case, that could definitely be down to inexperience. Maybe one day I will be in a better position to appreciate it.

BartHuis's avatar

Hi @Omranic ,

Thanks for this package :D

It seems like a good way to cache. I came here by a link from an answer on my own question about caching: https://laracasts.com/discuss/channels/eloquent/caching-eloquent-models-since-laravel-5

Apart from the question whether to use repository or not, just about the caching thing itself: Is there no build in cache way in laravel without creating your own cache tags every time? It feels a bit strange when you have a huge framework as laravel that has its own cache systems, to use an external package to make it possible to cache without setting your own cache tags :S

Bart

Omranic's avatar

@BartHuis our please of using this package :)

Regarding your question, sure. Laravel have already a great Caching layer which allows you to cache whatever result set you've, but it still have some shortage, here's what I can recall:

  • Cache tags are not supported when using the file or database cache drivers.
  • Caching results requires you to wrap your result set inside the cache wrappers, and it's not possible to turn on/off cache for single/multiple queries while keeping the code intact without change.

And that's what this package solves right now, it uses Laravel's default caching facilities to make it easier for you to cache simple or complex logic without the need to write more code, or to know the insights of handling cache tags & flushing procedures.. Hope this helps

BartHuis's avatar

thanks, we'll talk about my specific implementation on the other topic ;)

Please or to participate in this conversation.