drupal8建站教程_有效使用Drupal 8插件衍生物的教程

drupal8建站教程

In an earlier tutorial, we looked at the Drupal 8 plugin system and how to create our very own custom plugin type. We’ve seen that much of the functionality declared via _info hooks in Drupal 7 has been replaced by these plugins. Our use case was very basic and it allowed each instance of such functionality to be declared manually via a new plugin class and associated form.

先前的教程中 ,我们研究了Drupal 8插件系统以及如何创建自己的自定义插件类型。 我们已经看到,在Drupal 7中通过_info钩子声明的许多功能已被这些插件取代。 我们的用例非常基础,它允许通过新的插件类和关联的形式手动声明该功能的每个实例

Drupal 8 logo

But what if we needed such instances declared dynamically depending on some factors external to our little subsystem? For example, when declaring _info hooks in Drupal 7, we can get a list of something, loop over it and declare a new item in the returned array for each individual something. The menu system does this in order to provide a new block for each menu that either comes with Drupal core or is later created through the UI.

但是,如果我们需要根据小子系统外部的某些因素动态声明此类实例 ,该怎么办? 例如,当声明_info在Drupal 7挂钩,我们可以得到的东西在它的列表,循环和每一个人的东西返回数组中声明一个新的项目。 菜单系统执行此操作是为了为Drupal核心随附的或以后通过UI创建的每个菜单提供一个新块。

So what about Drupal 8? We’ve seen that for each plugin of a certain type we need to declare a different PHP class. To create a new block, we need a new class. To create another block, we need another class. So where would that looping we see in Drupal 7 take place? The short answer to this is: within a plugin derivative.

那么Drupal 8呢? 我们已经看到,对于每种特定类型的插件,我们需要声明一个不同PHP类。 要创建一个新的块,我们需要一个新的类。 要创建另一个块,我们需要另一个类。 那么我们在Drupal 7中看到的循环将在哪里发生? 对此的简短答案是:在插件派生类中

In this article we will explore the long answer to that and learn what derivates are and how we can use them. For the latter, we will build an example inside the demo module that can be found in this git repository and which should hopefully help us better understand what’s going on. For a slightly more complex example, the Menu system is great as it provides an individual block for each of its menus (similar to Drupal 7 but using plugins).

在本文中,我们将探讨这一问题的长答案,并了解什么是衍生品以及如何使用它们。 对于后者,我们将在此git存储库中找到的demo模块内部构建一个示例,希望该示例可以帮助我们更好地了解发生了什么。 对于稍微复杂一点的示例,Menu系统非常有用,因为它为每个菜单提供了一个单独的块(类似于Drupal 7,但使用了插件)。

What we are going to do is actually very simple. We are going to implement basic Node Block functionality by which for all the article nodes on our site we will have a block. Ridiculous? Sure. Should we be doing this for all the nodes on our site? Definitely not! But it’s a very basic implementation meant to keep things short and demonstrate the use of the plugin derivatives.

实际上,我们要做的很简单。 我们将实现基本的“节点阻止”功能,通过该功能,我们站点上所有文章节点都将拥有一个阻止。 荒谬? 当然。 我们应该对站点上的所有节点执行此操作吗? 当然不! 但这是一个非常基本的实现,旨在简化内容并演示插件派生工具的用法。

插件衍生物 (Plugin Derivatives)

Plugin derivatives are the way through which a plugin of a certain type can be represented in the system as multiple instances of itself. In other words, a plugin can reference a deriver class which is responsible for providing a list of plugin definitions that are based on the initial plugin (start from the same base definition) but have slightly different configuration or definition data. The SystemMenuBlock we referred to above is a great example. It’s a single plugin which has as many derivatives as there are menus on the site.

插件派生是某种类型的插件可以在系统中表示为自身多个实例的方式。 换句话说,插件可以引用派生类,该派生类负责提供基于初始插件的插件定义列表(从相同的基本定义开始),但配置或定义数据略有不同。 我们上面提到的SystemMenuBlock是一个很好的例子。 它是一个插件,具有与网站上的菜单一样多的派生工具。

To go a bit deeper, when a list of all the plugins of a certain type is requested, the plugin manager uses its discovery mechanism to load all the plugins of this type. If that mechanism is decorated with the DerivativeDiscoveryDecorator, the manager will be able to also retrieve derivatives. In order to do this, the derivative discovery looks for a deriver class on each plugin and, if it finds one, asks it for this list.

更深入一点,当请求某种类型的所有插件的列表时,插件管理器将使用其发现机制来加载该类型的所有插件。 如果该机制用DerivativeDiscoveryDecorator装饰,则管理器也将能够检索派生。 为了做到这一点,派生发现在每个插件上寻找一个派生类,如果找到一个派生类,则要求它提供此列表。

Plugin type managers that extend the DefaultPluginManager base class should normally have the derivative discovery mechanism decorating the default discovery (annotations). This is the most common pattern in the Drupal core plugin system: annotated discovery wrapped by derivatives.

扩展DefaultPluginManager基类的插件类型管理器通常应具有派生发现机制来装饰默认发现(注释)。 这是Drupal核心插件系统中最常见的模式:带衍生物的带注释的发现。

导数类 (The Derivative Class)

Now that we know what the role of plugin derivatives is, let’s create our first deriver class that will be used by our block plugin (which we will create in a minute).

现在我们知道插件派生类的作用是什么,让我们创建第一个派生类,该类将由我们的块插件使用(我们将在一分钟内创建)。

Inside src/Plugin/Derivative/NodeBlock.php of the demo module we have the following:

demo模块的src/Plugin/Derivative/NodeBlock.php中,我们具有以下内容:

<?php

/**
 * @file
 * Contains \Drupal\demo\Plugin\Derivative\NodeBlock.
 */

namespace Drupal\demo\Plugin\Derivative;

use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides block plugin definitions for nodes.
 *
 * @see \Drupal\demo\Plugin\Block\NodeBlock
 */
class NodeBlock extends DeriverBase implements ContainerDeriverInterface {

  /**
   * The node storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $nodeStorage;

  /**
   * Constructs new NodeBlock.
   *
   * @param \Drupal\Core\Entity\EntityStorageInterface $node_storage
   *   The node storage.
   */
  public function __construct(EntityStorageInterface $node_storage) {
    $this->nodeStorage = $node_storage;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, $base_plugin_id) {
    return new static(
      $container->get('entity.manager')->getStorage('node')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getDerivativeDefinitions($base_plugin_definition) {
    $nodes = $this->nodeStorage->loadByProperties(['type' => 'article']);
    foreach ($nodes as $node) {
      $this->derivatives[$node->id()] = $base_plugin_definition;
      $this->derivatives[$node->id()]['admin_label'] = t('Node block: ') . $node->label();
    }
    return $this->derivatives;
  }
}

All our class needs to implement is the DeriverInterface and implement its two methods. We use the ContainerDeriverInterface instead because we want to make our deriver container aware. Why? Because we use dependency injection to load Drupal’s entity manager so that we can access the Node storage (this is what the constructor and the create() method do). Additionally, our deriver class extends from the DeriverBase class because that already takes care of one of the required methods (getDerivativeDefinition()).

我们所有需要实现的类是DeriverInterface并实现其两个方法。 我们改用ContainerDeriverInterface因为我们想让派生容器知道。 为什么? 因为我们使用依赖注入来加载Drupal的实体管理器,以便我们可以访问Node存储(这是构造函数和create()方法的作用)。 另外,我们的DeriverBase类从DeriverBase类扩展而来, DeriverBase该类已经处理了一种必需的方法( getDerivativeDefinition() )。

Finally, getDerivativeDefinitions() is the method responsible for providing an array of plugin definitions that derive from the plugin which uses this class. It receives the $base_plugin_definition as an argument (the definition of the actual plugin which uses this deriver) and we use that to build up our derivative definitions. In our case, we indiscriminately load all the Article nodes and, for each of them, create a separate definition which differs only by having a different admin_label (this is a property on the Drupal\Core\Block\Annotation\Block annotation class). The array of derivatives is keyed by the ID of the derivative (in our case the Node ID which we will use later).

最后, getDerivativeDefinitions()是负责提供一系列插件定义的方法,这些定义来自使用该类的插件。 它接收$base_plugin_definition作为参数(使用此派生程序的实际插件的定义),然后使用它来构建派生定义。 在我们的例子中,我们不加选择地加载所有Article节点,并为每个节点创建一个单独的定义,该定义仅具有不同的admin_label (这是Drupal\Core\Block\Annotation\Block注释类的一个属性)才有所不同。 派生的数组由派生的ID(在我们的情况下为稍后将使用的Node ID)作为键。

A very important point we need to make here is that loading all the nodes and creating plugins out of them is never a good idea. What would be maybe interesting is to implement functionality by which individual nodes can be exposed as blocks via a checkbox or something like that.

我们需要在这里提出的非常重要的一点是,加载所有节点并从中创建插件绝不是一个好主意。 可能有趣的是实现一种功能,通过该功能,各个节点可以通过复选框或类似的方式显示为块。

块插件 (The Block Plugin)

Now that we have our deriver class, let’s create a simple block plugin that uses it to generate multiple instances of itself (one for each Article node).

现在我们有了派生类,让我们创建一个简单的块插件,使用它来生成自身的多个实例(每个Article节点一个)。

Inside src/Plugin/Block/NodeBlock.php:

里面src/Plugin/Block/NodeBlock.php

<?php

namespace Drupal\demo\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityViewBuilderInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a 'NodeBlock' block plugin.
 *
 * @Block(
 *   id = "node_block",
 *   admin_label = @Translation("Node block"),
 *   deriver = "Drupal\demo\Plugin\Derivative\NodeBlock"
 * )
 */

class NodeBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * @var EntityViewBuilderInterface.
   */
  private $viewBuilder;

  /**
   * @var NodeInterface.
   */
  private $node;

  /**
   * Creates a NodeBlock instance.
   *
   * @param array $configuration
   * @param string $plugin_id
   * @param array $plugin_definition
   * @param EntityManagerInterface $entity_manager
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->viewBuilder = $entity_manager->getViewBuilder('node');
    $this->nodeStorage = $entity_manager->getStorage('node');
    $this->node = $entity_manager->getStorage('node')->load($this->getDerivativeId());
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity.manager')
    );
  }
  
  /**
   * {@inheritdoc}
   */
  public function build() {
    if (!$this->node instanceof NodeInterface) {
      return;
    }
    $build = $this->viewBuilder->view($this->node, 'full');
    return $build;
  }
  
  /**
   * {@inheritdoc}
   */
  public function blockAccess(AccountInterface $account, $return_as_object = FALSE) {
    return $this->node->access('view', NULL, TRUE);
  }
}

The first thing we notice in this plugin’s annotation is the deriver key which points to the class we created before. And that is basically all we need to couple the two. The derivative discovery decorator handles the heavy lifting.

我们在此插件的注释中注意到的第一件事是deriver密钥,它指向我们之前创建的类。 这基本上就是我们将两者结合在一起所需要的。 派生发现装饰器处理繁重的工作。

Much of the rest is basic block building we should be familiar with. What’s interesting is that we can use the getDerivativeId() method to retrieve the node ID we used also as the ID of the derivative being displayed and, using that, we load the node object and build the block as the actual node output. Lastly, inside the blockAccess() method we make sure that this block has the same access checks as the actual node itself. So if the current user doesn’t have access to view the current node, the block won’t even show up.

其余的大部分是我们应该熟悉的基本构建块。 有趣的是,我们可以使用getDerivativeId()方法检索还用作显示的派生ID的节点ID,然后使用它加载节点对象并构建块作为实际的节点输出。 最后,在blockAccess()方法内部,我们确保该块具有与实际节点本身相同的访问检查。 因此,如果当前用户无权查看当前节点,则该阻止甚至不会显示。

Now if we clear the caches and navigate to the Block Layout interface we should see some blocks called Node Block: [Node title]. You can place these where you want and they will render the relevant node.

现在,如果我们清除缓存并导航到“块布局”界面,我们应该看到一些名为Node Block: [Node title] 。 您可以将它们放置在所需的位置,它们将呈现相关的节点。

结论 (Conclusion)

In this article, we’ve looked at plugin derivatives and seen a simple example of how they work. The key take away on this topic is that plugin derivatives are the way we dynamically declare multiple instances of the same plugin. They usually help us transform user configured functionality (e.g. menus) into plugins (e.g. menu blocks).

在本文中,我们研究了插件派生工具,并看到了它们如何工作的简单示例。 该主题的主要意义在于,插件派生是我们动态声明同一插件的多个实例的方式。 它们通常可以帮助我们将用户配置的功能(例如菜单)转换为插件(例如菜单块)。

To illustrate the use of derivatives, we’ve seen a very simple technique which allows us to render Article nodes as blocks. We should remember though not to try this out on a website with many Article nodes but rather implement additional functionality that limits the number of nodes that get exposed. You know, so we don’t crash our site.

为了说明派生类的用法,我们已经看到了一种非常简单的技术,该技术允许我们将Article节点呈现为块。 我们应该记住,尽管不要在具有许多Article节点的网站上进行尝试,而应该实施其他功能来限制暴露的节点数量。 您知道的,所以我们不会崩溃我们的网站。

Questions? Comments? Anything you’d like explained further? Let us know!

有什么问题吗 注释? 您想要进一步解释吗? 让我们知道!

翻译自: https://www.sitepoint.com/tutorial-on-using-drupal-8-plugin-derivatives-effectively/

drupal8建站教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值