You are here

FlowControllerBase.php in CMS Content Sync 2.1.x

File

src/Controller/FlowControllerBase.php
View source
<?php

namespace Drupal\cms_content_sync\Controller;

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

  /**
   * @var Flow
   */
  protected $flow;
  public function __construct(Flow $flow) {
    $this->flow = $flow;
  }

  /**
   * @inheritDoc
   */
  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;
  }

  /**
   * @inheritDoc
   */
  public function canPushEntityType($entity_type_name, $bundle_name, $reason, $action = SyncIntent::ACTION_CREATE, $pool = null) {
    $any_reason = [
      PushIntent::PUSH_AUTOMATICALLY,
      PushIntent::PUSH_MANUALLY,
      PushIntent::PUSH_AS_DEPENDENCY,
    ];
    if (is_string($reason)) {
      if (PushIntent::PUSH_ANY === $reason || PushIntent::PUSH_FORCED === $reason) {
        $reason = $any_reason;
      }
      else {
        $reason = [
          $reason,
        ];
      }
    }
    if (!$bundle_name) {
      foreach ($this
        ->getEntityTypeConfig($entity_type_name) as $bundles) {
        foreach ($bundles 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;
      }
    }
    return in_array($config['export'], $reason);
  }

  /**
   * @inheritDoc
   */
  public function canPushEntity(EntityInterface $entity, $reason, $action = SyncIntent::ACTION_CREATE, $pool = null) {
    $infos = $entity
      ->uuid() ? EntityStatus::getInfosForEntity($entity
      ->getEntityTypeId(), $entity
      ->uuid()) : [];

    // 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);
  }

  /**
   * Get a list of all pools that are used for pushing this entity, either
   * automatically or manually selected.
   *
   * @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 Pool[]
   */
  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 a list of all pools that are used for pushing this entity, either
   * automatically or manually selected.
   *
   * @param string $entity_type
   * @param string $bundle
   *
   * @return Pool[]
   */
  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 Pool[]
   */
  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 Pool $pool
   *
   * @return bool
   */
  public function usesPool($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 push the provided entity.
   *
   * @param string $entity_type_name
   * @param string $bundle_name
   * @param string $reason
   * @param string $action
   * @param bool   $strict
   *                                 If asking for DEPENDENCY as a $reason, then $strict will NOT include a Flow that pulls AUTOMATICALLY
   *
   * @return bool
   */
  public function canPullEntity($entity_type_name, $bundle_name, $reason, $action = SyncIntent::ACTION_CREATE, $strict = 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
   */
  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 $config
   *   {@see Flow::getEntityTypeConfig()}
   *
   * @return \Drupal\cms_content_sync\Plugin\EntityHandlerInterface
   */
  public function getEntityTypeHandler(string $entity_type_name, string $bundle_name, $config) {
    $entityPluginManager = \Drupal::service('plugin.manager.cms_content_sync_entity_handler');
    return $entityPluginManager
      ->createInstance($config['handler'], [
      'entity_type_name' => $entity_type_name,
      'bundle_name' => $bundle_name,
      'settings' => $config,
      'sync' => $this->flow,
    ]);
  }

  /**
   * Get the correct field handler instance for this entity type and field
   * config.
   *
   * @param $entity_type_name
   * @param $bundle_name
   * @param $field_name
   *
   * @return \Drupal\cms_content_sync\Plugin\FieldHandlerInterface
   */
  public function getFieldHandler($entity_type_name, $bundle_name, $field_name) {
    $fieldPluginManager = \Drupal::service('plugin.manager.cms_content_sync_field_handler');
    $config = $this
      ->getPropertyConfig($entity_type_name, $bundle_name, $field_name);
    if (empty($config)) {
      return null;
    }
    if (Flow::HANDLER_IGNORE == $config['handler']) {
      return null;
    }
    $entityFieldManager = \Drupal::service('entity_field.manager');
    $field_definition = $entityFieldManager
      ->getFieldDefinitions($entity_type_name, $bundle_name)[$field_name];
    return $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,
    ]);
  }

  /**
   * Get the preview type.
   *
   * @param $entity_type_name
   * @param $bundle_name
   *
   * @return string
   */
  public function getPreviewType($entity_type_name, $bundle_name) {
    $previews_enabled = ContentSyncSettings::getInstance()
      ->isPreviewEnabled();
    if (!$previews_enabled) {
      return Flow::PREVIEW_DISABLED;
    }
    $config = $this
      ->getEntityTypeConfig($entity_type_name, $bundle_name);
    if (empty($config['preview'])) {
      return Flow::PREVIEW_DISABLED;
    }
    return $config['preview'];
  }

}

Classes

Namesort descending Description
FlowControllerBase