我们何时应该在Magento 2中使用存储库和工厂?


74

我已经阅读了Magento 2中的一些教程,这让我有些困惑。我可以看到基本上有两种方法可以读取/写入业务实体:

检索数据

使用工厂方法

$object = $this->myFactory->create();
$object->load($myId);

使用存储库方法

$repo   = $this->myRepository();
$object = $repo->getById($myId);

保存数据

使用工厂方法

$object = $this->myFactory->create();
$object->load($myId);
$object->setData('something', 'somethingDifferent')->save();

使用存储库方法

$repo   = $this->myRepository();
$object = $repo->getById($myId);
$object->setData('something', 'somethingDifferent');
$repo->save($object);

我还看到,可以使用依赖项注入来注入存储库和工厂类。至少对我来说这令人困惑。

我们什么时候应该使用存储库方法和工厂方法?我们需要遵循的最佳实践是什么?


在\ Magento \ Setup \ Fixtures \ CategoryResolver上可以看到使用Factory,CollectionFactory和Repository的一个很好的例子
Ricardo Martins

Answers:


71

如果有一个存储库并且它可以很好地满足您的需求,请始终选择该存储库。

存储库是服务合同的一部分(它们是中的接口的实现Api),这意味着它们被视为与其他模块的公共接口。

使用存储库进行完全加载

$model->load()不属于服务合同的一部分。我对该特定主题有疑问,您可能会找到有用的答案:是否有理由比服务合同更喜欢$ model-> load()?

使用工厂创建新实体

存储库不带有创建新实体的方法,因此在这种情况下,您将需要一个工厂。但是将工厂用于接口,例如Magento\Catalog\Api\Data\ProductInterfaceFactory-它将基于DI配置创建正确的实现。

然后使用该repository->save()方法保存它。

如果需要更多控制权,请使用收集工厂

以下不是官方的Magento最佳做法,但目前,存储库无法很好地控制要加载的内容。搜索条件API允许您定义过滤器,但是例如,无法选择特定的EAV属性或指定要联接的索引表。

这些是实现细节,对服务合同API而言是隐藏的,但是这些实现细节通常很重要,如果忽略它们,将会导致性能下降。因此,一旦存储库限制了我,我便会毫不犹豫地使用基础集合。


2
您能否给出一个有关使用工厂创建新实体的代码示例,说明中缺少一些细节并且难以理解。非常感谢你。
Key Shang


谢谢。但这use the factory for the interface, such as Magento\Catalog\Api\Data\ProductInterfaceFactory - it will create the right implementation based on DI configuration.是我无法理解的重点,开发人员指南没有介绍InterfaceFactory,如何使用repository->save()方法保存新实体?我只能使用工厂来保存新实体,而不能使用存储库。
Key Shang

@Key Shang,这意味着该接口将为您提供所有设置的数据功能,以保存表的每一列,因此,请尽可能使用接口来保存新记录。InterfaceFactory类确实是在di:compile中创建的,因此您可以在var / generation文件夹中看到它们。
stevensagaar '18

@stevensagaar谢谢,我现在可以理解。
Key Shang

21

好问题。

即使存储库和工厂都允许我们访问实体,我认为我们也应该专注于他们的责任

来自Magento文档“工厂是实例化不可注入类的服务类,即表示数据库实体的模型。它们在ObjectManager和业务代码之间创建了抽象层。”

摘自Alan Storm的文章“存储库对象负责将对象信息读写到对象存储中”

我的解释是:如果我们的目的是使用不可注射的(所谓的“新的”)物体,我们应该使用工厂。如果我们的重点是在对象存储中搜索/读取/写入对象,则应使用存储库。

这是我对这个话题的理想主义方法。请记住,正如艾伦指出的那样,实际的实施可能会迫使我们搞砸。

请享用。


5

我要说的前进之路是开始使用存储库,因为它们允许在数据读取/写入和业务逻辑之间进行代码分离。

Alan Storm撰写了一篇非常详细的文章,介绍了如何使用存储库,还探讨了这种新方法的一些缺点:http : //alanstorm.com/magento_2_understanding_object_repositories/

另外,从Magento文档中,解释了此新方法的好处:http : //devdocs.magento.com/guides/v2.0/extension-dev-guide/service-contracts/service-contracts.html


2
感谢您的回答。实际上,我自己从alanstorm的文章中得到了这种怀疑。:)
Rajeev K Tomy

3
确实,这让您思考,但这可能是一件好事。即使这是Magento建议的最佳实践,也不意味着开发人员不能提出问题并批评它的某些方面。此外,存储库仍未涵盖某些情况。但是,在构建不会在将来版本中使用存储库中断的扩展的情况下,应考虑使用。另外,我相信他们会进一步发展,并提供有关开发人员需求的更多报道。
Marina Vilcea

我100%同意您的评论。我真的希望如此。还请参见fabian的答案。
Rajeev K Tomy

是的,我看到了:)已经支持他的回答。感谢您提出的好问题!
Marina Vilcea

此外,我在某处了解到在安装/升级脚本$setup->updateTableRow(...);或工厂中使用较低级别的数据操作方法是可以的,我不确定,但是感觉使用较高级别的参数也适用于该领域,您认为呢?
medmek '18

1

希望这个答案也可以对其他扩展开发人员有所帮助。

我们只需要使用存储库来保存模型。

  1. Magento 2中的“工厂模型”保存的数据非常有限。
  2. 另一方面,在与客户,产品等相关的eav属性的情况下,存储库模型包含所有数据。
  3. 对于保存模型,请始终使用存储库来保存任何实体,如果将工厂模型用于保存模型,它将删除与该实体相关的所有非系统eav属性(客户,产品等)。

  4. 为了加载模型,存储库是使用getById()方法获取模型的最佳选择。

我建议尽可能将Repository专门用于模型保存目的。


1

现在不赞成使用load,save,delete方法(模型)。因此我们可以使用资源模型或资源库。

Magento现在使用实体管理器概念进行保存,删除,加载操作。

资源模型具有实体管理器对象来完成这些操作。

$categoryModel = $this->_objectManager->create('\Magento\Catalog\Model\CategoryFactory')->create();        
  $categoryResource = $this->_objectManager->create('\Magento\Catalog\Model\ResourceModel\Category');        
  $categoryResource->load($categoryModel, 3);        
  echo $categoryModel->getName();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.