Reputation: 1422
I've got an ActiveRecord BaseModel
class and a lot of classes-models which inherit from it. And i've got a class Bookmark
, which is inherited from BaseModel
as well.
Also, i've got Decorator
-inherited classes, they implements special interface to represent single model ( getModelView(model)
method). This is some pseudo-code:
TestModel inherits BaseModel
getName:
return this.name
BookmarkModel inherits BaseModel
BaseModel model
getBookmark:
return this.model
TestDecorator inherits BaseDecorator implements SingleModelViewInterface:
getView(model):
return 'view' //html-view of model
BookmarkDecorator inherits BaseDecorator
getBookmarksView(BookmarkModel[] bookmarks):
foreach(bookmarks > bookmark):
decorator = Relation::getDecoratorByModel(bookmark->getEntityType())
decorator->getView(bookmark->getBookmark())
So, everything looks good, until i want to change that View for bookmarked model a bit. I want a to add a custom title for that view. And i can't make it inside decorator, because it renders it not only for a bookmarks.
EDIT: So, the problem is - seems that i need a decorator pattern, but i dont have anything to inherit from, because concrete TestDecorator using TestModel speical methods. So now i've done some really bad realization, using magic methods (PHP):
class BookmarkedModel {
/** @var BaseEntityModel*/
private $model;
public function __construct(BaseEntityModel $model) {
$this->model = $model;
}
public function getName() {
return 'Bookmark '.$this->model->getName();
}
public function __call($name, $arguments) {
return call_user_func_array(array($this->model, $name), $arguments);
}
public function __get($name) {
return $this->model->$name;
}
public function __set($name, $value) {
return $this->model->$name[$value];
}
}
So it will work for now, but in terms of code structure, readability and stability it's really bad decision.
Upvotes: 15
Views: 622
Reputation: 1163
The model should be unaware of the view. Models represent the raw data seen from every angle at once. The view is a perspective of that model. The controller should feed the model to the view:
$model_view->render($model);
Then decorate the view:
$bookmark_view->render($model); // bookmark_view wraps a model_view,
// returns 'Bookmark '.$this->model_view->render($model)
Only decorate based on interfaces, not types.
PHP's magic methods are great, but they should not be used for ActiveRecord, this goes against "separation of concerns", in this case separating the model from it's persistence mechanism.
Instead make an ActiveRecord object and feed the model to it.
$record->store($model);
Then if you need to modify storage, again just decorate the storage mechanism:
$log_record->store($model); // wraps $record, logs a message prior to database storage.
Upvotes: 2