0

Zend Framework を使用し、ドメイン モデルを実装しています。モデル、マッパー、および DbTables があります。

データベースから複数の行をフェッチするか、複数のモデルを作成してデータベースの行またはフォームからそのモデルを取り込む必要があるフォーム データをフェッチするとします。

Mapper でモデルの取得と作成を実装し、Controller からそのメソッドを呼び出す必要がありますか? または、これをモデルに実装する必要がありますか?

Controller で Mapper を初期化してもよろしいですか?

4

2 に答える 2

1

ZF のすべての仕事で、同じアーキテクチャと設計パターンを使用しています。マッパーは、システム全体でデータベースにアクセスする唯一のクラスである必要があります。これにより、問題の適切な分離が保証されます。

モデルで次のようなシン ラッパー メソッドを使用することを少しいじりました。

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);

後者の例は、コントローラー メソッドのコード行が 1 行増えることを意味しますが、テストを簡単にするために、それだけの価値があると思います。

于 2012-06-12T05:00:51.397 に答える
1

短い答えはイエスです!
データベースから何かを取得する必要がある場合は、ほとんどどこかでマッパーを使用する必要があります。これは、理想的には、ドメイン モデルデータベースをまったく認識しないか、マッパーが実際に存在することを認識しないようにする必要があるためです。
ドメイン モデルとマッパーを使用およびアクセスするための多くの戦略とパターンがあると確信しています。また、これらのリソースをどのように活用するのが最善かについて、誰もが異なる意見を持っていると確信しています. 肝心なのは、使用方法を知っているものを使用する必要があるということです。後で詳しく知ったときに、いつでもリファクタリングできます。

例として、ベース マッパーとベース エンティティ (ドメイン) モデルを含めます。

<?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];
        }
    }
}

これらの概念とテクニックを理解するために、多くのチュートリアルと書籍を参照しました。
これらのオブジェクトの使用は必要に応じて行われます。DB からオブジェクトをプルする必要がある場合はマッパーを呼び出します。フォーム データ (またはその他のデータ) を使用してオブジェクトを構築する必要がある場合は、オブジェクトを直接呼び出すことができます。

これがいくらか役立つことを願っています。幸運を!

于 2012-06-12T04:28:57.070 に答える