【问题标题】:Modular architecture to encapsulate functions in Symfony2在 Symfony2 中封装功能的模块化架构
【发布时间】:2015-10-10 11:15:41
【问题描述】:

我想开发什么......

我目前正在开发一个 SaaS 解决方案 (Symfony2) 来构建 HTML 演示文稿或更好的幻灯片放映。用户可以登录到管理 UI 并创建演示文稿。此演示文稿可以稍后播放。演示文稿由元素组成。元素可以是图片、文本、视频、pdf等。

应该从用户界面封装这些元素类型。所以extern开发者可以开发这样的新模块(元素类型),定义接口并注入到系统中。

如果一个新模块完成,我们将它移动到 symfony2 目录中的特定目录,系统会检测到新模块。 无需对管理 UI 系统进行硬编码更改

每个模块都有自己的“产品编号”。所以我们可以使用数据库来为不同的用户启用或禁用模块。

模块必须实现哪些功能?

在管理用户界面中,用户可以创建演示文稿并添加不同类型的元素(模块)。用户会看到包含元素的时间线。当他单击一个元素时,该元素的编辑器将显示在时间轴下方(父子视图)。每个模块都有不同的编辑器。文本模块需要其他配置可能性而不是图像模块。

因此,在管理 UI 中,我们需要编辑元素的函数:

  • createNewElement() 在数据库中创建新条目(模块有自己的表,例如 mod_text_elements)
  • renderEditorView() 生成 HTML,该 HTML 将显示在管理 UI 中,并带有特定于模块的输入。例如。图片上传/裁剪、所见即所得编辑器、...
  • saveEditorInputs()模块需要处理编辑器中输入的数据,并将其保存到数据库中的元素条目中
  • deleteElement() 删除一个元素

演示文稿的输出:

稍后我们要播放此演示文稿。因此,一个循环会遍历表示元素,并询问元素的模块是什么以及如何显示它。

  • renderPresentation() 为演示文稿呈现 (HTML) 元素

数据库

我制作了一个可能的解决方案的小图表,用于将有关模块和元素的信息保存在数据库中。黄色实体是特定于模块的表。

如何在 Symfony2 中实现这一点?

我的第一个想法是定义一个必须由模块实现的接口。但是哪个类必须实现这个?控制器?

模块 = 捆绑包吗?

如何实现编辑器的View-in-View?应该在管理 ui 的用户界面中查看模块的编辑器(例如 renderEditorView())。

【问题讨论】:

  • 您是对所有插件使用mod_text_elementmode_image_element,还是每个插件都有自己的表格?
  • 每个插件/模块都有自己的表。模块只使用自己的表来保存元素的信息。例如:mod_image_element、mod_image_files、mod_image_....图像模块...

标签: symfony architecture saas


【解决方案1】:

我会通过连接到 EventDispatcher Component 来做到这一点。

您的“主”控制器将定义一组事件,这些事件对应于您在上面定义的标准 CRUD 操作... onCreateNewElement()、onRenderEditorView() 等。您可能会发现更多提供钩子在您构建应用程序时(例如,允许插件将工具添加到工具栏)。

您将定义一个 Service(这不一定是控制器类),它会查找新的“模块”并将其正确命名的方法添加为您的自定义应用程序事件的侦听器。

modules = bundles 吗?这完全取决于你。您是否要为用户提供专门为您的应用程序“安装”新模块的方法?那么一个模块需要是什么样子完全取决于你。您是否要将 Composer 混入其中并允许以这种方式安装模块?对结构施加了一些限制,但仍然取决于您。

如何实现 View-in-View? 再次,这归结为您如何为“事件插件”定义接口以及它们对 TWIG 和YAML 配置。

您真正要问的问题是如何在不破解现有代码的情况下向应用程序添加功能 ...答案是 EventDispatcher。剩下的就看你自己了。

【讨论】:

  • 非常感谢。我相信这是正确的方法。但目前我不知道如何修改请求的输出/视图。用户想要添加新元素(控制器:PresentationController,动作:addElementAction())。在操作中,我将调度 modules.get_available_modules 事件。所有模块都在此事件上注册,并且可以将其产品 ID 附加到事件中。但是,在所有模块都附加它的 ID 之前,该操作已经呈现了视图。你能帮我吗?
  • 也许你可以通过一个更简单的例子来解释这个过程,比如 api 调用:get_modules。它应该响应系统中所有可用的模块。我必须在哪里调度事件?我可以在哪里修改响应?非常感谢!
【解决方案2】:

还有另一种使用自定义“模块”扩展代码库的方法:Dependency Injection Tags

它是这样工作的:

  • 您创建应用的核心,实现基本功能, registers compiler pass 处理代码扩展
  • 模块可以是核心应用程序的一部分,也可以移动到外部包中
  • 每个模块都必须在 DI 容器中注册,并带有您的核心应用支持的标签,因此可以正确处理(添加菜单位置、新元素类型,如您的示例)
  • Symfony DI 编译所有服务和内容,因此所有模块都可以立即在应用程序中使用(例如,您可以迭代准备好的项目集合,而无需动态构建它)

在我看来,EventDispatcher 更适合处理实时操作,例如在创建新实体时发送通知(例如控制器/服务调度事件,某些包订阅它并发送通知)。

当你想扩展核心时,我会推荐 DI 标签。当然,您必须构建所有核心(接口和整个架构),以便模块可以扩展现有服务的数据,然后您只能使用您的服务。

整个 Symfony 全栈框架基于 od this tags,因此有很多现有的代码需要研究来获得这个概念。

如果我写的内容和 Symfony 文档中的内容足够清楚,请告诉我。如果您需要更多信息,我会尽力提供帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-12
    • 2011-02-17
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多