class NavigationLinkBlock
Defines a link navigation block.
@internal
Attributes
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements \Drupal\Component\Plugin\PluginInspectionInterface, \Drupal\Component\Plugin\DerivativeInspectionInterface- class \Drupal\Core\Plugin\PluginBase uses \Drupal\Core\DependencyInjection\AutowiredInstanceTrait, \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait extends \Drupal\Component\Plugin\PluginBase- class \Drupal\Core\Block\BlockBase implements \Drupal\Core\Block\BlockPluginInterface, \Drupal\Core\Plugin\PluginWithFormsInterface, \Drupal\Core\Plugin\PreviewAwarePluginInterface, \Drupal\Core\Render\PreviewFallbackInterface, \Drupal\Core\Plugin\ContextAwarePluginInterface uses \Drupal\Core\Block\BlockPluginTrait, \Drupal\Core\Plugin\ContextAwarePluginTrait, \Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait extends \Drupal\Core\Plugin\PluginBase- class \Drupal\navigation\Plugin\Block\NavigationLinkBlock extends \Drupal\Core\Block\BlockBase
 
 
- class \Drupal\Core\Block\BlockBase implements \Drupal\Core\Block\BlockPluginInterface, \Drupal\Core\Plugin\PluginWithFormsInterface, \Drupal\Core\Plugin\PreviewAwarePluginInterface, \Drupal\Core\Render\PreviewFallbackInterface, \Drupal\Core\Plugin\ContextAwarePluginInterface uses \Drupal\Core\Block\BlockPluginTrait, \Drupal\Core\Plugin\ContextAwarePluginTrait, \Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait extends \Drupal\Core\Plugin\PluginBase
 
- class \Drupal\Core\Plugin\PluginBase uses \Drupal\Core\DependencyInjection\AutowiredInstanceTrait, \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait extends \Drupal\Component\Plugin\PluginBase
Expanded class hierarchy of NavigationLinkBlock
File
- 
              core/modules/ navigation/ src/ Plugin/ Block/ NavigationLinkBlock.php, line 20 
Namespace
Drupal\navigation\Plugin\BlockView source
final class NavigationLinkBlock extends BlockBase {
  
  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() : array {
    return [
      'title' => '',
      'uri' => '',
      'icon_class' => '',
    ];
  }
  
  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) : array {
    $config = $this->configuration;
    $display_uri = NULL;
    if (!empty($config['uri'])) {
      try {
        // The current field value could have been entered by a different user.
        // However, if it is inaccessible to the current user, do not display it
        // to them.
        $url = Url::fromUri($config['uri']);
        if (\Drupal::currentUser()->hasPermission('link to any page') || $url->access()) {
          $display_uri = static::getUriAsDisplayableString($config['uri']);
        }
      } catch (\InvalidArgumentException) {
        // If $item->uri is invalid, show value as is, so the user can see what
        // to edit.
        $display_uri = $config['uri'];
      }
    }
    // @todo Logic related to the uri component has been borrowed from
    //   Drupal\link\Plugin\Field\FieldWidget\LinkWidget.
    //   Will be fixed in https://www.drupal.org/project/drupal/issues/3450518.
    $form['uri'] = [
      '#type' => 'entity_autocomplete',
      '#title' => $this->t('URL'),
      '#default_value' => $display_uri,
      '#element_validate' => [
        [
          static::class,
          'validateUriElement',
        ],
      ],
      '#attributes' => [
        'data-autocomplete-first-character-denylist' => '/#?',
      ],
      // @todo The user should be able to select an entity type. Will be fixed
      //   in https://www.drupal.org/node/2423093.
'#target_type' => 'node',
      '#maxlength' => 2048,
      '#required' => TRUE,
      '#process_default_value' => FALSE,
    ];
    $form['title'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Link text'),
      '#default_value' => $config['title'],
      '#required' => TRUE,
      '#maxlength' => 255,
    ];
    $form['icon_class'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Icon CSS class'),
      '#default_value' => $config['icon_class'],
      '#element_validate' => [
        [
          static::class,
          'validateIconClassElement',
        ],
      ],
      '#required' => TRUE,
      '#maxlength' => 64,
    ];
    return $form;
  }
  
  /**
   * Form element validation handler for the 'icon_class' element.
   *
   * Disallows saving invalid class values.
   */
  public static function validateIconClassElement(array $element, FormStateInterface $form_state, array $form) : void {
    $icon = $element['#value'];
    if (!preg_match('/^[a-z0-9_-]+$/', $icon)) {
      $form_state->setError($element, t('The machine-readable name must contain only lowercase letters, numbers, underscores and hyphens.'));
    }
  }
  
  /**
   * Form element validation handler for the 'uri' element.
   *
   * Disallows saving inaccessible or untrusted URLs.
   */
  public static function validateUriElement($element, FormStateInterface $form_state, $form) : void {
    $uri = static::getUserEnteredStringAsUri($element['#value']);
    $form_state->setValueForElement($element, $uri);
    // If getUserEnteredStringAsUri() mapped the entered value to an 'internal:'
    // URI , ensure the raw value begins with '/', '?' or '#'.
    // @todo '<front>' is valid input for BC reasons, may be removed by
    //   https://www.drupal.org/node/2421941
    if (parse_url($uri, PHP_URL_SCHEME) === 'internal' && !in_array($element['#value'][0], [
      '/',
      '?',
      '#',
    ], TRUE) && !str_starts_with($element['#value'], '<front>')) {
      $form_state->setError($element, new TranslatableMarkup('Manually entered paths should start with one of the following characters: / ? #'));
      return;
    }
  }
  
  /**
   * Gets the user-entered string as a URI.
   *
   * The following two forms of input are mapped to URIs:
   * - entity autocomplete ("label (entity id)") strings: to 'entity:' URIs;
   * - strings without a detectable scheme: to 'internal:' URIs.
   *
   * This method is the inverse of ::getUriAsDisplayableString().
   *
   * @param string $string
   *   The user-entered string.
   *
   * @return string
   *   The URI, if a non-empty $uri was passed.
   *
   * @see static::getUriAsDisplayableString()
   */
  protected static function getUserEnteredStringAsUri($string) : string {
    // By default, assume the entered string is a URI.
    $uri = trim($string);
    // Detect entity autocomplete string, map to 'entity:' URI.
    $entity_id = EntityAutocomplete::extractEntityIdFromAutocompleteInput($string);
    if ($entity_id !== NULL) {
      // @todo Support entity types other than 'node'. Will be fixed in
      //   https://www.drupal.org/node/2423093.
      $uri = 'entity:node/' . $entity_id;
    }
    elseif (in_array($string, [
      '<nolink>',
      '<none>',
      '<button>',
    ], TRUE)) {
      $uri = 'route:' . $string;
    }
    elseif (!empty($string) && parse_url($string, PHP_URL_SCHEME) === NULL) {
      // @todo '<front>' is valid input for BC reasons, may be removed by
      //   https://www.drupal.org/node/2421941
      // - '<front>' -> '/'
      // - '<front>#foo' -> '/#foo'
      if (str_starts_with($string, '<front>')) {
        $string = '/' . substr($string, strlen('<front>'));
      }
      $uri = 'internal:' . $string;
    }
    return $uri;
  }
  
  /**
   * Gets the URI without the 'internal:' or 'entity:' scheme.
   *
   * The following two forms of URIs are transformed:
   * - 'entity:' URIs: to entity autocomplete ("label (entity id)") strings;
   * - 'internal:' URIs: the scheme is stripped.
   *
   * This method is the inverse of ::getUserEnteredStringAsUri().
   *
   * @param string $uri
   *   The URI to get the displayable string for.
   *
   * @return string
   *   The displayable string for the URI.
   *
   * @see static::getUserEnteredStringAsUri()
   */
  protected static function getUriAsDisplayableString($uri) : string {
    $scheme = parse_url($uri, PHP_URL_SCHEME);
    // By default, the displayable string is the URI.
    $displayable_string = $uri;
    // A different displayable string may be chosen in case of the 'internal:'
    // or 'entity:' built-in schemes.
    if ($scheme === 'internal') {
      $uri_reference = explode(':', $uri, 2)[1];
      // @todo '<front>' is valid input for BC reasons, may be removed by
      //   https://www.drupal.org/node/2421941
      $path = parse_url($uri, PHP_URL_PATH);
      if ($path === '/') {
        $uri_reference = '<front>' . substr($uri_reference, 1);
      }
      $displayable_string = $uri_reference;
    }
    elseif ($scheme === 'entity') {
      [$entity_type, $entity_id] = explode('/', substr($uri, 7), 2);
      // Show the 'entity:' URI as the entity autocomplete would.
      // @todo Support entity types other than 'node'. Will be fixed in
      //   https://www.drupal.org/node/2423093.
      if ($entity_type == 'node' && $entity = \Drupal::entityTypeManager()->getStorage($entity_type)
        ->load($entity_id)) {
        $displayable_string = EntityAutocomplete::getEntityLabels([
          $entity,
        ]);
      }
    }
    elseif ($scheme === 'route') {
      $displayable_string = ltrim($displayable_string, 'route:');
    }
    return $displayable_string;
  }
  
  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) : void {
    $this->configuration['uri'] = $form_state->getValue('uri');
    $this->configuration['title'] = $form_state->getValue('title');
    $this->configuration['icon_class'] = $form_state->getValue('icon_class');
  }
  
  /**
   * {@inheritdoc}
   */
  public function build() : array {
    $config = $this->configuration;
    $build = [];
    // Ensure that user has access to link before rendering it.
    try {
      $url = Url::fromUri($config['uri']);
      // Internal routes must exist.
      if (!$url->isExternal() && !$url->isRouted()) {
        return $build;
      }
      $access = $url->access(NULL, TRUE);
      if (!$access->isAllowed()) {
        // Cacheable dependency is explicitly added when access is not granted.
        // It is bubbled when the link is rendered.
        $cacheable_metadata = new CacheableMetadata();
        $cacheable_metadata->addCacheableDependency($access);
        $cacheable_metadata->applyTo($build);
        return $build;
      }
    } catch (\InvalidArgumentException) {
      return $build;
    }
    return $build + [
      '#title' => $config['label'],
      '#theme' => 'navigation_menu',
      '#menu_name' => 'link',
      '#items' => [
        [
          'title' => $config['title'],
          'class' => $config['icon_class'],
          'url' => $url,
          'icon' => [
            'icon_id' => $config['icon_class'],
          ],
        ],
      ],
    ];
  }
}Members
| Title Sort descending | Deprecated | Modifiers | Object type | Summary | Member alias | Overriden Title | Overrides | 
|---|---|---|---|---|---|---|---|
| AutowiredInstanceTrait::createInstanceAutowired | public static | function | Instantiates a new instance of the implementing class using autowiring. | ||||
| BlockBase::buildConfigurationForm | public | function | Form constructor. | Overrides PluginFormInterface::buildConfigurationForm | 2 | ||
| BlockBase::submitConfigurationForm | public | function | Form submission handler. | Overrides PluginFormInterface::submitConfigurationForm | |||
| BlockPluginInterface::BLOCK_LABEL_VISIBLE | constant | Indicates the block label (title) should be displayed to end users. | |||||
| BlockPluginTrait::$inPreview | protected | property | Whether the plugin is being rendered in preview mode. | ||||
| BlockPluginTrait::$transliteration | protected | property | The transliteration service. | ||||
| BlockPluginTrait::access | public | function | |||||
| BlockPluginTrait::baseConfigurationDefaults | protected | function | Returns generic default configuration for block plugins. | ||||
| BlockPluginTrait::blockAccess | protected | function | Indicates whether the block should be shown. | 17 | |||
| BlockPluginTrait::blockValidate | public | function | 3 | ||||
| BlockPluginTrait::buildConfigurationForm | public | function | Creates a generic configuration form for all block types. Individual block plugins can add elements to this form by overriding BlockBase::blockForm(). Most block plugins should not override this method unless they need to alter the generic form elements. | Aliased as: traitBuildConfigurationForm | |||
| BlockPluginTrait::calculateDependencies | public | function | 1 | ||||
| BlockPluginTrait::createPlaceholder | public | function | 7 | ||||
| BlockPluginTrait::getConfiguration | public | function | 1 | ||||
| BlockPluginTrait::getMachineNameSuggestion | public | function | 1 | ||||
| BlockPluginTrait::getPreviewFallbackString | public | function | 3 | ||||
| BlockPluginTrait::label | public | function | |||||
| BlockPluginTrait::setConfiguration | public | function | |||||
| BlockPluginTrait::setConfigurationValue | public | function | |||||
| BlockPluginTrait::setInPreview | public | function | |||||
| BlockPluginTrait::setTransliteration | public | function | Sets the transliteration service. | ||||
| BlockPluginTrait::submitConfigurationForm | public | function | Most block plugins should not override this method. To add submission handling for a specific block type, override BlockBase::blockSubmit(). | Aliased as: traitSubmitConfigurationForm | |||
| BlockPluginTrait::transliteration | protected | function | Wraps the transliteration service. | ||||
| BlockPluginTrait::validateConfigurationForm | public | function | Most block plugins should not override this method. To add validation for a specific block type, override BlockBase::blockValidate(). | 1 | |||
| BlockPluginTrait::__construct | public | function | 26 | ||||
| ContextAwarePluginAssignmentTrait::addContextAssignmentElement | protected | function | Builds a form element for assigning a context to a given slot. | ||||
| ContextAwarePluginAssignmentTrait::contextHandler | protected | function | Wraps the context handler. | ||||
| ContextAwarePluginTrait::$context | protected | property | The data objects representing the context of this plugin. | ||||
| ContextAwarePluginTrait::getCacheContexts | public | function | 9 | ||||
| ContextAwarePluginTrait::getCacheMaxAge | public | function | 6 | ||||
| ContextAwarePluginTrait::getCacheTags | public | function | 3 | ||||
| ContextAwarePluginTrait::getContext | public | function | |||||
| ContextAwarePluginTrait::getContextDefinition | public | function | |||||
| ContextAwarePluginTrait::getContextDefinitions | public | function | |||||
| ContextAwarePluginTrait::getContextMapping | public | function | 1 | ||||
| ContextAwarePluginTrait::getContexts | public | function | |||||
| ContextAwarePluginTrait::getContextValue | public | function | |||||
| ContextAwarePluginTrait::getContextValues | public | function | |||||
| ContextAwarePluginTrait::getPluginDefinition | abstract public | function | 1 | ||||
| ContextAwarePluginTrait::setContext | public | function | 1 | ||||
| ContextAwarePluginTrait::setContextMapping | public | function | |||||
| ContextAwarePluginTrait::setContextValue | public | function | |||||
| ContextAwarePluginTrait::validateContexts | public | function | |||||
| DependencySerializationTrait::$_entityStorages | protected | property | An array of entity type IDs keyed by the property name of their storages. | ||||
| DependencySerializationTrait::$_serviceIds | protected | property | An array of service IDs keyed by property name used for serialization. | ||||
| DependencySerializationTrait::__sleep | public | function | 2 | ||||
| DependencySerializationTrait::__wakeup | public | function | 2 | ||||
| MessengerTrait::$messenger | protected | property | The messenger. | 25 | |||
| MessengerTrait::messenger | public | function | Gets the messenger. | 25 | |||
| MessengerTrait::setMessenger | public | function | Sets the messenger. | ||||
| NavigationLinkBlock::blockForm | public | function | Overrides BlockPluginTrait::blockForm | ||||
| NavigationLinkBlock::blockSubmit | public | function | Overrides BlockPluginTrait::blockSubmit | ||||
| NavigationLinkBlock::build | public | function | Builds and returns the renderable array for this block plugin. | Overrides BlockPluginInterface::build | |||
| NavigationLinkBlock::defaultConfiguration | public | function | Overrides BlockPluginTrait::defaultConfiguration | ||||
| NavigationLinkBlock::getUriAsDisplayableString | protected static | function | Gets the URI without the 'internal:' or 'entity:' scheme. | ||||
| NavigationLinkBlock::getUserEnteredStringAsUri | protected static | function | Gets the user-entered string as a URI. | ||||
| NavigationLinkBlock::validateIconClassElement | public static | function | Form element validation handler for the 'icon_class' element. | ||||
| NavigationLinkBlock::validateUriElement | public static | function | Form element validation handler for the 'uri' element. | ||||
| PluginBase::$configuration | protected | property | Configuration information passed into the plugin. | 1 | |||
| PluginBase::$pluginDefinition | protected | property | The plugin implementation definition. | 1 | |||
| PluginBase::$pluginId | protected | property | The plugin ID. | ||||
| PluginBase::create | public static | function | Instantiates a new instance of the implementing class using autowiring. | 165 | |||
| PluginBase::DERIVATIVE_SEPARATOR | constant | A string which is used to separate base plugin IDs from the derivative ID. | |||||
| PluginBase::getBaseId | public | function | Gets the base_plugin_id of the plugin instance. | Overrides DerivativeInspectionInterface::getBaseId | |||
| PluginBase::getDerivativeId | public | function | Gets the derivative_id of the plugin instance. | Overrides DerivativeInspectionInterface::getDerivativeId | |||
| PluginBase::getPluginId | public | function | Gets the plugin ID of the plugin instance. | Overrides PluginInspectionInterface::getPluginId | |||
| PluginBase::isConfigurable | Deprecated | public | function | Determines if the plugin is configurable. | |||
| PluginWithFormsTrait::getFormClass | public | function | Implements \Drupal\Core\Plugin\PluginWithFormsInterface::getFormClass(). | ||||
| PluginWithFormsTrait::hasFormClass | public | function | Implements \Drupal\Core\Plugin\PluginWithFormsInterface::hasFormClass(). | ||||
| StringTranslationTrait::$stringTranslation | protected | property | The string translation service. | 3 | |||
| StringTranslationTrait::formatPlural | protected | function | Formats a string containing a count of items. | ||||
| StringTranslationTrait::getNumberOfPlurals | protected | function | Returns the number of plurals supported by a given language. | ||||
| StringTranslationTrait::getStringTranslation | protected | function | Gets the string translation service. | ||||
| StringTranslationTrait::setStringTranslation | public | function | Sets the string translation service to use. | 2 | |||
| StringTranslationTrait::t | protected | function | Translates a string to the current language or to a given language. | 1 | 
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.
