I have my own hand-rolled PHP MVC framework for some projects that I’m working on. When I first created the framework, it was in the context of building an admin CMS. Therefore, there was a very nice one-to-one relationship between model, view, and controller. You have a single row in the DB, which maps to a single model. The controller loads the model and passes it to the view to be rendered (such as into an edit form). Nice, clean, and easy.
However, now that I’m working on the front end of the site, things are getting sticky. A page isn’t always a view of a single model. It might be a user directory listing with 20 users (each a User model). Furthermore, there might be metadata about the request, such as pagination (current page, total pages, number of results) and/or a search query.
My question is, what is the cleanest way to pass all this data to the view?
Some options I’m considering:
-
Have the controller create an array and pass that to the view as a single parameter:
class UserController{ public function renderView(){ // assume there's some logic to create models, get pagination, etc. $data = array() $data['models'] = $models; $data['currentPage'] = $current; $data['totalPages'] = $total; return $view->render($data); } } class UserView{ public function render($data){ // render the data } } -
Create properties in the view class and have the controller populate them:
class UserView{ public $models; public $currentPage; public $totalPages; } class UserController{ public function renderView(){ // assume there's some logic to create models, get pagination, etc. $view = new UserView(); $view->models = $models; $view->currentPage = $current; $view->totalPages = $total; return $view->render(); } } -
Give the view some sort of generic HashMap or Collection object as a container which can hold any arbitrary number and name of data.
class UserView{ public $collection = new Collection(); // works like a Java collection } class UserController{ public function renderView(){ // assume there's some logic to create models, get pagination, etc. $view = new UserView(); $view->collection->add($models,'models'); $view->collection->add($currentPage,'currentPage'); return $view->render(); } }
I know that technically any of the could work, but I’m unsure of the best choice, or if there’s a better or more conventional choice that I’m missing.
I’m going to recommend the concept of Fat Models, Skinny Controllers (or, Fat Models Thin Controllers if you prefer…)
In otherwords, your model is too strict – tying your model to represent only something like a RowDataGateway is extremely limiting.
In fact, I think good models hide the fact that you’re reading the data from a database at all. Because, in reality, your data could be in text files, or from a web service, or whatever. If you treat your Model like nothing more than a glorified DBAL, you doom yourself to having tightly-coupled code in your controllers that just won’t let you break away from the “data only comes from the database” way of thinking.