Search code examples
model-view-controllerormdomain-driven-designddd-repositoriesrepository

DDD/MVC: how to avoid hitting the Repository from the View?


After reading several other questions, it looks like it's not advisable to have an entity class use a Repository. So given these repositories:

class RestaurantRepository {
    public function findAll() { ... }
}

class ReviewRepository {
    public function findByRestaurant(Restaurant $restaurant) { ... }
}

I should not do this in my class:

class Restaurant {
    public function getReviews() {
        // ...
        return $restaurantRepository->findByRestaurant($this);
    }
}

Buts let's say I have this controller, which gives a list of Restaurants to the view:

class IndexController {
    public function indexAction() {
        $restaurants = $restaurantRepository->findAll();
        $this->view->restaurants = $restaurants;
    }
}

What is the "good practice" to get each restaurant's reviews in the view script? I can therefore not do this:

foreach ($this->restaurants as $restaurant) {
    $reviews = $restaurant->getReviews();
}

And I guess that injecting the ReviewRepository in the view is not what we can call a "best practice" as well...

Any comment welcome!


Solution

  • If you need to have the reviews with the restaurant, your restaurant repository should (perhaps, optionally) retrieve these with the restaurant. These would be stored in the class instance as a collection of Reviews along with each Restaurants other data. This will allow you to construct a more efficient query that will get all the data in one go and populate the required objects. The design pattern is called aggregate root.

    class RestaurantRepository {
        public function findAll($withReviews = 0) { ... }
    }
    
    class IndexController {
        public function indexAction() {
            $restaurants = $restaurantRepository->findAll(1);
            $this->view->restaurants = $restaurants;
        }
    }
    
    <?php
    foreach ($this->restaurants as $restaurant) {
        foreach ($restaurant->reviews as $review) {
           ...
        }
    }
    ?>