g2-8.x-1.x-dev/src/Plugin/Block/WotdBlock.php

src/Plugin/Block/WotdBlock.php
<?php

declare(strict_types=1);

namespace Drupal\g2\Plugin\Block;

use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Path\PathValidatorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Drupal\g2\G2;
use Drupal\g2\WOTD;
use Drupal\views\Entity\View;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class Wotd is the Word of the Day plugin.
 *
 * @Block(
 *   id = "g2_wotd",
 *   admin_label = @Translation("G2 Word of the day"),
 *   category = @Translation("G2"),
 *   help = @Translation("This block displays a once-a-day entry from the G2 glossary."),
 * )
 *
 * @state g2.wotd.date
 * @state g2.wotd.entry
 * @phpstan-consistent-constructor
 */
class WotdBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * The block setting controlling the RSS feed icon presence.
   */
  const FEED_SETTING = 'feed_icon';

  const ICON_CLASS = 'g2-feed-icon';

  /**
   * The entity_type.manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $etm;

  /**
   * The core path.validator service.
   *
   * @var \Drupal\Core\Path\PathValidatorInterface
   */
  protected PathValidatorInterface $pathValidator;

  /**
   * The g2.wotd service.
   *
   * @var \Drupal\g2\WOTD
   */
  protected WOTD $wotd;

  /**
   * Static factory.
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The container.
   * @param array<string,mixed> $configuration
   *   The plugin configuration.
   * @param string $plugin_id
   *   The plugin ID.
   * @param array<string,mixed> $plugin_definition
   *   The plugin definition.
   *
   * @return static
   *   The plugin instance.
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ): static {
    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $etm */
    $etm = $container->get(G2::SVC_ETM);
    /** @var \Drupal\Core\Path\PathValidatorInterface $pv */
    $pv = $container->get('path.validator');
    /** @var \Drupal\g2\WOTD $wotd */
    $wotd = $container->get(G2::SVC_WOTD);
    return new static($configuration, $plugin_id, $plugin_definition,
      $etm, $pv, $wotd,
    );
  }

  /**
   * Constructor.
   *
   * @param array<string,mixed> $configuration
   *   The plugin configuration.
   * @param string $plugin_id
   *   The plugin ID.
   * @param array<string,mixed> $plugin_definition
   *   The plugin definition.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $etm
   *   The core entity_type.manager service.
   * @param \Drupal\Core\Path\PathValidatorInterface $pathValidator
   *   The core path.validator service.
   * @param \Drupal\g2\WOTD $wotd
   *   The g2.wotd service.
   */
  public function __construct(
    array $configuration,
    string $plugin_id,
    array $plugin_definition,
    EntityTypeManagerInterface $etm,
    PathValidatorInterface $pathValidator,
    WOTD $wotd,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->etm = $etm;
    $this->pathValidator = $pathValidator;
    $this->wotd = $wotd;
  }

  /**
   * Build the block configuration subform.
   *
   * @param array<string,mixed> $form
   *   The initial form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return array<string,mixed>
   *   The modified form.
   */
  public function blockForm($form, FormStateInterface $form_state): array {
    $form = parent::blockForm($form, $form_state);
    $form[static::FEED_SETTING] = [
      '#type' => 'checkbox',
      '#title' => $this->t("Display feed icon"),
      '#default_value' => $this->configuration[static::FEED_SETTING] ?? TRUE,
      '#description' => $this->t('Add the standard RSS feed icon at the bottom of the block, linking to the WOTD feed'),
    ];
    return $form;
  }

  /**
   * The block configuration form submit handler.
   *
   * @param array<string,mixed> $form
   *   The initial form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  public function blockSubmit($form, FormStateInterface $form_state): void {
    parent::blockSubmit($form, $form_state);
    $this->configuration[static::FEED_SETTING] = $form_state->getValue(static::FEED_SETTING);
  }

  /**
   * Builds and returns the renderable array for this block plugin.
   *
   * If a block should not be rendered because it has no content, then this
   * method must also ensure to return no content: it must then only return an
   * empty array, or an empty array with #cache set (with cacheability metadata
   * indicating the circumstances for it being empty).
   *
   * @return array<string,mixed>
   *   A renderable array representing the content of the block.
   *
   * @see \Drupal\block\BlockViewBuilder
   */
  public function build(): array {
    $viewBuilder = $this->etm->getViewBuilder(G2::TYPE);
    $showFeedIcon = $this->configuration[static::FEED_SETTING] ?? TRUE;
    $entry = $this->wotd->get();
    if (empty($entry)) {
      return [];
    }
    $build = $viewBuilder->view($entry, G2::VM_BLOCK);
    if ($showFeedIcon) {
      [, , $displayName] = explode('.', G2::ROUTE_FEED_WOTD);
      $view = $this->etm
        ->getStorage('view')
        ->load(G2::VIEW_WOTD);
      assert($view instanceof View);
      $display = $view
        ->getDisplay($displayName);
      $title = $display['display_title'];
      $description = $display['display_options']['display_description'];

      $build[static::FEED_SETTING] = [
        '#theme' => 'feed_icon',
        '#url' => Url::fromRoute(G2::ROUTE_FEED_WOTD, [],
          // Absolute is a best practice for RSS feed links.
          ['absolute' => TRUE],
        ),
        '#title' => $title,
        // Ignored by #3371937, hence the need for g2_preprocess_feed_icon.
        '#attributes' => [
          'class' => [self::ICON_CLASS],
          'title' => $description,
        ],
        '#weight' => 15,
      ];
    }
    return $build;
  }

  /**
   * Implements hook_preprocess_feed_icon().
   *
   * Adds the self::ICON_CLASS to the feed, which default theme handling does
   * not fix drupal_common_theme() declaration for "feed_icon" to include
   * attributes.
   *
   * @param array<string,mixed> $variables
   *   The variables array to preprocess. The 'url' key should contain the URL
   *   for the feed icon, either as a string or DrupalCore\Url.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function preprocessFeedIcon(array &$variables): void {
    global $base_url;
    $url = $variables['url'] ?? NULL;
    // With most themes, we get a string, but with Olivero we get a Url.
    // We know nothing about other behaviors.
    if (empty($url) || !(is_string($url) || $url instanceof Url)) {
      return;
    }

    if (is_string($url)) {
      // The path validator only operates on local paths, not absolute URLs.
      if (UrlHelper::isExternal($url)&&
        !UrlHelper::externalIsLocal($url, $base_url)) {
        return;
      };
      ['path' => $path] = UrlHelper::parse($url);

      $url = $this->pathValidator
        ->getUrlIfValidWithoutAccessCheck($path);
      if (empty($url)) {
        return;
      }
    }

    try {
      /** @var \Drupal\Core\Url $url */
      $route = $url->getRouteName();
    }
    catch (\UnexpectedValueException $e) {
      $route = '';
    }
    if ($route !== G2::ROUTE_FEED_WOTD) {
      return;
    }

    [, , $displayName] = explode('.', G2::ROUTE_FEED_WOTD);
    $view = $this->etm
      ->getStorage('view')
      ->load(G2::VIEW_WOTD);
    assert($view instanceof View);
    $display = $view
      ->getDisplay($displayName);
    $description = $display['display_options']['display_description'];
    $variables['attributes'] = [
      'class' => [self::ICON_CLASS],
      'title' => $description,
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc