It's a bit tough to give you the "right" answers, since some of them deal with the specifics of the framework (regardless of the ones you are working with).
At least in terms of CakePHP:
Yes
Anything that deals with data or data manipulation should be in a model. In terms of CakePHP what about a simple find() method? ... If there is a chance that it will do something "special" (i.e. recall a specific set of 'condition'), which you might need elsewhere, that's a good excuse to wrap inside a model's method.
Unfortunately there is never an easy answer, and refactoring of the code is a natural process. Sometimes you just wake up an go: "holy macaroni... that should be in the model!" (well maybe you don't do that, but I have :))
There are a few things to fix up here, but here are a few tips.
i. Table models work a little better if their names are pluralized. They sound better in the magic methods (e.g. $product_set = findProducts() instead of findModel_Product())
ii. The reference map is the important one and allows for those nifty magic selection methods (e.g. findParentX()) to work. It belongs in the dependent table, which is the product
table here because it references the product_manufacturer
.
// in Model_Product
protected $_referenceMap = array(
// rule name
'Manufacturer' => array(
'columns' => 'manufacturer_id', // this column
'refTableClass' => 'Model_Manufacturer', // references that table object
'refColumns' => 'id' // and references that column
)
);
iii. Move dependent tables entry to your product_manufacturers
table model, if you'd like: it's used only to replicate ON DELETE/UPDATE CASCADE
database commands, though. (Leave it for now)
// in manufacturer table model
protected $_dependentTables = array('Model_Product');
Fetching
To get a product's manufacturer, do this:
$manufacturer = $product_row->findParentManufacturer();
To get a manufacturer's products, do this:
$product_set = $manufacturer_row->findProducts(); // Well, findModel_Product(), which is why you should rename your table ;)
For other magic methods originating from each single row, dig into the source code for Zend_Db_Table_Row_Abstract
(especially public function __call
).
Best Answer
I was the project lead for the Zend Framework project through version 1.0. My contributions were mainly in the Zend_Db component.
I frequently advise that people should use the Domain Model pattern and avoid the Anemic Domain Model antipattern. Remember that a Table is not a Model.
Your Model is a class (extending no base class) for code that encapsulates your business logic. The relationship between a Model and a Table isn't IS-A, it's HAS-A (or HAS-MANY). The Model treats database persistence as an implementation detail. The consumer of a Model should have no clue about your database structure (this allows you to change database structure without changing the Model's interface).
I'm basically repeating the answer I gave to Models in the Zend Framework.
Here is some more reading: