核心要点
ConfigFormBase
类提供了额外的功能来与配置系统交互,允许将表单转换为存储值的工具。这可以通过用 ConfigFormBase
替换扩展类并在表单中进行必要的更改来实现。Drupal 8 中的配置存储在 YAML 文件中,可以通过 UI 进行更改,以便跨不同站点部署。demo.services.yml
文件来注册服务。ControllerBase
类或实现 ContainerInjectionInterface
来实现。还可以使用 Drupal
类全局访问服务。请注意,由于撰写本文时 Drupal 8 正在进行开发过程,因此某些代码部分可能已过时。请查看此存储库,我尝试更新示例代码并使其与最新的 Drupal 8 版本兼容。
在之前的关于 Drupal 8 模块开发的文章中,我们研究了创建块类型和表单。我们已经看到块现在是可重用的,以及定义块类型所需的一切都在一个类中完成。类似地,表单生成函数也分组在一个类中,其中特定方法执行的任务类似于我们在 Drupal 7 中习惯的任务。
在本教程中,我将从我们上次结束的地方继续。我将说明如何将我们的 DemoForm
转换为用于通过 Drupal 8 配置系统存储值的表单。之后,我们将通过示例说明服务容器和依赖注入。
别忘了,如果您想获取本教程系列中编写的全部代码,可以查看此存储库。
配置表单
当我们第一次定义 DemoForm
时,我们扩展了 FormBase
类,这是 FormInterface
的最简单实现。但是,Drupal 8 还附带了一个 ConfigFormBase
,它提供了一些附加功能,使与配置系统交互变得非常容易。
我们现在要做的是将 DemoForm
转换为一个用于存储用户输入的电子邮件地址的表单。我们应该做的第一件事是用 ConfigFormBase
替换扩展类(当然还要 use
它):
<code class="language-php">use Drupal\Core\Form\ConfigFormBase; class DemoForm extends ConfigFormBase {</code>
在我们继续更改表单中的其他内容之前,让我们了解一下 Drupal 8 中的简单配置是如何工作的。我说“简单”,因为还有更复杂的配置实体,我们今天不会介绍。就目前而言,模块(核心或 contrib)提供的配置存储在 YAML 文件中。启用模块后,此数据将导入到数据库中(以便在使用时提高性能)。通过 UI,我们可以更改此配置,然后可以轻松地将其导出到 YAML 文件中,以便跨不同站点部署。
模块可以在模块根目录的 config/install
文件夹中提供一个 YAML 文件中的默认配置。此文件的命名约定是在其前面加上模块的名称。因此,让我们创建一个名为 demo.settings.yml
的文件。在这个文件中,让我们粘贴以下内容:
<code class="language-yaml">demo: email_address: demo@demo.com</code>
这是一个嵌套结构(就像 PHP 中的关联数组)。在 demo
键下,我们有另一个键值对。通常,要访问这些嵌套值,我们使用点 (.)。在我们的例子中是 demo.email_address
。
一旦我们有了这个文件,你需要记住的一件重要事情是,只有在安装模块时才会导入此文件。因此,继续重新安装它。现在我们可以回到我们的表单并逐一查看需要调整的方法。
这就是 buildForm()
方法现在的样子:
<code class="language-php">public function buildForm(array $form, array &$form_state) { $form = parent::buildForm($form, $form_state); $config = $this->config('demo.settings'); $form['email'] = array( '#type' => 'email', '#title' => $this->t('Your .com email address.'), '#default_value' => $config->get('demo.email_address') ); return $form; }</code>
首先,与 FormBase
相反,ConfigFormBase
类也实现了此方法,以便向表单数组(提交按钮)添加元素。因此,在添加我们自己的元素之前,我们可以使用父类之前所做的操作。
现在对于配置部分。Drupal 8 提供了一个 Config
对象,我们可以用它来与配置交互。某些类已经通过依赖注入获得了它。ConfigFormBase
就是这样一个类。
如您所见,我们正在使用父类的 config()
方法来检索一个 Config
对象,该对象已填充我们的 demo.settings
简单配置。然后,对于电子邮件表单元素的 #default_value
,我们使用 Config
对象的 get()
方法来检索电子邮件地址的值。
接下来,我们只需要更改提交处理程序,因为 validateForm()
方法现在可以保持不变:
<code class="language-php">public function submitForm(array &$form, array &$form_state) { $config = $this->config('demo.settings'); $config->set('demo.email_address', $form_state['values']['email']); $config->save(); return parent::submitForm($form, $form_state); }</code>
在此方法中,我们首先检索我们配置的 Config
对象(就像我们之前做的那样)。然后,我们使用它的 set()
方法将 email_address
的值更改为用户提交的值。然后我们使用 save()
方法保存配置。最后,我们扩展了父提交处理程序,因为它确实包含一些功能(在这种情况下,它会将 Drupal 消息设置为屏幕)。
就是这样。您可以清除缓存并试一试。通过提交一个新的电子邮件地址,您将其存储在配置中。demo.settings.yml
文件当然不会更改,但是您可以去导出 demo.settings
配置并将其导入到另一个站点。
服务容器和依赖注入
接下来我们要看的是服务容器。服务背后的理念是将功能分解成可重用的组件。因此,服务是一个执行某些全局操作并注册到服务容器以便访问的 PHP 类。
依赖注入是我们传递对象以确保解耦的方式。每个服务都需要处理一件事情,如果它需要另一个服务,则后者可以注入到前者中。但我们马上就会看到如何操作。
接下来,我们将创建一个非常简单的服务并将其注册到容器中。它只有一个真正的返回简单值的方法。然后,我们将该服务作为依赖项注入到我们的 DemoController
中并使用服务提供的值。
为了注册服务,我们需要创建一个位于模块根目录的 demo.services.yml
文件,其内容如下:
<code class="language-php">use Drupal\Core\Form\ConfigFormBase; class DemoForm extends ConfigFormBase {</code>
文件命名约定是 module_name.services.yml
。
第一行创建了一个服务数组。第二行定义了第一个服务(称为 demo_service
,以模块名称为前缀)。第三行指定将为此服务实例化的类。接下来是在我们模块的 src/
文件夹中创建 DemoService.php
类文件。这就是我的服务所做的(实际上什么也没有,只是为了说明如何使用它):
<code class="language-yaml">demo: email_address: demo@demo.com</code>
这里不需要解释任何内容,因为它非常基础。接下来,让我们转向我们的 DemoController
并使用此服务。我们可以通过两种方式做到这一点:通过 Drupal
类全局访问容器或使用依赖注入将此类的对象传递给我们的控制器。最佳实践建议我们应该采用第二种方式,所以这就是我们将要做的。但有时您需要全局访问服务。为此,您可以执行以下操作:
<code class="language-php">public function buildForm(array $form, array &$form_state) { $form = parent::buildForm($form, $form_state); $config = $this->config('demo.settings'); $form['email'] = array( '#type' => 'email', '#title' => $this->t('Your .com email address.'), '#default_value' => $config->get('demo.email_address') ); return $form; }</code>
现在 $service
是我们刚刚创建的 DemoService
类的对象。但是让我们看看如何在 DemoController
类中将我们的服务作为依赖项注入。我将首先解释需要做什么,然后您将看到包含所有对其进行的更改的完整控制器。
首先,我们需要访问服务容器。对于控制器来说,这非常容易。我们可以扩展 ControllerBase
类,这除了其他一些帮助程序之外还给我们提供了这一点。或者,我们的控制器可以实现 ContainerInjectionInterface
,这也可以让我们访问容器。但是我们将坚持使用 ControllerBase
,因此我们需要 use
该类。
接下来,我们需要 use
Symfony 2 ContainerInterface
作为 create()
方法的要求,该方法实例化控制器的另一个对象并将我们想要的服务传递给它。
最后,我们将需要一个构造函数来获取传递的服务对象(create()
返回的对象)并将它们分配给属性以供以后使用。create()
方法返回对象的顺序需要反映它们传递给构造函数的顺序。
因此,让我们看看我们修改后的 DemoController
:
<code class="language-php">use Drupal\Core\Form\ConfigFormBase; class DemoForm extends ConfigFormBase {</code>
如您所见,所有步骤都在这里。create()
方法创建了我们控制器类的新实例,并将从容器检索的服务传递给它。最后,DemoService
类的实例存储在 $demoService
属性中,我们可以使用它来调用其 getDemoValue()
方法。然后,此值将用于“Hello”消息中。清除缓存并试一试。转到 demo/
路径,您应该看到页面上打印的“Hello Upchuk!”。
我相信您可以看到服务容器的强大功能,因为我们现在可以编写解耦的功能并将其传递到需要的地方。我没有向您展示如何操作,但是您也可以在注册服务时声明依赖项。这意味着当 Drupal 实例化服务对象时,它也将为其所有依赖项这样做,并将它们传递给其构造函数。您可以在此文档页面上阅读有关如何执行此操作的更多信息。
结论
在本文中,我们研究了很多很酷的东西。我们已经看到了配置系统如何管理简单的配置以及为此提供的哪些“表单”功能。我鼓励您探索 ConfigFormBase
的实现方式以及扩展它时可用的功能。此外,您应该在 UI 中使用在站点之间导入/导出配置进行练习。从现在开始,这将是对部署过程的一大改进。
然后,我们研究了服务、它们是什么以及它们如何工作。一种维护可重用且解耦的功能块的好方法,这些功能块可从任何地方访问。我希望依赖注入的概念不再那么可怕(如果它对您来说是的话)。它基本上等同于将参数传递给过程函数,但由 Symfony 及其强大的服务容器在幕后使用构造函数方法(或 setter)完成。
关于构建 Drupal 8 模块的常见问题:配置管理和服务容器
Drupal 8 中的服务容器是一个关键组件,用于管理服务的创建,服务是在 Drupal 应用程序中全局使用的对象。它确保每个服务只实例化一次,从而节省内存并提高性能。服务容器还处理依赖注入,这是一种设计模式,允许一个对象提供另一个对象的依赖项。这使代码更模块化、更易于测试并促进更好的组织。
要在 Drupal 8 中定义新服务,您需要在模块的根目录中创建一个 services.yml
文件。此文件应包含服务的名称、类和参数。该类应是实现服务的类的完全限定名称,参数应为服务所依赖的任何服务或参数。
Drupal 8 中的配置管理是一个系统,允许您以一致的方式管理站点配置数据。它使您可以导入、导出和同步配置数据,这在将配置更改从开发环境移动到生产站点时非常有用。它还提供了一种跟踪和管理站点配置随时间推移的变化的方法。
要在 Drupal 8 中导出配置数据,您可以使用管理面板中的配置管理界面或使用 Drush 命令。导出的数据将采用 YAML 格式,可以轻松读取和编辑。要导入配置数据,您可以通过配置管理界面上传导出的 YAML 文件或使用 Drush 命令。请记住,在导入配置数据之前备份您的站点,以防止任何潜在的数据丢失。
依赖注入是一种设计模式,允许一个对象提供另一个对象的依赖项。在 Drupal 8 中,它用于使服务和控制器更模块化且更易于测试。不是在对象内部创建依赖项,而是通过构造函数或 setter 方法传递(注入)它们。这使代码更易于测试、更灵活且耦合度更低。
要在 Drupal 8 中的服务中注入依赖项,您需要在 services.yml
文件中服务的定义中定义它们。依赖项应列在 arguments
键下。创建服务时,服务容器将自动将这些依赖项传递给服务的构造函数。
在 Drupal 8 中,服务是一个执行应用程序中全局任务的对象,而插件是一个以可插入方式执行特定任务的对象。服务在 services.yml
文件中定义,并由服务容器管理,而插件由插件管理器发现和实例化。
要在 Drupal 8 中覆盖服务,您需要在模块的 services.yml
文件中定义一个与要覆盖的服务同名的服务。您的新服务应扩展原始服务的类并覆盖要更改的方法。
Drupal 8 中的配置管理系统提供了一种通过配置快照系统跟踪站点配置更改的方法。每当您导入或同步配置数据时,此系统都会对站点的活动配置进行快照。然后,您可以比较这些快照以查看进行了哪些更改。
services.yml
文件在 Drupal 8 中的作用是什么?Drupal 8 中的 services.yml
文件是定义模块服务的场所。每个服务都使用唯一的名称、实现服务的类的完全限定名称以及服务所依赖的任何服务或参数来定义。services.yml
文件由服务容器读取,服务容器管理服务的创建和注入。
以上是Drupal 8模块 - 配置管理和服务容器的详细内容。更多信息请关注PHP中文网其他相关文章!