cms_content_sync-3.0.x-dev/src/Controller/FlowControllerBase.php

src/Controller/FlowControllerBase.php
<?php

namespace Drupal\cms_content_sync\Controller;

use Drupal\cms_content_sync\Entity\EntityStatus;
use Drupal\cms_content_sync\Entity\Flow;
use Drupal\cms_content_sync\Entity\Pool;
use Drupal\cms_content_sync\PullIntent;
use Drupal\cms_content_sync\PushIntent;
use Drupal\cms_content_sync\SyncIntent;
use Drupal\Core\Entity\EntityInterface;

/**
 * The Flow controller base.
 */
class FlowControllerBase {
  /**
   * The Content Sync flow entity.
   *
   * @var \Drupal\cms_content_sync\Entity\Flow
   */
  protected $flow;

  /**
   * Constructor.
   */
  public function __construct(Flow $flow) {
    $this->flow = $flow;
  }

  /**
   * Get the flow type.
   *
   * @return null|string
   *   Returns the flow type.
   */
  public function getType() {
    return $this->flow->type;
  }

  /**
   * The entity types to be pulled.
   *
   * @return array
   *   Returns the entity types to be pulled.
   */
  public function getEntityTypesToPull($pull_type = NULL) {
    $pulled_entity_types = [];
    $entity_types = $this->getEntityTypeConfig();

    foreach ($entity_types as $entity_type_name => $bundles) {
      foreach ($bundles as $bundle_name => $config) {
        if (is_null($pull_type) ? PullIntent::PULL_DISABLED != $config['import'] : $config['import'] == $pull_type) {
          $pulled_entity_types[$entity_type_name][$bundle_name] = $config;
        }
      }
    }

    return $pulled_entity_types;
  }

  /**
   * Check if an entity type can be pushed.
   */
  public function canPushEntityType($entity_type_name, $bundle_name, $reason, $action = SyncIntent::ACTION_CREATE, $pool = NULL) {
    static $any_reason = [
      PushIntent::PUSH_AUTOMATICALLY,
      PushIntent::PUSH_MANUALLY,
      PushIntent::PUSH_AS_DEPENDENCY,
    ];

    static $independent_reason = [
      PushIntent::PUSH_AUTOMATICALLY,
      PushIntent::PUSH_MANUALLY,
    ];

    if ($this->flow->type === Flow::TYPE_PULL) {
      return FALSE;
    }

    if (is_string($reason)) {
      if (PushIntent::PUSH_ANY === $reason) {
        $reason = $any_reason;
      }
      elseif (PushIntent::PUSH_FORCED === $reason) {
        $reason = $independent_reason;
      }
      else {
        $reason = [$reason];
      }
    }

    if (!$bundle_name) {
      foreach ($this->getEntityTypeConfig($entity_type_name) as $bundle_name => $config) {
        if ($this->canPushEntityType($entity_type_name, $bundle_name, $reason, $action, $pool)) {
          return TRUE;
        }
      }

      return FALSE;
    }

    $config = $this->getEntityTypeConfig($entity_type_name, $bundle_name);
    if (empty($config) || Flow::HANDLER_IGNORE == $config['handler']) {
      return FALSE;
    }

    if (PushIntent::PUSH_DISABLED == $config['export']) {
      return FALSE;
    }

    if (SyncIntent::ACTION_DELETE == $action && !boolval($config['export_deletion_settings']['export_deletion'])) {
      return FALSE;
    }

    if ($pool) {
      if (empty($config['export_pools'][$pool->id]) || Pool::POOL_USAGE_FORBID == $config['export_pools'][$pool->id]) {
        return FALSE;
      }
    }

    // If this has not been exported yet, we can't push the entity.
    if (empty($config['version'])) {
      return FALSE;
    }

    return in_array($config['export'], $reason);
  }

  /**
   * Check if an Entity can be pushed.
   */
  public function canPushEntity(EntityInterface $entity, $reason, $action = SyncIntent::ACTION_CREATE, $pool = NULL) {
    if ($this->flow->type === Flow::TYPE_PULL) {
      return FALSE;
    }

    $infos = $entity->uuid() ? EntityStatus::getInfosForEntity(
          $entity->getEntityTypeId(),
          $entity->uuid(),
          [
            'flow' => $this->flow->id(),
          ]
      ) : [];

    // Fresh entity- no pool restriction.
    if (!count($infos) || NULL !== $pool) {
      return $this->canPushEntityType($entity->getEntityTypeId(), $entity->bundle(), $reason, $action, $pool);
    }

    // If the entity has been pulled or pushed before, only the Flows that support the pools that were assigned
    // are relevant. So we filter out any Flows here that don't support any of the assigned pools.
    foreach ($infos as $info) {
      if ($this->canPushEntityType($entity->getEntityTypeId(), $entity->bundle(), $reason, $action, $info->getPool())) {
        return TRUE;
      }
    }

    // Flow config may have changed so status entities exist but now they no longer push the entity. In this case we
    // fall back into the behavior as if the entity was new (see above)
    return $this->canPushEntityType($entity->getEntityTypeId(), $entity->bundle(), $reason, $action, $pool);
  }

  /**
   * Check if an entity can be added as an dependency.
   */
  public function canAddEntityAsDependency(EntityInterface $entity) {
    $settings = $this->getEntityTypeConfig($entity->getEntityTypeId(), $entity->bundle());
    if (empty($settings)) {
      return FALSE;
    }
    if (PushIntent::PUSH_AS_DEPENDENCY !== $settings['export']) {
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Get pools to push to.
   *
   * Get a list of all pools that are used for pushing this entity, either
   * automatically or manually selected.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity that should be pushed.
   * @param string|string[] $reason
   *   {@see Flow::PUSH_*}.
   * @param string $action
   *   {@see ::ACTION_*}.
   * @param bool $include_forced
   *   Include forced pools. Otherwise only use-selected / referenced ones.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   *
   * @return \Drupal\cms_content_sync\Entity\Pool[]
   *   The pools the entity should be pushed to.
   */
  public function getPoolsToPushTo(EntityInterface $entity, $reason, $action, $include_forced = TRUE) {
    $config = $this->getEntityTypeConfig($entity->getEntityTypeId(), $entity->bundle());
    if (!$this->canPushEntity($entity, $reason, $action)) {
      return [];
    }

    $result = [];
    $pools = Pool::getAll();

    foreach ($config['export_pools'] as $id => $setting) {
      if (!isset($pools[$id])) {
        continue;
      }
      $pool = $pools[$id];

      if (Pool::POOL_USAGE_FORBID == $setting) {
        continue;
      }

      if (Pool::POOL_USAGE_FORCE == $setting) {
        if ($include_forced) {
          $result[$id] = $pool;
        }

        continue;
      }

      $entity_status = EntityStatus::getInfoForEntity($entity->getEntityTypeId(), $entity->uuid(), $this->flow, $pool);
      if ($entity_status && $entity_status->isPushEnabled()) {
        $result[$id] = $pool;
      }
    }

    return $result;
  }

  /**
   * Get used pool for pulling.
   *
   * Get a list of all pools that are used for pushing this entity, either
   * automatically or manually selected.
   *
   * @param string $entity_type
   *   The checked entity type.
   * @param string $bundle
   *   The checked entity type bundle.
   *
   * @return \Drupal\cms_content_sync\Entity\Pool[]
   *   Returns the used pools.
   */
  public function getUsedPoolsForPulling($entity_type, $bundle) {
    $config = $this->getEntityTypeConfig($entity_type, $bundle);

    if (empty($config['import_pools'])) {
      return [];
    }

    $result = [];
    $pools = Pool::getAll();

    foreach ($config['import_pools'] as $id => $setting) {
      $pool = $pools[$id];

      if (Pool::POOL_USAGE_FORBID == $setting) {
        continue;
      }

      $result[] = $pool;
    }

    return $result;
  }

  /**
   * Get a list of all pools this Flow is using.
   *
   * @return \Drupal\cms_content_sync\Entity\Pool[]
   *   The used pools.
   */
  public function getUsedPools() {
    $result = [];

    $pools = Pool::getAll();

    foreach ($pools as $id => $pool) {
      if ($this->usesPool($pool)) {
        $result[$id] = $pool;
      }
    }

    return $result;
  }

  /**
   * Check if the given pool is used by this Flow.
   *
   * If any handler set the flow as FORCE or ALLOW, this will return TRUE.
   *
   * @param \Drupal\cms_content_sync\Entity\Pool $pool
   *   The pool to check.
   *
   * @return bool
   *   TRUE if the pool is used by this flow, FALSE otherwise.
   */
  public function usesPool(Pool $pool) {
    foreach ($this->getEntityTypeConfig(NULL, NULL, TRUE) as $bundles) {
      foreach ($bundles as $config) {
        if (Flow::HANDLER_IGNORE == $config['handler']) {
          continue;
        }

        if (PushIntent::PUSH_DISABLED != $config['export']) {
          if (!empty($config['export_pools'][$pool->id]) && Pool::POOL_USAGE_FORBID != $config['export_pools'][$pool->id]) {
            return TRUE;
          }
        }

        if (PullIntent::PULL_DISABLED != $config['import']) {
          if (!empty($config['import_pools'][$pool->id]) && Pool::POOL_USAGE_FORBID != $config['import_pools'][$pool->id]) {
            return TRUE;
          }
        }
      }
    }

    return FALSE;
  }

  /**
   * Ask this Flow whether or not it can pull the provided entity.
   *
   * @param string $entity_type_name
   *   The name of the entity type to check.
   * @param string $bundle_name
   *   The name of the entity bundle to check.
   * @param string $reason
   *   The reason for the pull.
   * @param string $action
   *   The action to perform on the entity.
   * @param bool $strict
   *   If asking for DEPENDENCY as a $reason, then $strict will NOT include a Flow that pulls AUTOMATICALLY.
   *
   * @return bool
   *   Whether or not the entity can be pulled.
   */
  public function canPullEntity($entity_type_name, $bundle_name, $reason, $action = SyncIntent::ACTION_CREATE, $strict = FALSE) {
    if ($this->flow->type === Flow::TYPE_PUSH) {
      return FALSE;
    }

    $config = $this->getEntityTypeConfig($entity_type_name, $bundle_name);
    if (empty($config) || Flow::HANDLER_IGNORE == $config['handler']) {
      return FALSE;
    }

    if (PullIntent::PULL_DISABLED == $config['import']) {
      return FALSE;
    }

    if (SyncIntent::ACTION_DELETE == $action && !boolval($config['import_deletion_settings']['import_deletion'])) {
      return FALSE;
    }

    // If any handler is available, we can pull this entity.
    if (PullIntent::PULL_FORCED == $reason) {
      return TRUE;
    }

    // Flows that pull automatically can also handle referenced entities.
    if (PullIntent::PULL_AUTOMATICALLY == $config['import']) {
      if (PullIntent::PULL_AS_DEPENDENCY == $reason && !$strict) {
        return TRUE;
      }
    }

    // Once pulled manually, updates will arrive automatically.
    if (PullIntent::PULL_AUTOMATICALLY == $reason && PullIntent::PULL_MANUALLY == $config['import']) {
      if (SyncIntent::ACTION_UPDATE == $action || SyncIntent::ACTION_DELETE == $action) {
        return TRUE;
      }
    }

    return $config['import'] == $reason;
  }

  /**
   * Ask this synchronization whether it supports the provided entity.
   *
   * Returns false if either the entity type is not known or the config handler
   * is set to {@see Flow::HANDLER_IGNORE}.
   *
   * @return bool
   *   Returns true of the entity is supported.
   */
  public function supportsEntity(EntityInterface $entity) {
    $config = $this->getEntityTypeConfig($entity->getEntityTypeId(), $entity->bundle());
    if (empty($config) || empty($config['handler'])) {
      return FALSE;
    }

    return Flow::HANDLER_IGNORE != $config['handler'];
  }

  /**
   * The the entity type handler for the given config.
   *
   * @param string $entity_type_name
   *   The entity type name to check for.
   * @param string $bundle_name
   *   The entity type bundle name to check for.
   * @param null|array $config
   *   {@see Flow::getEntityTypeConfig()}.
   *
   * @return \Drupal\cms_content_sync\Plugin\EntityHandlerInterface
   *   Returns the entity type handler for the given config.
   */
  public function getEntityTypeHandler(string $entity_type_name, string $bundle_name, $config) {
    static $cache = [];

    $cache_key = join(":", [$this->flow->id(), $entity_type_name, $bundle_name]);
    if (isset($cache[$cache_key])) {
      return $cache[$cache_key];
    }

    $entityPluginManager = \Drupal::service('plugin.manager.cms_content_sync_entity_handler');

    return $cache[$cache_key] = $entityPluginManager->createInstance(
          $config['handler'],
          [
            'entity_type_name' => $entity_type_name,
            'bundle_name' => $bundle_name,
            'settings' => $config,
            'sync' => $this->flow,
          ]
      );
  }

  /**
   * Get the field handler.
   *
   * Get the correct field handler instance for this entity type and field
   * config.
   *
   * @param string $entity_type_name
   *   The entity type name to get the field handler for.
   * @param string $bundle_name
   *   The entity type bundle name to get the field handler for.
   * @param string $field_name
   *   The field name to get the field handler for.
   *
   * @return \Drupal\cms_content_sync\Plugin\FieldHandlerInterface
   *   The field handler instance for the given configuration.
   */
  public function getFieldHandler($entity_type_name, $bundle_name, $field_name) {
    static $cache = [];

    $cache_key = join(":", [$this->flow->id(), $entity_type_name, $bundle_name, $field_name]);
    if (isset($cache[$cache_key])) {
      return $cache[$cache_key];
    }

    $fieldPluginManager = \Drupal::service('plugin.manager.cms_content_sync_field_handler');

    $config = $this->getPropertyConfig($entity_type_name, $bundle_name, $field_name);

    if (empty($config)) {
      return $cache[$cache_key] = NULL;
    }

    if (Flow::HANDLER_IGNORE == $config['handler']) {
      return $cache[$cache_key] = NULL;
    }

    $entityFieldManager = \Drupal::service('entity_field.manager');
    $field_definition = $entityFieldManager->getFieldDefinitions($entity_type_name, $bundle_name)[$field_name];

    return $cache[$cache_key] = $fieldPluginManager->createInstance(
          $config['handler'],
          [
            'entity_type_name' => $entity_type_name,
            'bundle_name' => $bundle_name,
            'field_name' => $field_name,
            'field_definition' => $field_definition,
            'settings' => $config,
            'sync' => $this->flow,
          ]
      );
  }

}

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

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