drupal模块_构建一个Drupal 8模块:块和形式

drupal模块

Please be aware that due to the development process Drupal 8 has been undergoing at the time of writing, some parts of the code might be outdated. Take a look at this repository in which I try to update the example code and make it work with the latest Drupal 8 release.

请注意,由于在编写本文时Drupal 8正在进行开发过程,因此某些代码部分可能已过时。 看看这个存储库 ,我尝试在其中更新示例代码并使之与最新的Drupal 8版本一起使用。

In the first installment of this article series on Drupal 8 module development we started with the basics. We’ve seen what files were needed to let Drupal know about our module, how the routing process works and how to create menu links programatically as configuration.

有关Drupal 8模块开发的本系列文章的第一部分中 ,我们从基础开始。 我们已经了解了需要什么文件来使Drupal知道我们的模块,路由过程如何工作以及如何以编程方式创建菜单链接作为配置。

In this tutorial we are going to go a bit further with our sandbox module found in this repository and look at two new important pieces of functionality: blocks and forms. To this end, we will create a custom block that returns some configurable text. After that, we will create a simple form used to print out user submitted values to the screen.

在本教程中,我们将进一步研究在此存储库中找到的沙盒模块,并研究两个新的重要功能:块和窗体。 为此,我们将创建一个自定义块,该块返回一些可配置的文本。 之后,我们将创建一个简单的表单,用于将用户提交的值打印到屏幕上。

Drupal 8块 (Drupal 8 blocks)

A cool new change to the block API in D8 has been a switch to making blocks more prominent, by making them plugins (a brand new concept). What this means is that they are reusable pieces of functionality (under the hood) as you can now create a block in the UI and reuse it across the site – you are no longer limited to using a block only one time.

D8中对Block API的一个很酷的新变化是通过使其成为插件(一种全新的概念),使块变得更加突出。 这意味着它们是可重用的功能(在后台),因为您现在可以在UI中创建一个块并在整个站点中重复使用–您不再局限于仅使用一次块。

Let’s go ahead and create a simple block type that prints to the screen Hello World! by default. All we need to work with is one class file located in the src/Plugin/Block folder of our module’s root directory. Let’s call our new block type DemoBlock, and naturally it needs to reside in a file called DemoBlock.php. Inside this file, we can start with the following:

让我们继续创建一个简单的块类型,该块类型将打印到屏幕Hello World! 默认。 我们需要处理的是一个位于我们模块根目录的src/Plugin/Block文件夹中的类文件。 我们将其称为新的块类型DemoBlock ,自然地,它需要驻留在名为DemoBlock.php的文件中。 在此文件中,我们可以从以下内容开始:

<?php

namespace Drupal\demo\Plugin\Block;

use Drupal\block\BlockBase;
use Drupal\Core\Session\AccountInterface;

/**
 * Provides a 'Demo' block.
 *
 * @Block(
 *   id = "demo_block",
 *   admin_label = @Translation("Demo block"),
 * )
 */

class DemoBlock extends BlockBase {
  
  /**
   * {@inheritdoc}
   */
  public function build() {    
    return array(
      '#markup' => $this->t('Hello World!'),
    );
  }
  
  /**
   * {@inheritdoc}
   */
  public function access(AccountInterface $account) {
    return $account->hasPermission('access content');
  }  
  
}

Like with all other class files we start by namespacing our class. Then we use the BlockBase class so that we can extend it, as well as the AccountInterface class so that we can get access to the currently logged in user. Then follows something you definitely have not seen in Drupal 7: annotations.

与所有其他类文件一样,我们从命名类开始。 然后,我们使用 BlockBase类(以便可以对其进行扩展)以及AccountInterface类(以便可以对当前登录的用户进行访问)进行扩展。 然后遵循您在Drupal 7中绝对没有看到的内容:注释。

Annotations are a PHP discovery tool located in the comment block of the same file as the class definition. Using these annotations we let Drupal know that we want to register a new block type (@Block) with the id of demo_block and the admin_label of Demo block (passed through the translation system).

注释是一个PHP发现工具,位于与类定义相同的文件的注释栏中。 使用这些注释,我们让Drupal知道我们要注册一个新的块类型( @Block ),其id为demo_blockDemo块admin_label (通过翻译系统)。

Next, we extend the BlockBase class into our own DemoBlock, inside of which we implement two methods (the most common ones you’ll implement). The build() method is the most important as it returns a renderable array the block will print out. The access() method controls access rights for viewing this block. The parameter passed to it is an instance of the AccountInterface class which will be in this case the current user.

接下来,我们将BlockBase类扩展到我们自己的DemoBlock ,在其中我们实现两种方法(您将实现的最常见的方法)。 build()方法是最重要的,因为它返回将打印出该块的可渲染数组。 access()方法控制用于查看此块的访问权限。 传递给它的参数是AccountInterface类的实例,在这种情况下,它将是当前用户。

Another interesting thing to note is that we are no longer using the t() function globally for translation but we reference the t() method implemented in the class parent.

还要注意的另一件有趣的事情是,我们不再在全局上使用t()函数进行翻译,而是引用在父类中实现的t()方法。

And that’s it, you can clear the caches and go to the Block layout configuration page. The cool thing is that you have the block types on the right (that you can filter through) and you can place one or more blocks of those types to various regions on the site.

就是这样,您可以清除缓存并转到“ Block layout配置页面。 很酷的事情是,您在右侧具有块类型(可以过滤通过),并且可以将这些类型的一个或多个块放置到站点的各个区域。

Drupal 8块配置 (Drupal 8 block configuration)

Now that we’ve seen how to create a new block type to use from the UI, let’s tap further into the API and add a configuration form for it. We will make it so that you can edit the block, specify a name in a textfield and then the block will say hello to that name rather than the world.

现在,我们已经了解了如何从UI创建新的块类型,让我们进一步进入API并为其添加配置表单。 我们将这样做,以便您可以编辑该块,在文本字段中指定一个名称,然后该块将向该名称问好,而不是world

First, we’ll need to define the form that contains our textfield. So inside our DemoBlock class we can add a new method called blockForm():

首先,我们需要定义包含文本字段的表单。 因此,在我们的DemoBlock类中,我们可以添加一个名为blockForm()的新方法:

/**
 * {@inheritdoc}
 */
public function blockForm($form, &$form_state) {
  
  $form = parent::blockForm($form, $form_state);
  
  $config = $this->getConfiguration();

  $form['demo_block_settings'] = array(
    '#type' => 'textfield',
    '#title' => $this->t('Who'),
    '#description' => $this->t('Who do you want to say hello to?'),
    '#default_value' => isset($config['demo_block_settings']) ? $config['demo_block_settings'] : '',
  );
  
  return $form;
}

This form API implementation should look very familiar from Drupal 7. There are, however, some new things going on here. First, we retrieve the $form array from the parent class (so we are building on the existing form by adding our own field). Standard OOP stuff. Then, we retrieve and store the configuration for this block. The BlockBase class defines the getConfiguration() method that does this for us. And we place the demo_block_settings value as the #default_value in case it has been set already.

在Drupal 7中,应该很熟悉这种表单API实现。但是,这里有一些新情况。 首先,我们从父类中检索$form数组(因此,我们通过添加自己的字段来构建现有表单)。 标准的OOP内容。 然后,我们检索并存储该块的配置。 BlockBase类定义了为我们执行此操作的getConfiguration()方法。 我们放置demo_block_settings值作为#default_value情况下,它已经设置。

Next, it’s time for the submit handler of this form that will process the value of our field and store it in the block’s configuration:

接下来,是时候使用该表单的提交处理程序来处理字段的值并将其存储在块的配置中了:

/**
* {@inheritdoc}
*/
public function blockSubmit($form, &$form_state) {
 
 $this->setConfigurationValue('demo_block_settings', $form_state['values']['demo_block_settings']);
 
}

This method also goes inside the DemoBlock class and all it does is save the value of the demo_block_settings field as a new item in the block’s configuration (keyed by the same name for consistency).

此方法也位于DemoBlock类内部,它所做的只是将demo_block_settings字段的值demo_block_settings为块配置中的新项(用相同的名称键以保持一致性)。

Lastly, we need to adapt our build() method to include the name to say hello to:

最后,我们需要调整build()方法,使其包含要打招呼的名称:

/**
 * {@inheritdoc}
 */
public function build() {
  
  $config = $this->getConfiguration();
  
  if (isset($config['demo_block_settings']) && !empty($config['demo_block_settings'])) {
    $name = $config['demo_block_settings'];
  }
  else {
    $name = $this->t('to no one');
  }
  
  return array(
    '#markup' => $this->t('Hello @name!', array('@name' => $name)),
  );  
}

By now, this should look fairly easy. We are retrieving the block’s configuration and if the value of our field is set, we use it for the printed statement. If not, use use a generic one. You can clear the cache and test it out by editing the block you assigned to a region and add a name to say hello to. One thing to keep in mind is that you are still responsible for sanitizing user input upon printing to the screen. I have not included these steps for brevity.

现在,这看起来应该很容易。 我们正在检索块的配置,如果设置了字段的值,则将其用于打印语句。 如果不是,请使用通用的。 您可以通过编辑分配给区域的块并添加一个名称向其打个招呼来清除缓存并进行测试。 要记住的一件事是,您仍然有责任在打印到屏幕上时清理用户输入。 为了简洁起见,我没有包括这些步骤。

Drupal 8种形式 (Drupal 8 forms)

The last thing we are going to explore in this tutorial is how to create a simple form. Due to space limitations, I will not cover the configuration management aspect of it (storing configuration values submitted through forms). Rather, I will illustrate a simple form definition, the values submitted being simply printed on the screen to show that it works.

在本教程中,我们要探讨的最后一件事是如何创建一个简单的表单。 由于篇幅所限,我将不介绍它的配置管理方面(存储通过表单提交的配置值)。 相反,我将说明一个简单的表单定义,将提交的值简单地打印在屏幕上以表明其有效。

In Drupal 8, form definition functions are all grouped together inside a class. So let’s define our simple DemoForm class inside src/Form/DemoForm.php:

在Drupal 8中,表单定义功能全部归为一个类。 因此,让我们在src/Form/DemoForm.php定义我们简单的DemoForm类:

<?php

/**
 * @file
 * Contains \Drupal\demo\Form\DemoForm.
 */

namespace Drupal\demo\Form;

use Drupal\Core\Form\FormBase;

class DemoForm extends FormBase {
  
  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'demo_form';
  }
  
  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, array &$form_state) {
    
    $form['email'] = array(
      '#type' => 'email',
      '#title' => $this->t('Your .com email address.')
    );
    $form['show'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    );
    
    return $form;
  }
  
  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, array &$form_state) {
    
    if (strpos($form_state['values']['email'], '.com') === FALSE ) {
      $this->setFormError('email', $form_state, $this->t('This is not a .com email address.'));
    } 
  }
  
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, array &$form_state) {
    
    drupal_set_message($this->t('Your email address is @email', array('@email' => $form_state['values']['email'])));
  }
  
}

Apart from the OOP side of it, everything should look very familiar to Drupal 7. The Form API has remained pretty much unchanged (except for the addition of some new form elements and this class encapsulation). So what happens above?

除了OOP方面,Drupal 7看起来应该都很熟悉。FormAPI几乎保持不变(除了添加了一些新的表单元素和此类封装)。 那么上面发生了什么?

First, we namespace the class and use the core FormBase class so we can extend it with our own DemoForm class. Then we implement 4 methods, 3 of which should look very familiar. The getFormId() method is new and mandatory, used simply to return the machine name of the form. The buildForm() method is again mandatory and it builds up the form. How? Just like you are used to from Drupal 7. The validateForm() method is optional and its purpose should also be quite clear from D7. And finally, the submitForm() method does the submission handling. Very logical and organised.

首先,我们为该类命名空间并使用核心FormBase类,以便我们可以使用自己的DemoForm类对其进行扩展。 然后我们实现4种方法,其中3种应该看起来很熟悉。 getFormId()方法是新的强制性方法,仅用于返回表单的计算机名称。 同样, buildForm()方法是强制性的,它会建立表单。 怎么样? 就像您习惯使用Drupal 7一样validateForm()方法是可选的,并且从D7开始它的用途也应该很清楚。 最后, submitForm()方法进行提交处理。 非常合乎逻辑且有条理。

So what are we trying to achieve with this form? We have an email field (a new form element in Drupal 8) we want users to fill out. By default, Drupal checks whether the value input is in fact an email address. But in our validation function we make sure it is a .com email address and if not, we set a form error on the field. Lastly, the submit handler just prints a message on the page.

那么我们想用这种形式实现什么呢? 我们有一个电子邮件字段(Drupal 8中的新表单元素),我们希望用户填写。 默认情况下,Drupal检查输入的值是否实际上是电子邮件地址。 但是,在我们的验证功能中,我们确保它是.com电子邮件地址,如果不是,则在该字段上设置表单错误。 最后,提交处理程序仅在页面上打印一条消息。

One last thing we need to do in order to use this form is provide a route for it. So edit the demo.routing.yml file and add the following:

为了使用此表单,我们需要做的最后一件事是为其提供路由。 因此,编辑demo.routing.yml文件并添加以下内容:

demo.form:
  path: '/demo/form'
  defaults:
    _form: '\Drupal\demo\Form\DemoForm'
    _title: 'Demo Form'
  requirements:
    _permission: 'access content'

This should look familiar from the previous article in which we routed a simple page. The only big difference is that instead of _content under defaults, we use _form to specify that the target is a form class. And the value is therefore the class name we just created.

上一篇我们路由了一个简单页面的文章中,这应该看起来很熟悉。 唯一的不同是,在defaults下,我们使用_form而不是_content来指定目标是表单类。 因此,该值就是我们刚刚创建的类名。

Clear the caches and navigate to demo/form to see the form and test it out.

清除缓存并导航到demo/form以查看表单并进行测试。

If you are familiar with drupal_get_form() and are wondering how to load a form like we used to in Drupal 7, the answer is in the global Drupal class. Thus to retrieve a form, you can use its formBuilder() method and do something like this:

如果您熟悉drupal_get_form() ,并且想知道如何加载与我们在Drupal 7中一样的表单,那么答案就在全局Drupal类中。 因此,要检索表单,可以使用其formBuilder()方法并执行以下操作:

$form = \Drupal::formBuilder()->getForm('Drupal\demo\Form\DemoForm');

Then you can return $form which will be the renderable array of the form.

然后,您可以返回$form ,它将是$form的可渲染数组。

结论 (Conclusion)

In this article we’ve continued our exploration of Drupal 8 module development with two new topics: blocks and forms. We’ve seen how to create our own block type we can use to create blocks in the UI. We’ve also learned how to add a custom configuration to it and store the values for later use. On the topic of forms, we’ve seen a simple implementation of the FormBase class that we used to print out to the screen the value submitted by the user.

在本文中,我们通过两个新主题(块和表单)继续了对Drupal 8模块开发的探索。 我们已经看到了如何创建自己的块类型,可用于在UI中创建块。 我们还学习了如何向其中添加自定义配置并存储值以供以后使用。 在表单的主题上,我们看到了FormBase类的简单实现,该类用于将用户提交的值打印到屏幕上。

In the next tutorial we will take a quick look at configuration forms. We will save the values submitted by the user using the Drupal 8 configuration system. Additionally, we will look at the service container and dependency injection and how those work in Drupal 8. See you then.

在下一个教程中,我们将快速浏览配置表单。 我们将使用Drupal 8配置系统保存用户提交的值。 此外,我们还将研究服务容器和依赖项注入以及它们在Drupal 8中的工作方式。

翻译自: https://www.sitepoint.com/building-drupal-8-module-blocks-forms/

drupal模块

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值