group_content_menu-8.x-1.0-rc3/src/Hook/NodeFormAlter.php

src/Hook/NodeFormAlter.php
<?php

namespace Drupal\group_content_menu\Hook;

use Drupal\Core\Access\AccessResultAllowed;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Hook\Order\OrderAfter;
use Drupal\Core\Menu\MenuParentFormSelectorInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\group\Entity\GroupInterface;
use Drupal\group\Entity\GroupRelationshipInterface;
use Drupal\group_content_menu\GroupContentMenuInterface;
use Drupal\node\NodeInterface;

/**
 * Helper class to handle altering node forms.
 */
class NodeFormAlter {
  public function __construct(
    protected readonly EntityTypeManagerInterface $entityTypeManager,
    protected readonly MenuParentFormSelectorInterface $menuParentSelector,
    protected readonly AccountProxyInterface $currentUser
  ) {}

  /**
   * Alter node forms to add GroupContentMenu options where appropriate.
   *
   * @param array $form
   *   A form array as from hook_form_alter().
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   A form state object as from hook_form_alter().
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   *
   * @see group_content_menu_form_node_form_alter()
   */
  #[Hook(hook: 'form_node_form_alter', order: new OrderAfter(['menu_ui']))]
  public function alter(array &$form, FormStateInterface $form_state): void {
    /** @var \Drupal\node\NodeInterface $node */
    $node = $form_state->getFormObject()->getEntity();

    $groups = $this->getGroups($form_state, $node);
    if (empty($groups)) {
      return;
    }

    $group_menus = $this->getGroupMenus($groups);
    if (empty($group_menus)) {
      return;
    }

    if ($this->menuExistsAndAccessible($form)) {
      // The menu element exists and is accessible, update the menu element with
      // the group menus options.
      $this->updateMenuElement($form, $node, $group_menus);
    }
    else {
      // Build menu form out only if menu has explicitly not had access denied.
      if (!isset($form['#access']) || $form['#access'] !== FALSE) {
        $this->attachMenuElement($form, $node, $group_menus);
      }
    }
  }

  /**
   * Build a menu element for a node form with only group menu options.
   *
   * @param array $form
   *   The node form to add the menu element to.
   * @param \Drupal\node\NodeInterface $node
   *   The current node being edited.
   * @param array $group_menus
   *   The group menus available as options.
   */
  protected function attachMenuElement(array &$form, NodeInterface $node, array $group_menus): void {
    $defaults = group_content_menu_get_menu_link_default($node, array_keys($group_menus));
    $default_parent = $defaults['menu_name'] . ':' . $defaults['parent'];

    $form['menu'] = [
      '#type' => 'details',
      '#title' => t('Menu settings'),
      '#open' => (bool) $defaults['id'],
      '#group' => 'advanced',
      '#attached' => [
        'library' => ['menu_ui/drupal.menu_ui'],
      ],
      '#tree' => TRUE,
      '#weight' => -2,
      '#attributes' => ['class' => ['menu-link-form']],
    ];
    $form['menu']['enabled'] = [
      '#type' => 'checkbox',
      '#title' => t('Provide a menu link'),
      '#default_value' => (int) (bool) $defaults['id'],
    ];
    $form['menu']['link'] = [
      '#type' => 'container',
      '#parents' => ['menu'],
      '#states' => [
        'invisible' => [
          'input[name="menu[enabled]"]' => ['checked' => FALSE],
        ],
      ],
    ];

    // Populate the element with the link data.
    foreach (['id', 'entity_id'] as $key) {
      $form['menu']['link'][$key] = [
        '#type' => 'value',
        '#value' => $defaults[$key],
      ];
    }

    $form['menu']['link']['title'] = [
      '#type' => 'textfield',
      '#title' => t('Menu link title'),
      '#default_value' => $defaults['title'],
      '#maxlength' => $defaults['title_max_length'],
    ];

    $form['menu']['link']['description'] = [
      '#type' => 'textfield',
      '#title' => t('Description'),
      '#default_value' => $defaults['description'],
      '#description' => t('Shown when hovering over the menu link.'),
      '#maxlength' => $defaults['description_max_length'],
    ];

    $form['menu']['link']['menu_parent'] = $this->menuParentSelector
      ->parentSelectElement($default_parent, $defaults['id'], $group_menus);
    $form['menu']['link']['menu_parent']['#title'] = t('Parent link');
    $form['menu']['link']['menu_parent']['#attributes']['class'][] = 'menu-parent-select';

    $form['menu']['link']['weight'] = [
      '#type' => 'number',
      '#title' => t('Weight'),
      '#default_value' => $defaults['weight'],
      '#description' => t('Menu links with lower weights are displayed before links with higher weights.'),
    ];

    foreach (array_keys($form['actions']) as $action) {
      if ($action !== 'preview' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {
        $form['actions'][$action]['#submit'][] = 'menu_ui_form_node_form_submit';
      }
    }

    $form['#entity_builders'][] = 'menu_ui_node_builder';
  }

  /**
   * Update an existing menu element with group menu options.
   *
   * @param array $form
   *   The node form to add the menu element to.
   * @param \Drupal\node\NodeInterface $node
   *   The current node being edited.
   * @param array $group_menus
   *   The group menus available as options.
   */
  protected function updateMenuElement(array &$form, NodeInterface $node, array $group_menus): void {
    // Check for default menu link values from the traditional menu system.
    $defaults = menu_ui_get_menu_link_defaults($node);
    if (empty($defaults['id'])) {
      // Node does not have a menu link in traditional menus, check group menus.
      $defaults = group_content_menu_get_menu_link_default($node, array_keys($group_menus));
      if ($defaults['id']) {
        $has_link_in_group_menus = TRUE;
      }
    }

    $group_menu_parent_options = $this->menuParentSelector
      ->getParentSelectOptions($defaults['id'], $group_menus);

    $traditional_menu_parent_options = $form['menu']['link']['menu_parent']['#options'];
    $form['menu']['link']['menu_parent']['#options'] = $group_menu_parent_options + $traditional_menu_parent_options;

    if (!empty($has_link_in_group_menus)) {
      $form['menu']['#open'] = (bool) $defaults['id'];
      $form['menu']['enabled']['#default_value'] = (int) (bool) $defaults['id'];

      $form['menu']['link']['id']['#value'] = $defaults['id'];
      $form['menu']['link']['entity_id']['#value'] = $defaults['entity_id'];

      $form['menu']['link']['title']['#default_value'] = $defaults['title'];
      $form['menu']['link']['title']['#maxlength'] = $defaults['title_max_length'];

      $form['menu']['link']['description']['#default_value'] = $defaults['description'];
      $form['menu']['link']['description']['#maxlength'] = $defaults['description_max_length'];

      $form['menu']['link']['menu_parent']['#default_value'] = $defaults['menu_name'] . ':' . $defaults['parent'];

      $form['menu']['link']['weight']['#default_value'] = $defaults['weight'];
    }
  }

  /**
   * Get a node's groups for the edit form.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object from hook_form_node_form_alter().
   * @param \Drupal\node\NodeInterface $node
   *   The node object being edited.
   *
   * @return array|\Drupal\group\Entity\GroupInterface[]
   *   An empty array or an array of Groups.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getGroups(FormStateInterface $form_state, NodeInterface $node): array {
    $groups = [];

    if ($group_id = $form_state->get('group')) {
      // If group is set in $form_state, we're currently creating a new node in
      // a group so the node will have only one group.
      $groups[] = $group_id;
    }
    elseif (!$node->isNew()) {
      // We're on a node's edit form. A node can be added to any number of
      // groups so we must load all groups for the node.
      $group_relationships = $this->entityTypeManager
        ->getStorage('group_relationship')
        ->loadByEntity($node);
      $group_ids = array_map(static function (GroupRelationshipInterface $group_relationship) {
        return $group_relationship->getGroup()->id();
      }, $group_relationships);
      $groups = $this->entityTypeManager
        ->getStorage('group')
        ->loadMultiple($group_ids);
    }

    return $groups;
  }

  /**
   * Get an array of GroupContentMenus keyed by mlid.
   *
   * @param \Drupal\group\Entity\GroupInterface[] $groups
   *   An array of groups to get menus for.
   *
   * @return array
   *   An array of GroupContentMenu labels, keyed by menu link id.
   */
  protected function getGroupMenus(array $groups): array {
    $menus = [];
    foreach ($groups as $group) {
      if ($this->canManageGroupMenuItems($group, $this->currentUser)) {
        foreach (group_content_menu_get_menus_per_group($group) as $group_content) {
          $group_menu = $group_content->getEntity();
          $mlid = GroupContentMenuInterface::MENU_PREFIX . $group_menu->id();
          $menus[$mlid] = $group_menu->label() . " ({$group->label()})";
        }
      }
    }

    return array_unique($menus);
  }

  /**
   * Check if a user can manage menu items within a group.
   *
   * @param \Drupal\group\Entity\GroupInterface $group
   *   The group to check for.
   * @param \Drupal\Core\Session\AccountProxyInterface $user
   *   The user to access check.
   *
   * @return bool
   *   TRUE if the user can manage menu items within the group.
   */
  protected function canManageGroupMenuItems(GroupInterface $group, AccountProxyInterface $user): bool {
    if ($user->hasPermission('administer menu')) {
      return TRUE;
    }
    if ($group->hasPermission('manage group_content_menu menu items', $user)) {
      return TRUE;
    }

    return FALSE;
  }

  /**
   * Check if menu exists and is accessible on node form.
   *
   * @param array $form
   *   The node form render array.
   *
   * @return bool
   *   True if the menu exists and is accessible, false otherwise.
   */
  protected function menuExistsAndAccessible(array $form): bool {
    return !empty($form['menu']) && (
        !isset($form['menu']['#access']) || $form['menu']['#access'] === TRUE || $form['menu']['#access'] instanceof AccessResultAllowed
      );
  }

}

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

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