我正在使用Zend框架并实现域模型。我有Models,Mappers和DbTables。创建多个模型
假设我们应该从数据库中获取多行或获取我们应该建立多个模型形式的数据并填充数据库从行或形式的模型。
我应该实现抓取和模型建立的映射,然后调用从控制器,方法是什么?或者我应该在模型中实现这个?
可以在Controller中初始化Mapper吗?
我正在使用Zend框架并实现域模型。我有Models,Mappers和DbTables。创建多个模型
假设我们应该从数据库中获取多行或获取我们应该建立多个模型形式的数据并填充数据库从行或形式的模型。
我应该实现抓取和模型建立的映射,然后调用从控制器,方法是什么?或者我应该在模型中实现这个?
可以在Controller中初始化Mapper吗?
简短的回答是YES!
如果你需要从你几乎有地方使用映射数据库任何东西,因为理想的域模型应该不是在所有或事件的帽子映射器真的存在认识的数据库。
我确定许多使用和访问域模型和映射器的策略和模式。我也确信每个人对如何最好地利用这些资源都会有不同的看法。底线是你必须使用你知道如何使用的东西,当你知道更多东西时你总是可以重构。
仅通过实例的方式,我会包括底座映射和基础机构(领域)模型。
<?php
/**
* Base mapper model to build concrete data mappers around.
* Includes identity map functionallity.
*/
abstract class My_Application_Model_Mapper
{
protected $_tableGateway = NULL;
protected $_map = array();
/**
* Will accept a DbTable model passed or will instantiate
* a Zend_Db_Table_Abstract object from table name.
*
* @param Zend_Db_Table_Abstract $tableGateway
*/
public function __construct(Zend_Db_Table_Abstract $tableGateway = NULL) {
if (is_null($tableGateway)) {
$this->_tableGateway = new Zend_Db_Table($this->_tableName);
} else {
$this->_tableGateway = $tableGateway;
}
}
/**
* @return Zend_Db_Table_Abstract
*/
protected function _getGateway() {
return $this->_tableGateway;
}
/**
* @param string $id
* @param object $entity
*/
protected function _setMap($id, $entity) {
$this->_map[$id] = $entity;
}
/**
* @param string $id
* @return string
*/
protected function _getMap($id) {
if (array_key_exists($id, $this->_map)) {
return $this->_map[$id];
}
}
/**
* findByColumn() returns an array of rows selected
* by column name and column value.
* Optional orderBy value.
*
* @param string $column
* @param string $value
* @param string $order
* @return array
*/
public function findByColumn($column, $value, $order = NULL) {
$select = $this->_getGateway()->select();
$select->where("$column = ?", $value);
if (!is_null($order)) {
$select->order($order);
}
$result = $this->_getGateway()->fetchAll($select);
$entities = array();
foreach ($result as $row) {
$entity = $this->createEntity($row);
$this->_setMap($row->id, $entity);
$entities[] = $entity;
}
return $entities;
}
/**
* findById() is proxy for find() method and returns
* an entity object. Utilizes fetchRow() because it returns row object
* instead of primary key as find() does.
* @param string $id
* @return object
*/
public function findById($id) {
//return identity map entry if present
if ($this->_getMap($id)) {
return $this->_getMap($id);
}
$select = $this->_getGateway()->select();
$select->where('id = ?', $id);
//result set, fetchRow returns a single row object
$row = $this->_getGateway()->fetchRow($select);
//create object
$entity = $this->createEntity($row);
//assign object to odentity map
$this->_setMap($row->id, $entity);
return $entity;
}
/**
* findAll() is a proxy for the fetchAll() method and returns
* an array of entity objects.
* Optional Order parameter. Pass order as string ie. 'id ASC'
* @param string $order
* @return array
*/
public function findAll($order = NULL) {
$select = $this->_getGateway()->select();
if (!is_null($order)) {
$select->order($order);
}
$rowset = $this->_getGateway()->fetchAll($select);
$entities = array();
foreach ($rowset as $row) {
$entity = $this->createEntity($row);
$this->_setMap($row->id, $entity);
$entities[] = $entity;
}
return $entities;
}
/**
* Abstract method to be implemented by concrete mappers.
*/
abstract protected function createEntity($row);
}
这是基础域对象:
<?php
/**
* Base domain object
* includes lazy loading of foreign key objects.
*/
abstract class My_Application_Model_Entity_Abstract
{
protected $_references = array();
/**
* Accepts an array to instantiate the object, else use
* __set() when creating objects
* @param array $options
*/
public function __construct(array $options = NULL) {
if (is_array($options)) {
$this->setOptions($options);
}
}
/**
* @param array $options
* @return \My_Application_Model_Entity_Abstract
*/
public function setOptions(array $options) {
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
/**
* Map the setting of non-existing fields to a mutator when
* possible, otherwise use the matching field
*/
public function __set($name, $value) {
$property = '_' . strtolower($name);
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException("Setting the property '$property'
is not valid for this entity");
}
$mutator = 'set' . ucfirst(strtolower($name));
if (method_exists($this, $mutator) && is_callable(array($this, $mutator))) {
$this->$mutator($value);
} else {
$this->$property = $value;
}
return $this;
}
/**
* Map the getting of non-existing properties to an accessor when
* possible, otherwise use the matching field
*/
public function __get($name) {
$property = '_' . strtolower($name);
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException(
"Getting the property '$property' is not valid for this entity");
}
$accessor = 'get' . ucfirst(strtolower($name));
return (method_exists($this, $accessor) && is_callable(array(
$this, $accessor))) ? $this->$accessor() : $this->$property;
}
/**
* Get the entity fields.
*/
public function toArray() {
//TODO
}
/**
* set and get for _references array, allows the potential to lazy load
* foreign objects.
*/
public function setReferenceId($name, $id) {
$this->_references[$name] = $id;
}
public function getReferenceId($name) {
if (isset($this->_references[$name])) {
return $this->_references[$name];
}
}
}
我已经提到很多教程和书籍,终于让我的头围绕这些概念和技术。
这些对象的使用是根据需要的,如果需要从调用映射器的数据库中提取对象,如果需要使用表单数据(或其他数据)构建对象,则可以直接调用该对象。
我希望这有助于一些。祝你好运!
我在我所有的ZF工作中都使用相同的架构和设计模式。您的映射器应该是整个系统中访问数据库的只有类。这确保了良好的Separation of Concerns。
我把玩了一下用在我的模型薄的包装方法,如:
class Application_Model_Foo {
public function save() {
$mapper = $this->_getMapper();
$mapper->save($this);
}
}
这使我打电话是这样的:
$foo = new Application_Model_Foo();
$foo->setBar('baz-bum');
$foo->save();
但是,这使得测试更加复杂当涉及SoC时会混淆水。最近我支持只是直接调用映射器从我的代码中除去这种情况发生,如在:
$foo = new Application_Model_Foo();
$foo->setBar('baz-bum');
$mapper = new Application_Model_FooMapper();
$mapper->save($foo);
后者例如是指在我的控制器的方法一行代码,但对于在测试中简单我认为这是值得的。