Repository pattern and relationships

Published 3 weeks ago by xxRockOnxx

Searched the internet for this but even straight googling of this topic does not give anything related.

I would like the answers to be general programming answer rather than language or framework specific.

So in a repository pattern, how do you do relationships? Eager by default? Query if needed (kind of lazy load)? Have extra methods in repo?

Say StudentRepo which I think is the best example... would you

  • findStudentWithGuardian?
  • findStudentById and findGuardianByStudentId (on GuardianRepo)

First one seems dirty to me. What if you needed a nested relationship?

Eager load by default seems dangerous on some cases kind of 50/50 to be used a solid solution.

Those are the only solution solutions can think of. There might be some answers out there. How do you solve this?

xxRockOnxx

Anyone that can share his idea?

shez1983

take a look at this post which deals with relationships

https://medium.com/@smayzes/how-do-you-work-in-laravel-5a763fe5c5a0

xxRockOnxx

Thanks for the article @shez1983 i might not need doctrine anymore with that technique on the article but it did not really answer my question.

Imagine firing an event and you passed in the Student object and on the listener you might want to send an SMS or Email to a guardian.

Putting eloquent aside because it loads relationship when accessing the relationship that has not been loaded yet, doing student->getGuardian() would be null if it is not eager loaded.

How do you solve that? Do findGuardianByStudentId()? Or make a repo method that will join the relationship called findStudentWithGuardian()?

Cronix
Cronix
3 weeks ago (473,740 XP)

I'd just eager load the relationship on $student, and pass that to the event.

xxRockOnxx

So eager load by default? Thing with repository pattern is you can't eager load on the fly :\

Cronix
Cronix
3 weeks ago (473,740 XP)

No, not by "default." You specifically mentioned an event, and needing the relationship data in that listener. If you have a method that is passing something to an event, why couldn't you load the relationship there before passing it to the event if you know you need it?

xxRockOnxx

because "repository pattern" a.k.a Doctrine2/Hibernate style.

Cronix
Cronix
3 weeks ago (473,740 XP)

I'd argue an event doesn't belong in a repository, either. Only database logic.

$user = $this->repository->update(blah);

event(new SomeUserThing($user->load('relationship')));
xxRockOnxx

I dont fire event in repository but rather passing an object returned by the repository to the event.

$student = $this->repository->findById (1)

event (new FooEvent ($student)

In an event there might be multiple listener, and one of the listener operates on the student's relationship.

Repository only return POJOs/POPOs. It doesn't have any actions such as loading of relationship that's why I'm kinda confused and asked what is the best practice for this.

If you do student->getGuardian() and it wasn't eager loaded it'll be null.

If you guardianRepo->getByStudentId(1) then having getGuardian method and guardians property on the Student entity doesn't make sense anymore including the defining of relationship such as HasMany on it.

Cronix
Cronix
3 weeks ago (473,740 XP)

Yes, I got that, which is why in my example I eager loaded the relationship on $user being passed to the event outside of the repository.

event(new SomeUserThing($user->load('relationship')));
xxRockOnxx

But I can't do that because repo is only returning POPOs.

class User
{
    private $name;

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }
}

That does not have a load method.

https://jeremycurny.com/2016/04/07/php-popo-object/

Cronix
Cronix
3 weeks ago (473,740 XP)

Repository only return POJOs/POPOs

I missed that.

Ok, I really don't have any suggestion then. I use contracts/interfaces for my repos and use an implementation using eloquent. I don't want to give up the power of the ORM. I really don't see any benefit to using POPO as it seems (from your link) it's basically rewriting what the ORM already does natively, but missing tons of really useful features that you'd have to implement yourself.

Please sign in or create an account to participate in this conversation.