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

pmall's avatar

@JeffreyWay I've very interested by a screencast about query objects. Recently for some of my projects I felt the need of something like this without deciding how to approach this.

pmall's avatar

interfacing with services I might one day swap out for another.

It is the role of... Service classes :)

2 likes
JeffreyWay's avatar

I don't think mocking Eloquent models is as easy as you guys think it is.

3 likes
thepsion5's avatar

@pmall The technical name for this is the Specification Pattern. You can also use an interface + composition to create combinations of specifications for more complex logic:

class UserIsActiveSpec implements UserSpec, EloquentSpec
{
    public function satisfiedBy(User $entity)
    {
        return $user->isActive();
    }

    public function applyToQuery(Builder $queryBuilder)
    {
        return $queryBuilder->where('status', User::STATUS_ACTIVE);
    }
}
class UserCanReceiveCreditsSpec extends AbstractCompositeSpec implements UserSpecification
{
    public function __construct(UserIsActiveSpec $spec1, UserHasConfirmedEmail $spec2, UserHasPositiveKarma $spec3)
        {
        $this->add($spec1)
            ->add($spec2)
            ->add($spec3);
        }
}
pmall's avatar

@thepsion5 Thanks ! What is the role of the satisfiedBy method in this context ? I can't figure out how this can help me centralize complex queries in object.

jekinney's avatar

I think if your looking at a repo only for database type swap you are definitely under utilizing the pattern. That is one pro yes, but it does happen but pretty rare to swap a database that isn't implemented from the start and even less to one that eloquent doesn't support. It's not wise to take a MySQL database and swap in mongo. Cost alone will deter most clients.

A lot of repo packages from packagelist over complicate eloquent imo too. But as I said earlier thing of it more as a eloquent code translater to business names. Instead if create it's addnewuser in one line of code in the controller and all the code to add a user is executed in the repo, even in some cases events or dispatch commands. Instead of opening 3 files to update only one.

thepsion5's avatar

@pmall It's so your specification can be used on existing objects or collections and not just during the querying process. Domain services can take an existing subset of Users and filter them without having to call the repository.

thepsion5's avatar

@jekinney I would caution against letting your repositories do too much. If it's creating a user but also dispatching events, doing validation, etc, it makes it harder to decorate them.

For big projects, my repositories are very dumb outside of querying logic. Then, I add a service class that provides validation, other business logic, and syntactic sugar on top of the repositories. For example:

public function createNewClientApp($appName, $appKey = null)
{
    $attributes = [
        'app_name'  => $appName
        'app_key'   =>  $appKey ?: $this->generateRandomAppKey(),
    ];
    $clientApp = new ClientApp($attributes);
    $this->validator->validateModel($clientApp); //configured to throw an exception on failure
    return $this->repository->store($clientApp);
}
2 likes
MarkRedeman's avatar

As more have said I don't think switching an implementation is an advantage of using repositories. For me the benefit of using a repository is that, if implemented correctly, its only responsibility is persistence and as @thepsion5 has shown, when you first design an interface for your repositories, then it is easy to decorate them.

However using repositories in combination with eloquent objects can be quite annoying, since you're basically passing all method calls to your eloquent objects. As a consequence both your repositories and your eloquent classes are responsible for persistence. Ideally each class should have its own responsibility, making it easier for you to choose which object you need to use.

I think Shawn McCool's article on repositories gives a good explanation on how an ideal repository should work.

1 like
Ratty's avatar

@JeffreyWay +1 for not wanting to mock out Eloquent models. With a query object, you can mock out the functionality that is supposed to have which is a far easier task.

Another issue I have with repositories is that in many implementations I have seen, many of the repository class methods return instances of eloquent models. To my mind if an object that is supposed to abstract away the usage of another object returns instances of the object it is supposed to abstract, then you probably need to look at why you're using that pattern.

1 like
jekinney's avatar

@thepsion5

Great view point.

I have read Shaun's article awhile back and basically uses repository to GET data and a command bus to insert or update data. While a great article I am not a fan for utilizing command bus pattern as imo seems hard coded and not as dynamic. Yes you can pass objects and not be as explicit but wouldn't that defeat the point?

mehany's avatar

Great talk. I think building great software requires great architecture. I have been reading on DDD, and I ld say thepsion5 is very inspired by it, @thepsion5 thanks for showing examples.

@JefferyWay thanks for the quick video, if possible, can we see Part two with focus on DDD implementation?

bobbybouwmann's avatar

The main advantage of using a repository is coding to an interface. So it's readable and you don't have to repeat code! :D

1 like
pmall's avatar

Thanks for the explanation @thepsion5 , I will dig deeper into it when I'll have time :)


Also I'd like to mention Analogue ORM is a great data mapper package. Repositories are part of the design and it really makes sense with this architecture. I had a sort of haha moment using repositories when I tried analogue. You should all try :)

santacruz's avatar

This is a great topic and I have been wondering about the exact same question for a while.

I originally used repositories, but slowly moved away from them since - face it - I am not going to ditch Eloquent without also undergoing a major rewrite and maybe switch the framework or language altogether. So the whole idea with switching implementations is not valid for me anymore.

I do like that I can put away complex queries in repositories and that's what I mainly use them for now. I ditched interfaces entirely since I found that they were just sitting there creating another piece of code that has to be maintained. I am really enjoying this discussion to find out how others are utilizing repositories, query scopes etc.

everdaniel's avatar

Hi everyone

I've been following this thread the last few days and reading interesting comments in here, now, I hear some people saying Repositories are an anti-pattern and other saying Repositories are good, with that said, I'm currently working on a project that not only has an UI interface but it also has a REST and a SOAP interface, the same thing a user can do via the UI it also needs to be available via REST and SOAP. Now, if I don't use Repositories, it means that all of the business logic I'm using in my controller would have to be duplicated for the REST and SOAP interfaces as these will have different controllers, what would be the correct or recommended approach for this?

The way I was thinking was that I could use the Repositories to handle all of the business logic on my app (ACL, permissions, data filtering, etc.), and the Repository would be one "talking" to my Eloquent models directly. I wouldn't be returning Eloquent objects when getting data out of Repositories but rather, just arrays.

Would be great to read some comments on this.

Thanks.

1 like
simensen's avatar

I happened to find this post earlier today (completely unrelated to this discussion) and I think it is relevant: http://shawnmc.cool/the-repository-pattern

I had also checked the PoEAA definition this morning:

Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

http://martinfowler.com/eaaCatalog/repository.html

Swapping out the implementation is definitely one of the selling points but that is a byproduct of what the repository pattern is for: providing collection-like access to your domain objects.

I'm guilty of repositorying all the things. That is partly because many of my tools provide a repository as a first-class citizen in those ecosystems. It also makes sense in many of those cases given how they are supposed to be used. Whether they are all actually used that way or not is another story.

Previous

Please or to participate in this conversation.