跳转到主要内容
yplam 提交于 30 July 2014

原文链接:http://drupalize.me/blog/201407/drupal-8-plugins-explained

 

在您开始学习Deupal 8模块开发以后,您遭遇到的第一个Drupal新特性很有可能就是插件。譬如这篇关于创建区块的文章,使用的就是新的插件机制。在写完这篇文章后我觉得如果可以后退一步,跟大家分享关于插件的高阶应用将是一件有趣的事情。这篇文章将介绍“什么是插件”以及“为何使用插件”,目的是帮助Drupal 7开发者转换到Drupal 8。

什么是插件

插件是Drupal 8引入的新概念,对每一名Drupal 8模块开发者而言都十分重要。你会用到插件的一些常见例子如:创建一个自定义区块、提供自定义的字段、为图片添加处理特效(如缩放或旋转)。Drupal 手册中是这样定义插件的:

“D8插件系统提供一组指导原则和可重用的代码组件,允许开发者在他们的代码中开放可插入的组件,并且(如有必要)可以在用户界面中管理这些组件。”

插件在什么情况下有用?在您需要让其他模块提供额外的“东西”,这些“东西”实现相同的接口,但是提供完成不同的功能。区块就是其中一个经典的应用。在Drupal中,每一个区块本质上都是由相同的部分组成:一个标签,一些内容,以及一些用来控制其可见性与缓存性的设置。然而,对每个模块而言,如何生成标签与内容都是很不一样的。譬如一个静态内容区块与Views生成内容的区别是很大的。

每一个插件对外的行为是一样的(针对调用他们的代码而言),而内部实现可以有非常大的区别。只要它遵循其外部接口需要满足的条件,这些条件同时也定义了其插件类型。

什么是插件类型?

如果一些插件实现类似的功能,那么就说它们具有相同的插件类型。譬如,所有的区块都是区块类型的插件。

插件类型就像是您签订的合同,同意在某种规范下创建您的新功能,以保证插件管理器(plugin manager)知道应该如何对接您的插件,获取所需的数据或者运行某项指定操作。

插件类型控制器(或者插件管理器)决定用何种方式找到插件,并将其实例化。找到插件比较常用的方式为annotated plugin discovery。您的插件文件位置需要遵循 PSR-4标准,插件管理器负责找到插件,并且根据文件中包含的元数据注释来实例化插件。

模块除了可以为某种插件类型创建插件以外,还可以像Drupal内核那样,创建自己的插件类型,让其他模块可以增强或者扩展其功能。

为什么插件很棒?

归根到底,编写插件其实就是实现某个PHP接口。而这个过程可以很好的帮助您理解每个插件是如何工作的、您必须要编写哪些代码、还有哪些可选的操作是可以实现的。在Drupal中的每一种插件类型都必须根据其插件管理器的需要,实现一系列的需求。将这些需求以方法的形式整合到一个接口中,这样可以非常方便快速地让开发者浏览和理解某类插件的工作方式。

如果您曾经在Drupal 7的模块中实现过自定义区块,那么您应该比较熟悉在Drupal 7中使用钩子函数的方式来实现区块的功能。您可以通过实现 hook_block_info() 钩子,并且提供一些元数据,来告诉Drupal您的模块里有区块。但这还不够,您还必须实现 hook_block_view() 钩子,用来提供区块的内容。想让管理员添加一些配置选项?那么你需要实现另一个钩子来为配置表单添加元素,以及另一个钩子来保存数据。这一切都是通过某个协定来整合在一起的,您之所以知道此协定是因为有文档记录。当然,如果您已经知道这个协定,那不是一件难事,但在你第一次需要创建一个自定义区块时,找出所需要实现的所有钩子则是一件具有挑战性的事情。

想在您的模块中提供超过一个区块?那么你需要在每个钩子函数中用switch语句来区分当前正在操作的是哪个区块。

与Drupal 7的实现不同,插件将每个区块的所有操作封装到一个单独的PHP文件中。插件的元数据通过@docblock 注释的方式在插件类中提供。这可以很容易的看出来,您可以通过实现lable() 方法来返回具可读性的区块label,或者通过实现build()方法来返回区块内容,因为这些都已经定义在您需要实现的 BlockPluginInterface 接口中。很多IDE甚至可以为您找到并且自动生成相应的公有方法。这样可以让刚接触区块插件的用户更容易的理解如何实现一个区块。

对我而言,最大的优势就是插件可以将相关的代码放在同一个位置,很好的提高开发者体验。一个php文件,一个区块。并且现在有了统一的方式来实现那种 “我的模块也想提供XXX” 的场景,这在Drupal中实在是太常见了。学习插件系统,你可以知道如何为超过20个的使用插件模式的场景提供功能,而不需要每一种都要学一个新的模式。

关于Drupal 8插件的一些扩展阅读:

Drupal 版本