使用 Symfony 2 CLI 工具,如何为子类生成具有正确类型提示的 getter 和 setter?

Posted

技术标签:

【中文标题】使用 Symfony 2 CLI 工具,如何为子类生成具有正确类型提示的 getter 和 setter?【英文标题】:Using Symfony 2 CLI tools, how can I generate getters and setters with correct type hinting for sub-classes? 【发布时间】:2013-08-08 13:03:43 【问题描述】:

背景

我正在使用 Symfony 2 开发一个应用程序,该应用程序的结构使得“核心”包定义实体、关系和字段。然后其他包可以通过继承来专门化核心功能,即所谓的“子”包。

Doctrine 2 注释已被用于定义称为“包”的核心实体。一个“包”将建筑设计和一块土地联系在一起——本质上是一个房屋和土地包。我已将示例简化为更基本的形式,因此您不会在下面的示例中找到 Land 和 ChildLand 的定义,但您可以假设它们已以类似的方式实现。

更新

根据 FreeNode 的 #symfony 频道上的用户,这是一个原则问题,因为 app/console 命令只是调用了原则控制台。我正在使用学说 2.3。

这是一个图表,显示了导致问题的一般情况,应该有助于可视化场景:

(imgur link to full-size image)

此外,这里是关于教条问题跟踪器的错误报告的链接:http://www.doctrine-project.org/jira/browse/DDC-2605

更新 2 - 更详细的 ERD

实体之间的关系结构受到质疑,因此下面是我们正在实现的数据结构的更好示例。

主要要求再次是拥有提供一组共享实体和字段的核心类。公司包中的子类扩展了这些核心类。

我们确实详细考虑过 EAV,但在这种方法中,我们将花费更多时间来创建一个平台和工具来管理 EAV 数据,而不是满足当前的业务需求,我们将无法使用原则来管理将在数据库中定义的实体等。

随着时间的推移,我对这个问题有了更好的理解,似乎唯一的问题是由学说的 CLI 工具生成的 getter 和 setter,因为它们破坏了下面提到的类型提示合同。当手动纠正这些问题时,这种结构可以完美运行。

(imgur link to full-size image)

使用 CLI 工具生成实体

所以,最初我使用的是命令行工具...

> app/console doctrine:generate:entity

...生成具有基本字段映射的实体存根,然后手动将关系添加到土地(因为该工具似乎不支持关系):

这是生成的代码:

核心包实体:http://pastebin.com/3ujPT1mJ

子包实体:http://pastebin.com/sjAB0XJ2

生成 Getter 和 Setter

接下来,我通过执行来生成 getter 和 setter:

> app/console doctrine:generate:entities CompanyCoreBundle

> app/console doctrine:generate:entities CompanyChildBundle

自动修改核心和子实体定义:

核心包实体:http://pastebin.com/kfQRxcnm

子包实体:http://pastebin.com/UdiPP9xX

问题!

所以,问题的症结在于:如果你比较 Core 和 Child 包中的 setLand 函数,你会发现声明是不同的:

public function setLand(\Company\CoreBundle\Entity\Land $land = null)
public function setLand(\Company\ChildBundle\Entity\ChildLand $land = null)

错误:(

不幸的是,不同的类型提示会导致发生 php 严格错误,例如:

PHP Fatal error:  Class 'Symfony\Component\Debug\Exception\ContextErrorException' not found in ... Company/ChildBundle/Entity/ChildPackage.php on line ...

Runtime Notice: Declaration of ... should be compatible with ... in ... line ...

错误原因

在对为什么这是一个问题进行了一些研究之后,我在几个地方读到更改子类中的类型提示会破坏类型提示合同(参见这篇文章:Is there a way to redefine a type hint to a descendant class when extending an abstract class?)。

选项?

有一些明显但不太理想的选择:

我可以很容易地抑制严格的通知,但我的开发经理对不得不在我们的 CI 流程中创建雪花异常的前景犹豫不决。 我可以手动编辑学说生成的代码以删除所有类型提示,或确保子类类型提示与父类相同。这样做可以使代码工作,但我可以看到它很乏味,除非我编写一些脚本来为我管理它。 我不能使用命令行工具并手动制作我的实体和子实体。我宁愿能够用脚本自动化这个:(

我的问题!!! (最后)

我的问题是,是否可以使用命令行工具来执行我在这里尝试执行的操作?理想情况下,我希望能够执行原则控制台命令来生成实体存根、getter 和 setter,而无需手动干预来修复子类中的类型提示。如果这不容易实现,那么下一个最佳选择是什么?

感谢

谢谢!

【问题讨论】:

这会有帮助吗? symfony.com/doc/current/cookbook/doctrine/… 必须彻底重新思考我的方法。首先,我需要每个关系的接口。第二个也是可能的主要原因是,根据文档“ResolveTargetEntityListener 只能将目标更改为单个对象”,而我需要将核心功能扩展到许多孩子,所以我将拥有 'XPackage'、'YPackage'等等。不过,感谢您的回复,我不知道此功能,并且肯定会在未来的场景中考虑它。 您要求一段代码,您可以看到学说无法处理继承类具有覆盖关系属性的情况? 我的问题是,是否可以使用命令行工具来做我想做的事情?理想情况下,我希望能够执行原则控制台命令来生成实体存根、getter 和 setter,而无需手动干预来修复子类中的类型提示。如果这不容易实现,那么下一个最佳选择是什么? 不过,ResolveTargetEntityListener 还是要走的路。你把你的方法复杂化了。 【参考方案1】:

我不确定您将使用什么流程来定义实体,但为了有效地使用 GenericEngine 和 FordEngine 等 Doctrine 创建可持久化的实体,您需要 @MappedSuperclass

http://docs.doctrine-project.org/en/latest/reference/inheritance-mapping.html#mapped-superclasses

它是一个抽象类的 Doctrine 等价物。

在上面链接的那个页面上还有一些其他有趣的继承技巧。他们可能会帮助你。

就自动生成这些东西而言,它可能是可行的,但在 +50 声望点上高于我的薪酬等级。 :-) Doctrine 可以帮助您为实体生成代码模板,但实际上,花时间设计实体及其关系比花时间想出一个神奇的命令行组合更好。

(我自己,我有一个Manufacturer 实体,然后在EngineManufacturer 之间建立一对多关系。但这不是你问的。:-)

【讨论】:

感谢您的回复。我将添加详细的 ERD,说明“制造商”在不实施 EAV 结构的情况下如何工作;不同的蠕虫罐头。我们的结构满足所有业务需求,并且一旦手动修复教义的类型提示错误,效果就会很好。对数据结构的不同想法意味着我们可以永远讨论这个方面:-)。在时间方面,自动生成子类将提供持续的好处,除了类型提示问题之外,doctrine 的 CLI 工具很好地支持了这一点。如果不使用工具真的是答案,那么我会接受它:/

以上是关于使用 Symfony 2 CLI 工具,如何为子类生成具有正确类型提示的 getter 和 setter?的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 2. 如何为实体的嵌入表单设置默认值?

Symfony2:如何为整个应用程序强制使用 HTTPS?

如何为 Symfony2 站点正确设置 Varnish?

如何为特定浏览器导入脚本 Ember-CLi Broccoli

Symfony:如何为与 Voryx REST Bundle 的一对多关系创建 POST 请求

如何为 Symfony3 上的 AJAX 调用添加 CSRF 保护?