I have one big concern about integrating these functions directly into DM - unnecessarily loading a lot of class data if it isn’t needed. If I’m just looking up some value - and not displaying it - I don’t want to load in the display or editing classes.
In my case, I’m mostly sending my data over JSON-formatted data, so there actually is no display or formatting code being used!
The reason I chose my method - using the “->v->${field}” or “->e-${field}” methods is that it allowed me to load up the class when it was needed, but completely silently. Also, this class only needed to be instantiated once each per object. not perfect, but not too bad. I might actually try to move more of my code into shared objects, eventually.
Of course, you could make this work just fine with stensi’s method - using magic get_${field}_as_${type} - you would just have to load a rendering or editing class in the background. I think I have a way of combining the methodologies.
First, I would offer the magic fields display_${field}_as_${type} and edit_${field}_as_${type}, as stensi mentioned
Second, allow the special forms view_${field} and view_${field}_as_default (same for edit_) to exist, and to choose the type based on the (optional) $type parameter of the validations field, or default to simply calling htmlspecialchars() on the field. For editing, it should simply place the htmlspecialchars()‘ed in a plain <input type=“text” />. Also, the virtual properties (not methods) $view_${field} and $edit_${field} should call view_${field}_as_default() behind the scenes. This is very clean to read and write:
// example formatted this way because the website won't properly render <?= ?> tags
echo $user->view_firstname;
echo ' ';
echo $user->view_lastname;
Third, load a single class in that can handle the rendering, but only upon first access. The best case would be to store this class as a static object within DataMapper, or within each class, to reduce overhead. The methods would, obviously, be named after the ${type}.
Fourth, this class needs to be able to be overridden. In fact, I think it would be best if the default class was extremely basic - maybe only offer the defaults listed above. The name of the class could be described the way updated and created fields are, within the DM config, or the way model or table are, within the object. You could label it $field_displayer and $field_editor. Then, when instantiated, you could do:
if( ! isset( ($model)::$_dm_field_displayer ) ) {
if( isset($this->field_displayer) ) {
$this->load->library(strtolower($this->field_displayer));
($model)::$_dm_field_displayer = new $this->field_displayer;
} else {
if( ! isset(DataMapper::$_dm_field_displayer) ) {
$model = // get model from datamapper config
$this->load->library(strtolower($model));
DataMapper::$_dm_field_displayer = new $model
}
($model)::$_dm_field_displayer = DataMapper:$:_dm_field_displayer;
}
}
// now look up function in ($model)::$_dm_field_displayer
This also allows for methods that need or can take arguments, such as display_${field}_as_limitedlength($length, $use_ellipsis)
Finally, I agree here with Stensi that the related objects should not be embedded within DM. In the end, the question is, how much should you combine your View with your Model and Controller. Of course, you really should keep them separate. That’s why I prefer, somewhat, my method of using a virtual property.
As for me, I probably won’t use it at all unless it is completely overwriteable. All of my editors rely on the Dojo JavaScript toolkit, and both my viewers and editors depend on localization code and the structure of the DM object. For example, I print out the complete XHTML form row, including a properly linked label tag, error messages, etc, from a simple ->e->name. It helps to keep my code as light as possible, and keeps 90% of my formatting in one spot.
Hopefully that is some help.
PS: I actually prefer the term “viewer” instead of “displayer”, and therefore the function name view_${field}_as_${type}... But that’s not terribly important.