cms_content_sync-3.0.x-dev/src/Plugin/cms_content_sync/entity_handler/DefaultMenuLinkContentHandler.php

src/Plugin/cms_content_sync/entity_handler/DefaultMenuLinkContentHandler.php
<?php

namespace Drupal\cms_content_sync\Plugin\cms_content_sync\entity_handler;

use Drupal\cms_content_sync\Plugin\EntityHandlerBase;
use Drupal\cms_content_sync\PullIntent;
use Drupal\cms_content_sync\PushIntent;
use Drupal\cms_content_sync\SyncIntent;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\system\Entity\Menu;
use EdgeBox\SyncCore\Interfaces\Configuration\IDefineEntityType;
use EdgeBox\SyncCore\V2\Configuration\DefineProperty;

/**
 * Class DefaultMenuLinkContentHandler, providing a minimalistic implementation
 * for menu items, making sure they're referenced correctly by UUID.
 *
 * @EntityHandler(
 *   id = "cms_content_sync_default_menu_link_content_handler",
 *   label = @Translation("Default Menu Link Content"),
 *   weight = 100
 * )
 */
class DefaultMenuLinkContentHandler extends EntityHandlerBase {
  public const USER_REVISION_PROPERTY = 'revision_user';

  protected $resolveDependent;

  /**
   * {@inheritdoc}
   */
  public static function supports($entity_type, $bundle) {
    return 'menu_link_content' == $entity_type;
  }

  /**
   * {@inheritdoc}
   */
  public function getAllowedPreviewOptions() {
    return [
      'table' => 'Table',
    ];
  }

  /**
   * @param \EdgeBox\SyncCore\Interfaces\Configuration\IDefineEntityType|EdgeBox\SyncCore\V2\Configuration\DefineProperty $definition
   */
  public function updateEntityTypeDefinition(IDefineEntityType|DefineProperty &$definition) {
    parent::updateEntityTypeDefinition($definition);

    $module_handler = \Drupal::service('module_handler');
    if ($module_handler->moduleExists('menu_token')) {
      $definition->addObjectProperty('menu_token_options', 'Menu token options', FALSE, FALSE, 'menu_token');
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getHandlerSettings($current_values, $type = 'both') {
    $menus = [];
    if ($custom_menus = Menu::loadMultiple()) {
      foreach ($custom_menus as $menu_machine_name => $menu) {
        $menus[$menu_machine_name] = $menu->label();
      }
    }

    return [
      'ignore_unpublished' => [
        '#type' => 'checkbox',
        '#title' => 'Ignore disabled',
        '#default_value' => isset($current_values['ignore_unpublished']) && 0 === $current_values['ignore_unpublished'] ? 0 : 1,
      ],
      'restrict_menus' => [
        '#type' => 'checkboxes',
        '#title' => 'Restrict to menus',
        '#default_value' => $current_values['restrict_menus'] ?? [],
        '#options' => $menus,
        '#description' => t('When no checkbox is set, menu items from all menus will be pushed/pulled.'),
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function push(PushIntent $intent, ?EntityInterface $entity = NULL) {
    $result = parent::push($intent, $entity);

    if ($result && SyncIntent::ACTION_DELETE != $intent->getAction()) {
      $module_handler = \Drupal::service('module_handler');

      if ($module_handler->moduleExists('menu_token')) {
        $uuid = $intent->getUuid();
        $config_menu = \Drupal::entityTypeManager()
          ->getStorage('link_configuration_storage')
          ->load($uuid);

        if (!empty($config_menu)) {
          $config_array = unserialize($config_menu->get('configurationSerialized'));
          $intent->setProperty('menu_token_options', $config_array);
        }
      }
    }

    return $result;
  }

  /**
   * {@inheritdoc}
   */
  public function ignorePull(PullIntent $intent) {
    $action = $intent->getAction();
    if (SyncIntent::ACTION_DELETE == $action) {
      return parent::ignorePull($intent);
    }

    if (empty($this->resolveDependent)) {
      if (empty($intent->getProperty('enabled'))) {
        $enabled = TRUE;
      }
      else {
        $enabled = $intent->getProperty('enabled')[0]['value'];
      }
    }
    else {
      $enabled = $this->resolveDependent[5]['enabled'];
    }

    // Not published? Ignore this revision then.
    if (!$enabled && $this->settings['handler_settings']['ignore_unpublished']) {
      $intent->setIgnoreMessage('The menu item is not enabled.');
      // Unless it's a delete, then it won't have a status and is independent.
      return TRUE;
    }

    if ($this->shouldRestrictMenuUsage()) {
      $menu = $intent->getProperty('menu_name')[0]['value'];
      if (empty($this->settings['handler_settings']['restrict_menus'][$menu])) {
        $intent->setIgnoreMessage('The menu (' . $menu . ') is not allowed.');

        return TRUE;
      }
    }

    return parent::ignorePull($intent);
  }

  /**
   * {@inheritdoc}
   */
  public function pull(PullIntent $intent) {
    if (SyncIntent::ACTION_DELETE == $intent->getAction()) {
      return parent::pull($intent);
    }

    $link = $intent->getProperty('link');

    // Reset, in case the handler is re-used.
    $this->resolveDependent = NULL;

    if (isset($link[0]['uri'])) {
      $uri = $link[0]['uri'];
      preg_match('@^internal:/([a-z_0-9]+)\/([0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12})$@', $uri, $found);

      if (!empty($found)) {
        [$type, $uuid] = $found[1];
        $referenced = \Drupal::service('entity.repository')
          ->loadEntityByUuid($type, $uuid);

        if (!$referenced) {
          $this->resolveDependent = [
            $type,
            $uuid,
            $intent->getEntity(),
            $intent->getReason(),
            'link',
                [
                  'enabled' => (bool) $intent->getProperty('enabled')[0]['value'],
                ],
          ];

          $intent->overwriteProperty('enabled', [['value' => 0]]);
        }
      }
    }
    elseif (($reference = $intent->loadReference($link[0])) && $reference->getType() && ($reference->getId() || $reference->getUuid())) {
      $referenced_entity = $intent->loadEmbeddedEntity($link[0]);

      if (!$referenced_entity) {
        $this->resolveDependent = [
          $reference->getType(),
          $reference->getId() ?? $reference->getUuid(),
          $intent->getEntity(),
          $intent->getReason(),
          'link',
              [
                'enabled' => (bool) $intent->getProperty('enabled')[0]['value'],
              ],
        ];

        $intent->overwriteProperty('enabled', [['value' => 0]]);
      }
    }

    if (!parent::pull($intent)) {
      return FALSE;
    }

    if (!empty($this->resolveDependent)) {
      // The entity may not exist yet when called above (only created after the pull). So we have to postpone the reporting to down here
      // and ask for the entity again so that MissingDependencyManager::saveUnresolvedDependency() doesn't err out.
      $this->resolveDependent[2] = $intent->getEntity();
      call_user_func_array(['\\Drupal\\cms_content_sync\\MissingDependencyManager', 'saveUnresolvedDependency'], $this->resolveDependent);
    }

    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function ignorePush(PushIntent $intent) {
    /**
     * @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity
     */
    $entity = $intent->getEntity();

    if (!$entity->isEnabled() && $this->settings['handler_settings']['ignore_unpublished']) {
      $intent->setIgnoreMessage('The menu item is not enabled.');

      return TRUE;
    }

    if ($this->shouldRestrictMenuUsage()) {
      $menu = $entity->getMenuName();
      if (empty($this->settings['handler_settings']['restrict_menus'][$menu])) {
        $intent->setIgnoreMessage('The menu (' . $menu . ') is not allowed.');

        return TRUE;
      }
    }

    $uri = $entity->get('link')->getValue()[0]['uri'];
    if ('entity:' == mb_substr($uri, 0, 7)) {
      preg_match('/^entity:(.*)\/(\d*)$/', $uri, $found);
      // This means we're already dealing with a UUID that has not been resolved
      // locally yet. So there's no sense in pushing this back to the pool.
      if (empty($found)) {
        $intent->setIgnoreMessage("The entity that is referenced at this menu item doesn't exist.");

        return TRUE;
      }

      $link_entity_type = $found[1];
      $link_entity_id = $found[2];
      $entity_manager = \Drupal::entityTypeManager();
      $reference = $entity_manager->getStorage($link_entity_type)
        ->load($link_entity_id);
      // Dead reference > ignore.
      if (empty($reference)) {
        $intent->setIgnoreMessage("The entity that is referenced at this menu item doesn't exist.");

        return TRUE;
      }
    }

    return parent::ignorePush($intent);
  }

  /**
   * {@inheritdoc}
   */
  protected function setEntityValues(PullIntent $intent, ?FieldableEntityInterface $entity = NULL) {
    $result = parent::setEntityValues($intent, $entity);

    if (SyncIntent::ACTION_DELETE != $intent->getAction()) {
      $module_handler = \Drupal::service('module_handler');

      if ($module_handler->moduleExists('menu_token')) {
        $config_array = $intent->getProperty('menu_token_options');
        if (!empty($config_array)) {
          $uuid = $intent->getUuid();
          $config_menu = \Drupal::entityTypeManager()
            ->getStorage('link_configuration_storage')
            ->load($uuid);
          if (empty($config_menu)) {
            $config_menu = \Drupal::entityTypeManager()
              ->getStorage('link_configuration_storage')
              ->create([
                'id' => $uuid,
                'label' => 'Menu token link configuration',
                'linkid' => (string) $intent->getProperty('link')[0]['uri'],
                'configurationSerialized' => serialize($config_array),
              ]);
          }
          else {
            $config_menu->set('linkid', (string) $intent->getProperty('link')[0]['uri']);
            $config_menu->set('configurationSerialized', serialize($config_array));
          }
          $config_menu->save();
        }
      }
    }

    return $result;
  }

  /**
   *
   */
  protected function shouldRestrictMenuUsage() {
    return !empty($this->settings['handler_settings']['restrict_menus']) && !empty(array_diff(array_values($this->settings['handler_settings']['restrict_menus']), [0]));
  }

}

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

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