Here’s a quick tip that should help you write clean code in large CRUD-centric applications. This is something that’s helped me considerably working on and refactoring a fairly large web application that supports over 20 user types with context- and model-dependent behavioring.
The basic idea is that a controller should be lean and "dumb":
Manage only one class of records.
Customize its records’ behaviors based on the user/application context
Allow for searching, creating, viewing, modifying, and deleting specific records.
Delegate all complex logic to the model (e.g. how to search, or what records to find)
Delegate loading data and invoking model methods to Actions.
See the gists in my reply below for implementation ideas.
I’ve actually moved to a more general concept just involving loadModel(). I think the docs and auto-generators leave a lot to be desired. Here’s the gist of it as well as a conversation starter for self-describing controllers.
I bundled the classes I’m using into an extension that I’ve posted to Github.
This extension differs from the Yii philosophy (expressed by Gii) that controllers should contain the logic used to generate their action parameters. (E.g. using loadModel().) In the extension, the controller delegates the task of generating action parameters to a form class.
The flow is as follows:
Controller parses raw request data using an adaptor class.
The adaptor class passes attributes to an action parameters model in a standardized format
The parameters model validates the request parameters and loads additional dependent parameters, e.g. a model
The filters validate the parameters model
The parameters model attributes are bound as action parameters automatically by Yii
A standard RESTController with this extension is just a controller extending from the base class. In many cases you will not have to modify the default actions() or filters() configurations at all.