model-view-controllermodeldecoupling

MVC - where do you put methods relating to multiple instances of your model?


This is a simple question but I can't find a straight answer anywhere. It's the base concepts I'm interested in so I've kept it simple...

Say I have a 'post' model for a blog, I'm going to have to use a getAllPosts method at some point - retrieving all the posts from the database, and instantiating a Post object for each so I can display a list of them

If a User owned the Posts then knowing where to put this code would be easy - you'd put a getPosts method on the User model and it would return posts belonging to the user.

The question is: Where do you put methods which handle multiple instances of a Model which aren't owned by anything else in the system?

I've considered these options, and listed my concerns:

  1. Just interact with the database from the index method of a PostController. Surely this can't be right because my Controller shouldn't know about the database, I want them decoupled so that future changes won't be hard to implement

  2. Put a getAll method on the Post model as a static method so that you don't need a Post instance to call it. I've read that static methods make things hard to test and that this is against the principles of OOP

  3. Create a PostRepository with a getAllPosts method. This is my current preferred option but having read up about the repository pattern - with its links to unit of work etc. - it feels like overkill. It would also implement similar methods to those I think I'm supposed to have on the Post model, like update and delete

  4. Create a PostCollection class which has responsibility for anything relating to many Posts, and leave the Post class for anything related to a single Post. This is ok, but I haven't seen any mention of it elsewhere

  5. Create a pointless 'owner' of the posts, like a User or Admin class, of which there is only 1 instance, and it simply houses a getUserPosts method

What's the simplest way to solve this?


Solution

  • Option #3 is the best one, and it's preferred to create Unit of Work pattern in case there is transactional operations.

    Another option is to create a service layer (ManagePostsService) which may be used as a DomainService that works with multiple entities, this service will invoke the repository or unit of work, see Domain-Driven Design.

    Bear in mind, that in all cases it's not preferred to communicate with data sources e.g.database from Domain Entities (User, Post), these are independent and should only contain their natural behavior through encapsulation.

    You may find these architectures helpful:Clean Architecture, The Onion Architecture, Hexagonal architecture and Ports & Adapters Architecture