How to decouple eloquent from the service layer? How to decouple eloquent from the service layer? laravel laravel

How to decouple eloquent from the service layer?


The easy way:

public function assignToAuthor($postId, $authorId) {    $post = $this->find($postId); // or whatever method you use to find by id    $post->author_id = $authorId;}

Now, the above implies that you know the foreign key author_id of the relation. In order to abstract it just a bit, use this:

public function assignToAuthor($postId, $authorId) {    $post = $this->find($postId);    $foreignKey = $post->author()->getForeignKey();    $post->{$foreignKey} = $authorId;}

Mind, that you still need to save the $post model, but I suppose you already know that.


Depending on your implementation of the simple, immutable, data object that you use, you could also allow passing the objects instead of raw ids. Something between the lines:

public function assignToAuthor($postId, $authorId) {    if ($postId instanceof YourDataOject) {       $postId = $postId->getId();    }    if ($authorId instanceof YourDataOject) {       $authorId = $authorId->getId();    }    // ...}


What I've done in the past that has brought some sanity to this situation for me was do things similar to what you are doing in your second associate method and prefix the repository with Eloquent so in the event I use something besides Eloquent, I just create a new implementation of the repository.

So in this case, I'd end up with class EloquentUserRepository implements UserInterface. I usually end up with some public methods which take and return only primitives and possibly some private methods which would be coupled to Eloquent so what I end up doing then is dropping those public methods into a AbstractUserRepository, or a trait if it makes more sense, to keep the code DRY.


It really depends on the situation, I had many thoughts on those actions as well on my repositories.

What I would suggest is to simply not use the "associate" function, you can simply do:

$post->user_id = $userID;$post->save();

** of course you need to make sure that the user with that id exists.

A) You can do it outside with a special service for "associatingUser"B) You can do it like you did with using the UserRepositoryInterface,I see no problem adding the interface as a dependency.

Option A:

class AssociateUserToPost {private $userRepo;private $postRepo;public function __construct(UserRepoInterface $userRepo, PostRepoInterface $postRepo) {    $this->userRepo = $userRepo;    $this->postRepo = $postRepo;}public function associate($userId, $postId) {    $user = $this->userRepo->getUser($userId);    if ( ! $user )        throw new UserNotExistException();    $post = $this->postRepo->getPost($postId);    if ( ! $post )        throw new PostNotExistException();    $this->postRepo->AttachUserToPost($postId, $userId);}}

option B (quite the same, code just sits in different places)

class PostRepository implements PostRepoInterface {private $userRepo;public function __construct(UserRepoInterface $userRepo) {    $this->userRepo = $userRepo;}public function associate($userId, $postId) {    $user = $this->userRepo->getUser($userId);    if ( ! $user )        throw new UserNotExistException();    $post = $this->getPost($postId);    if ( ! $post )        throw new PostNotExistException();    $this->AttachUserToPost($postId, $userId);}}