2015-05-07 153 views
1

ZF2项目的Zend \ Db的模式 - 无主义,使用本机的Zend \ Db的:具有以下结构:与儿童模式

Controller 
    ProductController 
Model 
    Product 
    ProductTable 
    ProductType 
    ProductTypeTable 

产品是模型,具有对应于“产品”表中的字段变量。

的productTable是连接到经由tableGateway数据库表类。的productTable具有的getItem()方法由“ID”来检索请求的产品。

ProductType是模型,具有对应像ID,名称,描述变量到“产品” pes“表字段。

ProductTypeTable就像ProductTable一样是表类。

每个产品属于某个ProductType

products.productTypeId = productTypes.id 

是的关系。

在ProductTable-> getItem()方法中,我可以简单地获取productTypeId。 我可以使用连接来获取productTypes.name,productTypes.description或“productTypes”表中的任何字段。 但我不想这样做 - 而是处理产品实体中的新变量,如productTypeName,productTypeDesc, 我想要Product->getProductType()并将其设置为ProductType对象,因此我可以获得Product->getProductType() ->getName()以获得产品类型名称。

只是我想分配一个子模型作为父模型的变量。

我能做到这一点在控制器象下面这样:

$product = $this->getProductTable()->getItem(7); // id = 7 
$product->setProductType($this->getProductTypeTable() 
        ->getItem($product->getProductTypeId()); 

,但我想,使其在产品表类的getItem发生()方法。所以我不必在每个控制器中考虑它,而且它是封装的。

这样做的正确方法是什么?

谢谢。

回答

1

您拥有的问题是Table Gateway pattern仅仅是将抽象数据库访问抽象为单个数据库表的真正好处。反正它不允许实体的水合或关系的管理。对象关系映射器(ORM's)(如Doctrine)解决了这个问题。

如果主义,不管是什么原因,是不适合你的使用情况的替代,可以实现Data Mapper Pattern

数据映射器是,在内存中的对象从数据库中分离的软件层。其职责是两个,也之间传输数据给他们相互

数据映射器隔离会使用表网关获取每个表所需的数据和构建Product实例,包括它的关联ProductType。然后你会将映射器公开给控制器(而不是表格网关)。

一个简单的例子ProductMapper

class ProductMapper 
{ 
    // @var \Zend\Db\TableGateway\TableGateway 
    protected $productTable; 

    protected $productTypeMapper; 

    // an 'identity map' of loaded products 
    protected $loaded = []; 

    public function __construct(ProductTable $productTable, ProductTypeMapper $productTypeMapper) 
    { 
     $this->productTable = $productTable; 
     $this->productTypeMapper = $productTypeMapper; 
    } 

    protected function hydrate(Product $product, array $data) 
    { 
     $product->setId($data['id']); 
     $product->setName($data['name']); 
     $product->setFoo($data['foo']); 

     if (isset($data['type_id'])) { 
      // Load a fully constructed product type from the database 
      $type = $this->productTypeMapper->findById($data['type_id']); 
      $product->setType($type); 
     } 

     return $product; 
    } 

    public function findById($id) 
    { 
     if (isset($this->loaded[$id])) { 
      return $this->loaded[$id]; 
     } 
     // Get the data 
     $row = $this->productTable->select(['id' => $id]); 

     if (empty($row)) { 
      throw new SomeCustomException("No product could be found with id $id"); 
     } 
     // Create and hydrate the product 
     $product = $this->hydrate(new Product, $row->current()) 
     $this->loaded[$id] = $product; 

     return $product; 
    } 

    public function save(array $data); 

    public function update($data); 

    public function delete($id); 
} 
+0

只要我可以按照你的详细描述,这是非常好的。这很棒,因为我知道必须有一种方法,但我对ZF2并不是100%熟悉的。我试图避免学说使用本地方法 - 学习。我目前无法对其进行测试,但是我想感谢您为解释这一点做出的努力。当我周末回到电脑时,我会给出结果。 – smozgur

+0

我做了一些关于DataMapper的研究,我可以看到这是我需要的,我必须学习的东西。然而,我太过专注于TableGateway--意味着到目前为止只熟悉ZF2中的TableGateway模式,而且如果没有适当的文档,我就很难开始工作,而且我没有发现任何关于DataMapper的内容,而是另一大图片的一小部分帮助初学者。你可以参考一个教程或某个地方的一个良好的开端,我可以像传统的指南一样遵循?除此之外,我的理解是,DataMapper正是我的问题的答案。谢谢! – smozgur

+0

我强烈推荐Martin Fowler的书[企业应用程序架构模式(PoEAA)](http://www.amazon.co.uk/Enterprise-Application-Architecture-Addison-Wesley-Signature/dp/0321127420)。尽管第一次在2002年发布,并且大多数示例都是Java,但它仍然提供了有关Web应用程序设计模式的非常相关和简明的细节(Data Mapper模式仅为众多示例之一)。 – AlexP

0

你可以做到这一点,你只需要遵循以下3个步骤:

  1. 让您Product->exchangeArray()功能更聪明
  2. 获取所有所需ProductType领域,使用前缀有助于例如:type_
  3. Add @var ProductType所以你会有适当的自动运行(适用于Eclipse的我)

    <?php 
    namespace Product\Model\Product; 
    
    class Product { 
        public $id; 
        ... 
        /** 
        * @var ProductType 
        */ 
        public $productType; 
        ... 
        public function exchangeArray($data) { 
         $this->id = (isset($data['id'])) ? $data['id'] : null; 
         ... 
         $productType = new ProductType(); 
         $typeData = array(
          'id' => $data['type_id'], 
          'value' => $data['type_value'] 
         ); 
         $productType->exchangeArray($typeData); 
         $this->productType = $productType; 
        } 
    } 
    
+0

感谢您的详细回复。但是,我正在通过成功地加入,这就是我想要避免的。我不想填充ProductType对象,我想通过产品附带的productTypeId字段值创建相关的ProductType对象实例,并将其作为链接到产品模型的对象变量使用。谢谢。 – smozgur