Zend framework2 带有子模型的Zend\Db模型

Zend framework2 带有子模型的Zend\Db模型,zend-framework2,parent-child,zend-db,one-to-one,Zend Framework2,Parent Child,Zend Db,One To One,ZF2项目-无条令,使用本机Zend\Db:具有以下结构: Controller ProductController Model Product ProductTable ProductType ProductTypeTable Product是模型,具有与“products”表字段相对应的变量 ProductTable是通过tableGateway连接到数据库的表类。ProductTable具有getItem()方法,可通过“id”检索请求的产品 P

ZF2项目-无条令,使用本机Zend\Db:具有以下结构:

Controller 
    ProductController
Model
    Product
    ProductTable
    ProductType
    ProductTypeTable
Product是模型,具有与“products”表字段相对应的变量

ProductTable是通过tableGateway连接到数据库的表类。ProductTable具有getItem()方法,可通过“id”检索请求的产品

ProductType是模型,具有与“productTypes”表字段相对应的id、name、description等变量

ProductTypeTable和ProductTable一样是table类

每种产品都属于特定的产品类型

products.productTypeId = productTypes.id 
这就是关系

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

我只想指定一个子模型作为父模型的变量

我可以在控制器中执行此操作,如下所示:

$product = $this->getProductTable()->getItem(7); // id = 7 
$product->setProductType($this->getProductTypeTable()
                    ->getItem($product->getProductTypeId());
但是我想在产品表类getItem()方法中实现它,所以我不必在每个控制器中都考虑它,它是一种封装的

正确的方法是什么


谢谢。

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

  • 使您的
    产品->exchangeArray()
    功能更智能
  • 使用前缀帮助获取所有必需的
    ProductType
    字段,例如:
    type
  • 添加
    @var-ProductType
    ,这样您就有了适当的自动补偿(在Eclipse中适用于我)


    您遇到的问题是,在将数据库访问抽象到单个数据库表方面,它实际上是唯一擅长的。它无论如何都不允许实体水合或关系管理。对象关系映射器(ORM)如条令解决了这个问题

    如果原则,无论出于何种原因,不适合您的用例,那么替代方案可以是实现

    数据映射器是一个将内存中的对象与数据库分离的软件层。它的职责是在两者之间传输数据,并将它们彼此隔离

    数据映射器将使用表网关获取每个表所需的数据,并构造
    产品
    实例,包括其关联的
    产品类型
    。然后将映射器公开给控制器(而不是表网关)

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

    感谢您的详细回复。不过,我正在成功地使用联接进行此操作,这正是我试图避免的。我不想填充ProductType对象,我想通过产品附带的productTypeId字段值创建相关的ProductType对象实例,并将其作为对象变量链接到产品模型。谢谢。这是真实的就我所能理解你的详细描述而言,这很好。这很好,因为我知道一定有办法,但我对ZF2不是100%熟悉。我试图避免使用本地方法进行学习。我目前无法对其进行测试,但我想感谢你为解释这一点所做的努力。我回来后会给出结果这个周末我对我的电脑做了一些关于DataMapper的研究,我知道这是我需要的,也是我必须学习的。但是我太专注于TableGateway了——这意味着到目前为止我只熟悉ZF2中的TableGateway模式,没有适当的文档,我很难开始,我发现只有DataMapper但是另一个对初学者没有帮助的大画面的一小部分。你能参考一个教程或一个我可以像传统指南一样遵循的好的开始吗?除此之外,据我所知,DataMapper正是我问题的答案。谢谢!我强烈推荐Martin Fowler的书。尽管这本书第一次出版在2002年,大多数示例都是Java,它仍然提供了关于web应用程序设计模式的非常相关和简洁的细节(数据映射器模式只是众多模式中的一种)。我会尝试一下-我不认为它对ZF2有太大帮助,但它看起来像是了解很多模式的宝贵资源-我不是很强。谢谢。关于您的示例ProductMapper和我的问题中的文件结构,以及您的声明“您将在控制器中而不是在表网关中公开映射器”:我是否打算杀掉ProductTable和ProductTypeTable类,注册映射器类,并使用它们来代替表类?我可以感觉到我在问一个ZF2专家的愚蠢问题,但我非常习惯使用Album Tutorial约定来设置表网关,并在Module.php中作为工厂返回,现在我只是尝试跟随一个有组织的方式就像专辑教程一样。再次感谢。
    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);
    }