For years now I\'ve been reimplementing the same code over and over (with evolution) without finding some method of cleanly, and efficiently, abstracting it out.
The pat
I think you're overcomplicating things.
I've worked on a project using Doctrine 2 which has quite a lot of entities, different uses for them, various services, custom repositories etc. and I've found something like this works rather well (for me anyway)..
Firstly, I don't generally do queries in services. Doctrine 2 provides the EntityRepository and the option of subclassing it for each entity for this exact purpose.
UserRepository.findByNameStartsWith
and things like that.So in other words...
Use services to combine "transactions" behind a simple interface you can use from your controllers or test easily with unit tests.
For example, let's say your users can add friends. Whenever a user friends someone else, an email is dispatched to the other person to notify. This is something you would have in your service.
Your service would (for example) include a method addNewFriend
which takes two users. Then, it could use a repository to query for some data, update the users' friend arrays, and call some other class which then sends the email.
You can use the entitymanager in your services for getting repository classes or persisting entities.
Lastly you should try to put your business logic that is specific to an entity directly into the entity class.
A simple example for this case could be that maybe the email sending in the above scenario uses some sort of a greeting.. "Hello Mr. Anderson", or "Hello Ms. Anderson".
So for example you would need some logic to determine the appropriate greeting. This is something you could have in the entity class - For example, getGreeting
or something, which could then take into account the user's gender and nationality and return something based on that. (assuming gender and nationality would be stored in the database, but not the greeting itself - the greeting would be calculated by the function's logic)
I should probably also point out that the entities should generally not know of either the entitymanager or the repositories. If the logic requires either of these, it probably doesn't belong into the entity class itself.
I have found the approach I've detailed here works rather well. It's maintainable because it generally is quite "obvious" to what things do, it doesn't depend on complicated querying behavior, and because things are split clearly into different "areas" (repos, services, entities) it's quite straightforward to unit test as well.