【问题标题】:MVC structure with Zend Framework 2 and Doctrine带有 Zend Framework 2 和 Doctrine 的 MVC 结构
【发布时间】:2013-11-01 22:36:57
【问题描述】:

什么是使用 ZF2 和 Doctrine 实现业务逻辑模型的“正确方法”,同时创建干净的 OOP 和 MVC 结构,并为模型提供对 EntityManager 的访问权限?

虽然我很想将 Doctrine Repositories 用于所有业务逻辑,但我知道它们应该主要用于执行复杂的查询。我也知道 ZF2 中的模型可以通过多种方式提供依赖项(EntityManager):ZF2: Dependency injection done the proper wayhttp://zend-framework-community.634137.n4.nabble.com/ZF2-Injecting-objects-to-a-controller-or-getting-objects-from-the-service-locator-td4656872.html

为了说明现实生活中的问题,我们如何为简单的网上商店功能创建模型层:

首先,我们将拥有实体

/**
 * @Entity(repositoryClass="App\Repository\ProductRepository")
 * @Table(name="products")
 */
class Product { ... }

/**
 * @Entity(repositoryClass="App\Repository\ProductgroupRepository")
 * @Table(name="productgroups")
 */
class Productgroup { ... }

以及为我们提供更详细查询功能的存储库

class ProductRepository extends EntityRepository {
    public function isAvailable() { ... }
    public function getQuantity() { ... }
    public function getProductImages() { ... }
    public function getRelatedProducts() { ... }
    ...
}

class ProductgroupRepository extends EntityRepository {
    public function getAvailableProducts() { ... }
    public function getAllProducts() { ... }
    ...
}

但是我们把这样的业务逻辑放在哪里呢?

Products functionalities:
- createNewProduct( $data ), eg. update prices, retrieve new quantities, generate a     new image gallery, notify the administrator, ...
- deleteProduct(),           eg. delete corresponding files and existing associations, put product into archive
- ...

Productgroups functionalities:
- removeProductFromProductgroup( $product), eg. update ordering in group, remove associations, ...
- addProductToProductgroup( $product ),     eg. update ordering in group, create associations, ...
- deleteProductgroup(),                     eg. delete productgroup, set all it's products as uncategorized
- ...

是否应该创建 Productgroup 业务模型,例如,作为在服务级别注入 EntityManager 的类? --

class Productgroup implements ServiceLocatorAwareInterface
{
    public function removeProductFromProductgroup( $productgroup, $product) { }
    public function addProductToProductgroup( $productgroup, $product) { }
}

或者它是否也应该扩展原始实体以访问其内部结构? --

class Productgroup extends \Application\Entity\Productgroup 
    implements ServiceLocatorAwareInterface
{
    public function removeProductFromProductgroup( $productgroup, $product) { }
    public function addProductToProductgroup( $productgroup, $product) { }
}

如果是这样,它是否也应该有某种设置状态方法? 公共功能集($产品){ $this->populate($product); }

【问题讨论】:

    标签: php model-view-controller model doctrine zend-framework2


    【解决方案1】:

    关于在哪里有业务逻辑,显然是模型。我不建议扩展您的实体,因为任何与设置/获取实体对象无关的逻辑都应该在您的实体之外。

    所以答案是肯定的,我会将实体管理器注入模型中。但是,您是否使用服务定位器或其他方法进行 DI 取决于您。

    您正在思考的问题实际上是关于 OOP、DI、DiC 等的。请阅读专家关于 DI 的一些最佳博客文章。我在下面列出了它们:

    将依赖注入提升到不同的级别真的取决于您。如果您查看 Martin Fowler 的博客,您可以了解构造函数注入、setter 注入和为您执行注入的 DiC。您必须为您的系统接听电话。对我有用的是,在模块依赖项中,我进行构造函数注入(以便依赖项清晰可见)。任何作为服务的东西,都会通过 DiC 或 ServiceLocator 从我的模块外部调用。

    反对服务定位器模式的唯一论据是它将依赖注入隐藏到其配置中,并且不清晰可见。

    【讨论】:

      【解决方案2】:

      我将Array Collection 用于此类任务。这个对象有各种非常有用的方法,比如 clean()、contains() 等。

      我倾向于将我的 oneToOne、oneToMany 等关系存储在 arrayCollections 中。

      在您的实体中,您必须使用构造函数来启动集合。

      use Doctrine\Common\Collections\ArrayCollection;
      
      /**
       * @ORM\OneToMany(targetEntity="yourModule\Entity\yourEntity", mappedBy="yourRelation", cascade={"persist"})
       */
      protected $yourCollection;
      
      public function __construct()
      {
         $this->yourCollection = new ArrayCollection();
      }
      //once I have the collection I usually create methods like add, remove, etc methods like so:
      public function addToCollection($toAdd) {
         $this->yourCollection->add($toAdd);
      }
      
      public function removeFromCollection($toRemove) {
         $this->yourCollection->removeElement($toRemove);
      }
      
      //etc.....
      

      【讨论】:

      • 我相信你可能弄错了,这个答案是针对其他问题的?感谢您的尝试,但我看不出它与这个特定问题有什么关系。
      • 我可能没有很好地解释自己。我只是想展示一种方法,您不必实现您提供的 removeProductFromProductGroup() 之类的功能。因为它们以某种方式代表关系,所以你绕过了处理关系的教义方式。通常,您使用 OneToMany、ManyToOne、ManyToMany、ManyToOne 等注释来定义它们,并使用关系而不是自己创建这些方法。您可以在此处找到有关此问题的一些信息:docs.doctrine-project.org/en/latest/reference/…
      • 是的,当然,这是处理 ArrayCollections 的正确方法。但我的问题是针对整个业务逻辑建模,而不仅仅是处理实体的细节。除了删除实体之外,还需要处理很多其他操作(业务逻辑)(例如,更新产品订单、发送通知电子邮件、删除属于该文件的文件、更新导航菜单......),所以主要问题是您如何将整个业务逻辑建模为对象和类?您能否回答/评论哪些对象持有并执行该业务逻辑?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-13
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      相关资源
      最近更新 更多