10.6 插件上下文

1、什么是上下文?

"上下文Context"这个词是什么意思呢?平常生活中它常见于语言、文字交流里面,意思是当前交流处于一个特定的环境下,依托前面的内容交流才有意义。

比如这句话:"他正在学习drupal",如果单独说是没有意义的,因为你不知道"他"指代谁,在交流中前面一定定义清楚了"他"是谁,这个"他"就是上下文,这个谁就是上下文的值。

在软件工程中,上下文是一种属性的有序序列,它们为驻留在环境内的对象定义环境。不过你无需去理会这样晦涩的定义,只需要知道"上下文"相当于"环境"就行了,它们是等价的。

假设将来能制造出真正的类人智能机器人,那么把它投放到社会中,激活那一刻,他第一件事情就是侦查环境,换句话说就是搞清楚自己所在的上下文,然后他才能有所行动。

可见上下文概念是如此重要,在脑子里面建立一个印象:有目的的行为是建立在环境之上的,万事万物皆是如此.

在Drupal 8中上下文就是指当请求到来时,系统所处的工作环境,这个环境由请求和系统设置共同构成,系统首先要搞清楚环境(上下文)才知道自己该怎么行动(正应前文所讲)。

比如缓存上下文CacheContext,就是指相对于缓存系统的环境(缓存环境是系统环境的子集),缓存系统依据此环境才能正确行动,具体实现就是缓存依据这个上下文来存放或取回正确的数据。

2、插件上下文

通常,插件上下文我们放在目录src/Plugin/Condition下。

下面例子我们实现了一个NodeType类,它的上下文是node实体,只有在node实体被调用的情况下它才生效。

core/modules/node/src/Plugin/Condition/NodeType.php代码如下:

<?php

namespace Drupal\node\Plugin\Condition;

use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a 'Node Type' condition.
 *
 * @Condition(
 *   id = "node_type",
 *   label = @Translation("Node Bundle"),
 *   context = {
 *     "node" = @ContextDefinition("entity:node", label = @Translation("Node"))
 *   }
 * )
 */
class NodeType extends ConditionPluginBase implements ContainerFactoryPluginInterface {

  /**
   * The entity storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $entityStorage;

  /**
   * Creates a new NodeType instance.
   *
   * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
   *   The entity storage.
   * @param array $configuration
   *   The plugin configuration, i.e. an array with configuration values keyed
   *   by configuration option name. The special key 'context' may be used to
   *   initialize the defined contexts by setting it to an array of context
   *   values keyed by context names.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   */
  public function __construct(EntityStorageInterface $entity_storage, array $configuration, $plugin_id, $plugin_definition) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityStorage = $entity_storage;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $container->get('entity.manager')->getStorage('node_type'),
      $configuration,
      $plugin_id,
      $plugin_definition
    );
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $options = array();
    $node_types = $this->entityStorage->loadMultiple();
    foreach ($node_types as $type) {
      $options[$type->id()] = $type->label();
    }
    $form['bundles'] = array(
      '#title' => $this->t('Node types'),
      '#type' => 'checkboxes',
      '#options' => $options,
      '#default_value' => $this->configuration['bundles'],
    );
    return parent::buildConfigurationForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    $this->configuration['bundles'] = array_filter($form_state->getValue('bundles'));
    parent::submitConfigurationForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function summary() {
    if (count($this->configuration['bundles']) > 1) {
      $bundles = $this->configuration['bundles'];
      $last = array_pop($bundles);
      $bundles = implode(', ', $bundles);
      return $this->t('The node bundle is @bundles or @last', array('@bundles' => $bundles, '@last' => $last));
    }
    $bundle = reset($this->configuration['bundles']);
    return $this->t('The node bundle is @bundle', array('@bundle' => $bundle));
  }

  /**
   * {@inheritdoc}
   */
  public function evaluate() {
    if (empty($this->configuration['bundles']) && !$this->isNegated()) {
      return TRUE;
    }
    $node = $this->getContextValue('node');
    return !empty($this->configuration['bundles'][$node->getType()]);
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return array('bundles' => array()) + parent::defaultConfiguration();
  }

}

@Condition注解解释:

  • id: 插件ID
  • label: 用户界面上显示的标签
  • context: 调用evaluate方法来检测node的类型

其他的一些键:

  • required: 指定是否为必须,默认为true
  • multiple: 指定是否有多个条件,默认为false
  • description: 上下文的描述,用于UI
  • default_value: 默认为false
  • class: 默认\Drupal\Core\Plugin\ContextDefinition类。如果你提供你自已的类,你必须实现\Drupal\Core\Plugin\Context\ContextDefinitionInterface接口。

注意:上下文定义可以不使用default_value键。

3、其他的一些示例

其他的一些示例可以在Drupal8目录下搜索到:

jerry@mac:~/Sites/drupal8 > grep "@Condition" * -R
core/modules/block/tests/modules/block_test/src/Plugin/Condition/BaloneySpam.php: * @Condition(
core/modules/block/tests/modules/block_test/src/Plugin/Condition/MissingSchema.php: * @Condition(
core/modules/language/src/Plugin/Condition/Language.php: * @Condition(
core/modules/node/src/Plugin/Condition/NodeType.php: * @Condition(
core/modules/system/src/Plugin/Condition/CurrentThemeCondition.php: * @Condition(
core/modules/system/src/Plugin/Condition/RequestPath.php: * @Condition(
core/modules/system/tests/modules/condition_test/src/Plugin/Condition/ConditionTestDualUser.php: * @Condition(
core/modules/system/tests/modules/condition_test/src/Plugin/Condition/ConditionTestNoExistingType.php: * @Condition(
core/modules/system/tests/modules/condition_test/src/Plugin/Condition/OptionalContextCondition.php: * @Condition(
core/modules/user/src/Plugin/Condition/UserRole.php: * @Condition(
modules/ctools/src/Plugin/Condition/EntityBundle.php: * @Condition(

本书共79小节:

评论 (写第一个评论)