association-1.0.0-alpha2/src/Plugin/Block/AssociationBlock.php

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

namespace Drupal\association\Plugin\Block;

use Drupal\association\AssociationNegotiatorInterface;
use Drupal\association\Entity\AssociationInterface;
use Drupal\association_menu\AssociationMenuBuilderInterface;
use Drupal\association_menu\AssociationMenuStorageInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\Attribute\Block;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;

/**
 * Provides a block, based on the active association context.
 */
#[Block(
  id: 'association_block',
  admin_label: new TranslatableMarkup('Association display block'),
  category: new TranslatableMarkup("Entity association"),
  context_definitions: [
    'association' => new ContextDefinition("entity:association", new TranslatableMarkup('Association'), FALSE),
    'entity' => new ContextDefinition("entity", new TranslatableMarkup('Entity'), FALSE),
  ],
)]
class AssociationBlock extends AssociationBlockBase implements ContainerFactoryPluginInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Retrieves the bundle information for various entity types.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $entityBundleInfo;

  /**
   * The entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * The entity display repository manager.
   *
   * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
   */
  protected $entityDisplayRepo;

  /**
   * Association menu item storage manager.
   *
   * @var \Drupal\association_menu\AssociationMenuStorageInterface
   */
  protected $menuStorage;

  /**
   * Association menu builder, if available.
   *
   * @var \Drupal\association_menu\AssociationMenuBuilderInterface
   */
  protected $menuBuilder;

  /**
   * The menu storage data of the association menu of this block.
   *
   * @var array
   */
  protected $menuData;

  /**
   * Create an instance of the AssociationBlock plugin.
   *
   * @param array $configuration
   *   The block configuration.
   * @param string $plugin_id
   *   The unique identifier for this plugin.
   * @param mixed $plugin_definition
   *   The plugin definition from discovery or a deriver.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
   *   Retrieves the bundle information for various entity types.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
   *   The entity display repository manager.
   * @param \Drupal\association\AssociationNegotiatorInterface $association_negotiator
   *   The negotiator to determine the active association context of the block.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_bundle_info, EntityFieldManagerInterface $entity_field_manager, EntityDisplayRepositoryInterface $entity_display_repository, AssociationNegotiatorInterface $association_negotiator) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $association_negotiator);

    $this->entityTypeManager = $entity_type_manager;
    $this->entityBundleInfo = $entity_bundle_info;
    $this->entityFieldManager = $entity_field_manager;
    $this->entityDisplayRepo = $entity_display_repository;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager'),
      $container->get('entity_type.bundle.info'),
      $container->get('entity_field.manager'),
      $container->get('entity_display.repository'),
      $container->get('association.negotiator')
    );

    // Optionally add association menu options when the menu module is enabled.
    $moduleHandler = $container->get('module_handler');
    if ($moduleHandler->moduleExists('association_menu')) {
      try {
        // Having these services present allows menu options to appear, and
        // the association specific menus to become available.
        $instance->setAssociationMenuStorage($container->get('association_menu.storage'));
        $instance->setAssociationMenuBuilder($container->get('association_menu.builder'));
      }
      catch (ServiceNotFoundException $e) {
        // Optional menu services can fail safety.
      }
    }

    return $instance;
  }

  /**
   * Sets the association menu item storage manager.
   *
   * Having this service available indicates that menus are available to the
   * block and unlocks the menu configurations.
   *
   * @param \Drupal\association_menu\AssociationMenuStorageInterface $menu_storage
   *   The association menu item storage manager.
   */
  public function setAssociationMenuStorage(AssociationMenuStorageInterface $menu_storage) {
    $this->menuStorage = $menu_storage;
  }

  /**
   * Sets the association menu builder service.
   *
   * Having this service available indicates that menus are available to the
   * block and unlocks the menu display.
   *
   * @param \Drupal\association_menu\AssociationMenuBuilderInterface $menu_builder
   *   The association menu builder to use with this block.
   */
  public function setAssociationMenuBuilder(AssociationMenuBuilderInterface $menu_builder) {
    $this->menuBuilder = $menu_builder;
  }

  /**
   * {@inheritdoc}
   */
  protected function getAssociationContextNames(): array {
    return [
      'layout_builder' => 'entity',
      'global' => 'association',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    $cacheTags = parent::getCacheTags();

    // Apply association tags from the entity context.
    if ($association = $this->getAssociation()) {
      $viewMode = $this->configuration['view_mode'] ?? 'default';
      $display = $this->entityDisplayRepo->getViewDisplay('association', $association->bundle(), $viewMode);

      if ($display) {
        $cacheTags = Cache::mergeTags($cacheTags, $display->getCacheTags());
      }

      // Apply menu cache tags if menus are displayed.
      $menu = $this->getMenu($association);
      if (!empty($menu['cache'])) {
        $cacheTags = Cache::mergeTags($cacheTags, $menu['cache']->getCacheTags());
      }
    }

    return $cacheTags;
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    $cacheContexts = parent::getCacheContexts();

    if ($association = $this->getAssociation()) {
      $viewMode = $this->configuration['view_mode'] ?? 'default';
      $display = $this->entityDisplayRepo->getViewDisplay('association', $association->bundle(), $viewMode);

      if ($display) {
        $cacheContexts = Cache::mergeContexts($cacheContexts, $display->getCacheContexts());
      }

      // Apply menu cache contexts if menus are displayed.
      $menu = $this->getMenu($association);
      if (!empty($menu['cache'])) {
        $cacheContexts = Cache::mergeContexts($cacheContexts, $menu['cache']->getCacheContexts());
      }
    }

    return $cacheContexts;
  }

  /**
   * {@inheritdoc}
   */
  public function blockAccess(AccountInterface $account) {
    $bundles = $this->configuration['bundles'] ?? [];

    if ($assoc = $this->getAssociation()) {
      // Treat empty bundles configuration as all bundles, or if bundle is in
      // the list of allowed bundles check for association access to view.
      return (!$bundles || in_array($assoc->bundle(), $bundles))
        ? $assoc->access('view', $account, TRUE)
        : AccessResult::forbidden()->addCacheableDependency($assoc);
    }

    // No association value available, block is not available.
    return AccessResult::forbidden();
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'view_mode' => 'block',
      'bundles' => [],
      'menu_display' => 'none',
      'menu_display_field' => NULL,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    $content = [];

    if ($assoc = $this->getAssociation()) {
      $viewMode = $this->configuration['view_mode'] ?? 'default';

      $content['association'] = $this->entityTypeManager
        ->getViewBuilder('association')
        ->view($assoc, $viewMode);

      // Optionally include the association menu, if association_menu services
      // are available and the block has been configured to display the menu.
      $menu = $this->getMenu($assoc);
      if ($menu && $this->menuBuilder) {
        $content['menu'] = $this->menuBuilder->buildMenu($menu);
      }
    }

    return $content;
  }

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    $form['view_mode'] = [
      '#type' => 'radios',
      '#title' => $this->t('View mode'),
      '#options' => $this->entityDisplayRepo->getViewModeOptions('association'),
      '#default_value' => $this->configuration['view_mode'] ?? 'default',
      '#description' => $this->t('View mode to render the Entity Association as.'),
    ];

    $bundles = [];
    foreach ($this->entityBundleInfo->getBundleInfo('association') as $bundle => $bundleInfo) {
      $bundles[$bundle] = $bundleInfo['label'];
    }

    $form['bundles'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Allowed association types'),
      '#options' => $bundles,
      '#default_value' => $this->configuration['bundles'] ?? [],
      '#description' => $this->t('Leaving this configuration blank is the same as allowing any types.'),
    ];

    // Optional menu display settings. Only available if association_menu
    // module is currently enabled.
    $form['menu_display'] = [
      '#type' => 'select',
      '#title' => $this->t('Display association menu'),
      '#options' => [
        'none' => $this->t('Hide menu'),
        'visible' => $this->t('Show menu'),
        'field' => $this->t('By field value'),
      ],
      '#default_value' => $this->configuration['menu_display'] ?? 'none',
    ];

    // Hide these options if the association menu module is not available.
    if (!$this->menuStorage || !$this->menuBuilder) {
      $form['menu_display']['#access'] = FALSE;
      $form['menu_display']['#default_value'] = 'none';
    }
    else {
      $fieldOptions = [];
      $fieldDefs = $this->entityFieldManager->getFieldStorageDefinitions('association');

      foreach ($fieldDefs as $fieldName => $definition) {
        $fieldOptions[$fieldName] = preg_replace('#^association\.#', '', $definition->getLabel());
      }

      // If a field is used to determine menu visibility, allow the admin to
      // pick which field is checked.
      $form['menu_display_field'] = [
        '#type' => 'select',
        '#title' => $this->t('Field which determines menu visibility'),
        '#options' => $fieldOptions,
        '#states' => [
          'visible' => [
            'select[name="settings[menu_display]"]' => ['value' => 'field'],
          ],
          'required' => [
            'select[name="settings[menu_display]"]' => ['value' => 'field'],
          ],
        ],
        '#description' => $this->t('Display menu when this field is TRUE.'),
      ];
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $config['view_mode'] = $form_state->getValue('view_mode') ?: 'default';
    $config['bundles'] = array_filter($form_state->getValue('bundles'));
    $config['menu_display'] = $form_state->getValue('menu_display');
    $config['menu_display_field'] = $form_state->getValue('menu_display_field');

    $this->setConfiguration($config);
  }

  /**
   * Get an association menu if configured to appear and menu is available.
   *
   * Method checks for block configurations to determine if a menu should be
   * included in the block display, and if the menu services are available to
   * build and display the menu.
   *
   * @param \Drupal\association\Entity\AssociationInterface $association
   *   The entity association to fetch the menu for.
   *
   * @return array|null
   *   If menu options are configured, and menu storage manager is available,
   *   returns an array of menu data for the association. NULL returned if
   *   menu is configured not to appear, or is not available.
   */
  protected function getMenu(AssociationInterface $association): ?array {
    if (!$this->menuStorage) {
      return NULL;
    }

    $menuDisplay = $this->configuration['menu_display'] ?? 'none';
    if ('none' === $menuDisplay) {
      return NULL;
    }

    // If the menu display is based on a field value, check the field. If the
    // field display parameter is missing, or points to a field that doesn't
    // exist for the association, these all count "no menu".
    if ('field' === $menuDisplay) {
      $menuField = $this->configuration['menu_display_field'] ?? '';

      // The field is missing, or computes to empty, don't show the menu.
      if (!$menuField || !$association->hasField($menuField) || !$association->get($menuField)->value) {
        return NULL;
      }
    }

    if (!isset($this->menuData)) {
      $this->menuData = $this->menuStorage->getMenu($association);
    }

    return $this->menuData;
  }

}

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

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