Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bikerboy's avatar

Best practices services / repositories

Hi guys,

I was just wondering from your experience what is the best practice in the following scenario.

Let's assume that I have an app where users can post stuff. I will have an Eloquent Post model, an EloquentPostRepository and a PostService.

From my controller I would call:

public function create()
{
    $this->postService->create(Input::all());
    return ...
}

public function update($id)
{
    $this->postService->update($id, Input::all());
    return ...
}

public function destroy($id)
{
    return $this->postService->delete($id);
}
  1. Is it a good idea to have all these methods inside a single PostService class? Or would you separate it in PostCreatorService, PostUpdaterService, PostDestroyerService...?
  2. If I decide that a post can have Comments, is it a good practice to have an abstract ResourceService from which I extend my PostService and CommentService? This abstract class would contain the create, update, delete methods.
  3. When I update or delete a post, I need to make sure that the logged in user is the owner of that post. Would you do a check inside the Service or inside the Repository?
  4. When it comes to authentication, would you pass the user from the controller to the service which then passes it to the repository or would you inject the AuthManager class inside the Service and Repository? The reason for this is that if I decide to provide a REST api, I would have to do something like this:
    Auth::onceUsingId($apiUserId);

That's because an API should be stateless.

0 likes
14 replies
JohnRivs's avatar
  1. If you go down the route of Service Classes, yes, it's ok to keep those methods inside the PostService class.

    Now, what you suggest here too, is 'mapping' a certain action that takes places in your application, to a single class. This approach is very similar to the Command Bus, in which case I wouldn't call them PostCreatorService, instead, they would be like orders, like CreatePost, or CreatePostCommand or whatever. Have a look: https://laracasts.com/series/commands-and-domain-events And a preview: https://laracasts.com/lessons/laravel-5-commands

    If you are comfortable with Service Classes and the idea of 1 class per action (or Command Buses) is a bit too much, stick with Service Classes.

  2. Yes, you could do that.. Haven't seen that around too much, but technically it's possible. Me personally, wouldn't do that. Hopefully someone can provide some opinions that aren't gut based.

  3. Inside the Service.

  4. I don't have a strong opinion on this

Mattiman's avatar

No direct answer from me unfortunately, but want to participate in the conversation. For example, no 3:

  1. When I update or delete a post, I need to make sure that the logged in user is the owner of that post. Would you do a check inside the Service or inside the Repository?

is something I have been struggling with as well. In most articles/tutorials you read online about services, repositories and models the examples chosen are very (overly) simple. The Todolist app with "tasks" and "users" or the Blog with "posts" and "comments". Leading to very simple examples in which one form maps neatly to one controller method, maps to one service or repo method, maps to one table. Easy and clear. In real projects you might be dealing with dozens of tables in a relational db, in which one form maps to many tables in a very complex way.

JohnRivs answer to 3. is "Inside the service". Does that mean that all the complexity of mapping the front end intention (through a form) with the back end (the database) and the mismatch/logic between those layers is the responsibility of the service layer? Or could it also be the responsibility of the repository layer? Even leaving the service layer out?

1 like
JohnRivs's avatar

@mattiman What I'm saying is, if he gives me those 2 options for checking the owner, I'd take Service Class.

I would put the "checking if the logged in user is the owner" in a FormRequest object. Laravel 5 makes it really easy. I wouldn't even use Service Classes. I like the Command Bus, mapping an action to a class.

All the logic you mentioned, I'd never put that in a repository, that's not its job at all. Actually getting rid of the Service Class and throwing all that stuff into the repo would greatly break the SRP principle.

And it's not like you have to put everything into the service class, you still have controllers, you still have events.. But if you're gonna base your domain code around Service Classes, that's where you'd put the domain logic.

Mattiman's avatar

@JohnRivs: "All the logic you mentioned, I'd never put that in a repository, that's not its job at all". Why not? If you reduce the job of the repository only to a simple class with CRUD methods for a single table, that repository is in fact just an active record and then you might as well use Eloquent itself instead of putting an extra layer in between which does exactly the same thing.

Maybe to clarify what I mean, is that if you have a form with say 12 fields, mapping to 6 db tables. And inserting that data in the right way in the db means that several checks and queries have to be run against all those tables (or more). For example: "if I want to save field X in table Y, I have to make sure other users than the current user arent' referencing that record, otherwise I have to insert a new record, etc". I would think that the repo could perform those queries, possibly using Eloquent in the case of Laravel, so that the layer above (controller, service) doesn't have to know about the storage (db in this case).

thepsion5's avatar

If you reduce the job of the repository only to a simple class with CRUD methods for a single table, that repository is in fact just an active record and then you might as well use Eloquent itself instead of putting an extra layer in between which does exactly the same thing.

Maybe for right now. But the whole point of using a repository is that you can add to or update that logic in one place and avoid duplicated code. Some applications will never grow beyond one-line eloquent CRUD methods. But I'd rather take the extra hour or two and future-proof them instead of being wrong and then having to make significantly larger changes later on.

I would think that the repo could perform those queries, possibly using Eloquent in the case of Laravel, so that the layer above (controller, service) doesn't have to know about the storage (db in this case).

I would have something like $userRepository->getNumberOfUsersReferencingFoo(Foo $referencedFoo); but then use a service to enforce the business rules that depend on the number of users referencing foo. If you want to use Eloquent relationships you can always specify that as part of the Repository's API, like: $fooRepository->includeReferencingUsers()->findById($fooId);

1 like
JohnRivs's avatar

@mattiman When I said "all that logic" I was referencing your

complexity of mapping the front end intention (through a form) with the back end (the database) and the mismatch/logic between those layers".

I don't know exactly what you mean by that, probably business rules, but doesn't sound to me like something I would put in a repo.

instead of putting an extra layer in between which does exactly the same thing

Here's the key part, you wanna get rid of that layer because you think it does the same thing as a repo when it doesn't. Here's where you could place the business/domain code. The repo, the CRUD aspect is just 1 thing that takes place in that code.

The Service Class could make use of mailers, validators, repos.. according to the needs of the business. If you don't have a place to write all that business/domain logic, what are you going to do? Throwing all that stuff into the controllers, or repos? In my opinion, that's not the place.

I have to make sure other users than the current user arent' referencing that record, otherwise I have to insert a new record

Yes, the repo would perform the queries to insert, update or whatever, but the Service/Domain Layer would be responsible for determining what needs to be done, what business rules to apply and then consume the code, in other words, delegate the tasks.

I think we both agree in something: the service class is not reponsible for the CRUD stuff, the Eloquent. You wouldn't write the code for an actual insertion of a row in a Service Class, instead, it would defer to a repo, it would ask the repo to do "this" if "whatever rule".

1 like
Mattiman's avatar

OK, so maybe if one action in a controller leads to a bunch of actions to be done: - check if user is authorised - do some saving/updating/retrieving data in/to database - send mails - log something You could/would have a Service class managing these four things.

But the question is, that the second point "do some saving/updating/retrieving data in/to database" can be very complex on its own. And what thepsion5 suggests: if you have methods like $userRepository->getNumberOfUsersReferencingFoo(Foo $referencedFoo); inside your Service class, that means that the whole object/relation mapping complexity is put in the Service layer. Or am I misunderstanding the meaning of this method?

JohnRivs's avatar

The repo would handle the interaction with the database, it would expose a public api and then some other class would consume it. That consumer class can be a Service Class, a Command Handler or whatever.

Honestly, I don't quite understand the method proposed by @thepsion5, I'm not familiar with that "technique" or "pattern" (if it's even one of those) so I can't really answer the "that means that the whole object/relation mapping complexity is put in the Service layer" part, since I don't know the purpose and the complexity behind that method.

At the end of the day, there has to be something in the middle. A layer that makes use of the public api of your own classes. A layer in charge for enforcing business rules.

thepsion5's avatar

Yeah, that was just an example of I might implement a business rule like "A user cannot have more than 5 things". One could also do count($user->things) after eager-loading them with the repository but the first technique is more efficient for the DB.

Mattiman's avatar

The repo would handle the interaction with the database, it would expose a public api and then some other class would consume it. That consumer class can be a Service Class, a Command Handler or whatever.

Ok I can agree with that

Honestly, I don't quite understand the method proposed by @thepsion5, I'm not familiar with that "technique" or "pattern" (if it's even one of those) so I can't really answer the "that means that the whole object/relation mapping complexity is put in the Service layer" part, since I don't know the purpose and the complexity behind that method.

What I mean is this: say you have a web app about some sort of Fantasy science fiction game in which users of the system can save Trips they made to Places in Cities in Regions on a different planet. Now User 1 fills in a form with such a Trip. In a well normalised database, there will be a table Regions. One Region contains many cities. So a table Cities with foreign key to Region. One city contains many places. So a table Places with foreign key to Cities. A table trips with foreign keys to users and places tables. So after user 1 fills in the form, data is saved to all tables. Now User 2 comes to the web app and fills in his own Trip. Coincidently, to the same Place (and City and Region). So only a new record is inserted into the Trips table, which references the same Place record as was inserted by user 1.

But now comes User 1 again: he wants to update his Trip data, because he made a spelling mistake. So he wants to change the name of the City or Region. In this case, when the update form is posted, you can't just update the records in the cities and region tables, because that would also change the data User 2 saved. Maybe the correction User 1 makes is not correct or not what User 2 wants. In any way you don't want user 1 to change the data user 2 saved. So you have to check before saving and in case another user is referencing the same data, you have to add a new record in the tables cities and regions.

Anyway, all this checking is being done to deal with the fact that you do not store the objects directly in a relational database. You don't store a complete object "Trip 1" for user 1 and after that a complete object "Trip 2" for User 2. Because of the nature of the relational database system you have to deal with all these tables with foreign key relationships, etc. So my idea is, is that this is something the Repositories themselves have to deal with. The Service layer (or Command) gives all the data to the Repository. The repository (say TripRepository) then deals with all that mess of getting the data right in all those different db tables.

Hope my example makes sense.

JohnRivs's avatar

Ok, I see where you're coming from. Thanks for taking the time to explain your thoughts. This is my final word:

Since I'm not experiencied and mature enough in these kind of architectures, I can't provide stronger opinions for each approach, so I'm gonna go with gut feeling. Seems to me like a matter of preference.

You just stated a perfect example of a business rule, which in my head, feels right to put in a Service Class or a Command Handler. In my opinion, that's the kind of stuff that should be placed in that middle layer, the Domain Layer.

I like to separate goals, that's why I don't like mixing business rules and CRUD operations all under the same class.

Mattiman's avatar

Yes, you are right, it helps to separate goals. The difficulty (for me at least! ;) ) is knowing what are business rules and what are rules which are just there because in this instance I'm storing data in a relational database (an "implementation detail" according to all the gurus). Is it the responsibility of my Service class to deal with the fact that record 10 in table A has a foreign key to record 20 in table B and it can't update that record without messing up the "entity" that user X stored in the system?

Well, thanks for your input. And hope this is still at least partially related and interesting to the original question of topic starter bikerboy.

JohnRivs's avatar

I feel you on that. I find it hard sometimes to determine what kind of rule is that.

In that particular case, I would consider it a business rule to be put in a Service Layer because:

  1. It's not something that happens everytime you want to insert/update something in your application. It takes place in a very specific situation/context. It just so happens to take the shape of a implementation detail.
  2. It's a rule that "comes from the real world". Sounds to me like something the business owner would say:

I don't want a user to be able to change a Place, if some other user is referencing that Place.

My reasoning might not sound too strong :P But I can't find the words.

Mattiman's avatar

Yes maybe you're right and put in that way it is a business rule and belongs in the service layer. Guess it's difficult, might depend on circumstances etc

Please or to participate in this conversation.