cms_content_sync-3.0.x-dev/src/SyncCoreFlowExport.php

src/SyncCoreFlowExport.php
<?php

namespace Drupal\cms_content_sync;

use Drupal\cms_content_sync\Controller\ContentSyncSettings;
use Drupal\cms_content_sync\Entity\Flow;
use Drupal\cms_content_sync\Entity\Pool;
use Drupal\cms_content_sync\Event\BeforeEntityTypeExport;
use Drupal\cms_content_sync\Plugin\Type\EntityHandlerPluginManager;
use Drupal\cms_content_sync\SyncCoreInterface\DrupalApplication;
use Drupal\cms_content_sync\SyncCoreInterface\SyncCoreFactory;
use Drupal\Core\Serialization\Yaml;
use EdgeBox\SyncCore\V2\Raw\Model\RemoteEntityTypePropertyFormat;

/**
 * Class SyncCoreFlowExport used to export the Synchronization config to the Sync
 * Core backend.
 */
class SyncCoreFlowExport extends SyncCoreExport {
  protected $subsequent = FALSE;

  /**
   * @var \Drupal\cms_content_sync\Entity\Flow
   */
  protected $flow;

  /**
   * Sync Core Config constructor.
   *
   * @param \Drupal\cms_content_sync\Entity\Flow $flow
   *   The flow this exporter is used for.
   * @param mixed $subsequent
   */
  public function __construct(Flow $flow, $subsequent = FALSE) {
    $pools = $flow->getController()->getUsedPools();
    $first = reset($pools);
    parent::__construct($first->getClient());

    $this->flow = $flow;
    $this->subsequent = $subsequent;
  }

  /**
   *
   */
  public static function all($machine_names = NULL) {
    foreach (Flow::getAll() as $flow) {
      if (!$machine_names  || in_array($flow->id(), $machine_names)) {
        $flow->getController()->updateEntityTypeVersions();

        $exporter = new SyncCoreFlowExport($flow, TRUE);
        $batch = $exporter->prepareBatch();

        $batch->executeAll();
      }
    }
  }

  /**
   *
   */
  public static function deleteUnusedFlows() {
    // If the site wasn't even registered, we can skip trying to delete Flows from the Sync Core.
    if (!ContentSyncSettings::getInstance()->getSiteUuid()) {
      return;
    }

    // If the module is being uninstalled, we can't communicate with the Sync Core.
    if (!DrupalApplication::get()->getSyncCoreUrl()) {
      return;
    }

    $keep_flows = [];
    // Get all active Flows and add them to the "keep list".
    foreach (Flow::getAll() as $flow) {
      $keep_flows[] = $flow->id;
    }

    $core = SyncCoreFactory::getSyncCoreV2();
    // We are deleting all that are not in the "keep list". This is the
    // most reliable way to delete all unwanted configuration as we
    // may not always be informed about changes of Flows (e.g. when
    // customers use a database dump for deployment or setup), and we
    // want the Flow status to be in sync to avoid unnecessary requests
    // and failures.
    $core->getConfigurationService()->deleteFlows($keep_flows);
  }

  /**
   * Create all entity types, connections and synchronizations as required.
   *
   * @param bool $force
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \EdgeBox\SyncCore\Exception\SyncCoreException
   *
   * @return \EdgeBox\SyncCore\Interfaces\IBatch
   */
  public function prepareBatch($force = FALSE) {
    $pool_configurations = [];

    $batch = $this
      ->client
      ->batch();

    $flow_definition = $this
      ->client
      ->getConfigurationService()
      ->defineFlow(
              $this->flow->id,
              $this->flow->label(),
              Yaml::encode(\Drupal::service('config.storage')->read('cms_content_sync.flow.' . $this->flow->id()))
          )
      ->addToBatch($batch);

    $allowed_languages = $this->flow->getController()->getAllowedLanguages();
    if (!empty($allowed_languages)) {
      $flow_definition->allowedLanguages($allowed_languages);
    }

    $this
      ->addConfiguration($flow_definition, $pool_configurations, $batch, FALSE, $force);

    // Adding these must be done last so that the entity types are always
    // defined before being used. Otherwise the Sync Core will throw an exception.
    foreach ($pool_configurations as $pool_id => $operations) {
      /**
       * @var \EdgeBox\SyncCore\Interfaces\IBatchOperation $pool
       */
      $pool = $operations['pool_definition'];
      $pool->addToBatch($batch);
    }

    return $batch;
  }

  /**
   * Create all entity types, connections and synchronizations as required.
   *
   * @param \EdgeBox\SyncCore\Interfaces\Configuration\IDefineFlow $flow_definition
   * @param $pool_configurations
   * @param \EdgeBox\SyncCore\Interfaces\IBatch $batch
   * @param bool $extend_only
   * @param bool $force
   *
   * @throws \EdgeBox\SyncCore\Exception\SyncCoreException
   */
  public function addConfiguration($flow_definition, &$pool_configurations, $batch, $extend_only = FALSE, $force = FALSE) {
    // Ignore disabled flows at export.
    if (!$this->flow->get('status')) {
      return;
    }

    $enable_preview = ContentSyncSettings::getInstance()->isPreviewEnabled();

    $pools = Pool::getAll();

    $export_pools = [];

    foreach ($this->flow->getController()->getEntityTypeConfig(NULL, NULL, FALSE, TRUE) as $entity_type_name => $bundles) {
      foreach ($bundles as $bundle_name => $type) {
        $version = $type['version'];

        if (Flow::HANDLER_IGNORE == $type['handler']) {
          continue;
        }

        $current = Flow::getEntityTypeVersion($entity_type_name, $bundle_name);
        if ($current !== $version) {
          throw new \Exception("Entity type {$entity_type_name}.{$bundle_name} was changed without updating Flow {$this->flow->id}. Please re-save that Flow first to apply the latest entity type changes.");
        }

        $handler = $this->flow->getController()->getEntityTypeHandler($entity_type_name, $bundle_name, $type);

        $entity_type_pools = [];
        if (isset($type['import_pools'])) {
          foreach ($type['import_pools'] as $pool_id => $state) {
            if (!isset($entity_type_pools[$pool_id])) {
              $entity_type_pools[$pool_id] = [];
            }

            if (PullIntent::PULL_DISABLED == $type['import']) {
              $entity_type_pools[$pool_id]['import'] = Pool::POOL_USAGE_FORBID;

              continue;
            }

            $entity_type_pools[$pool_id]['import'] = $state;
          }
        }

        if (isset($type['export_pools'])) {
          foreach ($type['export_pools'] as $pool_id => $state) {
            if (!isset($entity_type_pools[$pool_id])) {
              $entity_type_pools[$pool_id] = [];
            }

            if (PushIntent::PUSH_DISABLED == $type['export']) {
              $entity_type_pools[$pool_id]['export'] = Pool::POOL_USAGE_FORBID;

              continue;
            }

            $entity_type_pools[$pool_id]['export'] = $state;
          }
        }

        foreach ($entity_type_pools as $pool_id => $definition) {
          if (empty($pools[$pool_id])) {
            continue;
          }

          $pool = $pools[$pool_id];

          $export = NULL;
          $import = NULL;

          if (isset($definition['export'])) {
            $export = $definition['export'];
          }

          if (isset($definition['import'])) {
            $import = $definition['import'];
          }

          if ((!$export || Pool::POOL_USAGE_FORBID == $export) && (!$import || Pool::POOL_USAGE_FORBID == $import)) {
            continue;
          }

          if (!in_array($pool, $export_pools)) {
            $export_pools[] = $pool;
          }

          $entity_type_id_without_version = $entity_type_name . '-' . $bundle_name;

          if ($extend_only) {
            if (!isset($pool_configurations[$pool_id])) {
              continue;
            }
          }

          $pull_condition = [];

          if (EntityHandlerPluginManager::isEntityTypeFieldable($entity_type_name)) {
            $entityFieldManager = \Drupal::service('entity_field.manager');
            /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $fields */
            $fields = $entityFieldManager->getFieldDefinitions($entity_type_name, $bundle_name);

            $forbidden = $handler->getForbiddenFields();

            foreach ($fields as $key => $field) {
              $field_config = $this->flow->getController()->getPropertyConfig($entity_type_name, $bundle_name, $key);
              if (!$field_config) {
                continue;
              }

              if (in_array($key, $forbidden)) {
                continue;
              }
              if (!empty($field_config['handler_settings']['subscribe_only_to'])) {
                $allowed = [];

                foreach ($field_config['handler_settings']['subscribe_only_to'] as $ref) {
                  $allowed[] = $ref['uuid'];
                }

                $pull_condition[$key] = $allowed;
              }
            }
          }

          if ($extend_only) {
            if (isset($pool_configurations[$pool_id]['entity_types'][$entity_type_id_without_version])) {
              if (Pool::POOL_USAGE_FORBID != $import && PullIntent::PULL_DISABLED != $type['import']) {
                /**
                 * @var \EdgeBox\SyncCore\Interfaces\Configuration\IFlowPullConfiguration $pull_configuration
                 */
                $pull_configuration = $pool_configurations[$pool_id]['entity_types'][$entity_type_id_without_version];

                $override = $pull_configuration
                  ->configureOverride($this->flow->id)
                  ->manually(PullIntent::PULL_MANUALLY == $type['import'])
                  ->asDependency(PullIntent::PULL_AS_DEPENDENCY == $type['import'])
                  ->pullDeletions(boolval($type['import_deletion_settings']['import_deletion']));

                foreach ($pull_condition as $property => $allowed_entity_ids) {
                  $override
                    ->ifTaggedWith($property, $allowed_entity_ids);
                }
              }

              continue;
            }
          }

          $entity_type_label = \Drupal::service('entity_type.bundle.info')->getAllBundleInfo()[$entity_type_name][$bundle_name]['label'];
          $entity_type = $this
            ->client
            ->getConfigurationService()
            ->defineEntityType($pool_id, $entity_type_name, $bundle_name, $version, $entity_type_label)
            ->isTranslatable(TRUE);
          $entity_type
            ->addReferenceProperty('menu_items', 'Menu items', TRUE, FALSE, 'menu')
            ->addAllowedType('menu_link_content');

          if (EntityHandlerPluginManager::isEntityTypeFieldable($entity_type_name)) {
            $entityFieldManager = \Drupal::service('entity_field.manager');
            /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $fields */
            $fields = $entityFieldManager->getFieldDefinitions($entity_type_name, $bundle_name);

            $forbidden = $handler->getForbiddenFields();

            $added = [];
            foreach ($fields as $key => $field) {
              $field_config = $this->flow->getController()->getPropertyConfig($entity_type_name, $bundle_name, $key);
              if (!$field_config) {
                continue;
              }

              if (in_array($key, $forbidden)) {
                continue;
              }

              $field_handler = $this->flow->getController()->getFieldHandler($entity_type_name, $bundle_name, $key);
              if (!$field_handler) {
                continue;
              }
              $field_handler->definePropertyAtType($entity_type);

              $added[] = $key;
            }

            if (!in_array('created', $added)) {
              $entity_type
                ->addObjectProperty('created', 'Created', FALSE, FALSE, 'created')
                ->addIntegerProperty('value', 'Value', FALSE, TRUE, 'integer')
                ->setFormat(RemoteEntityTypePropertyFormat::UNIX_TIMESTAMP);
            }
            if (!in_array('changed', $added)) {
              $entity_type
                ->addObjectProperty('changed', 'Changed', FALSE, FALSE, 'changed')
                ->addIntegerProperty('value', 'Value', FALSE, TRUE, 'integer')
                ->setFormat(RemoteEntityTypePropertyFormat::UNIX_TIMESTAMP);
            }
          }

          // Remote sites must use the same entity type handler otherwise sync
          // will fail- at least for these properties or it will not work at all.
          $handler->updateEntityTypeDefinition($entity_type);

          // Dispatch EntityTypeExport event to give other modules the possibility
          // to adjust the entity type definition and add custom fields.
          \Drupal::service('event_dispatcher')->dispatch(
              new BeforeEntityTypeExport($entity_type_name, $bundle_name, $entity_type),
              BeforeEntityTypeExport::EVENT_NAME
            );

          // Create the entity type.
          $entity_type->addToBatch($batch);

          /**
           * @var \EdgeBox\SyncCore\Interfaces\Configuration\IDefinePoolForFlow $pool_definition
           */
          if (isset($pool_configurations[$pool_id])) {
            // If the given entity type has added before, we don't add it a second time.
            $pool_definition = $pool_configurations[$pool_id]['pool_definition'];
          }
          else {
            $pool_definition = $flow_definition
              ->usePool($pool_id);

            $pool_configurations[$pool_id] = [
              'pool_definition' => $pool_definition,
              'entity_types' => [],
            ];
          }

          $pool_definition
            ->useEntityType($entity_type);

          if ($extend_only) {
            continue;
          }

          // Create a synchronization from the pool to the preview connection.
          if ($enable_preview) {
            $pool_definition
              ->enablePreview($entity_type);
          }

          if (Pool::POOL_USAGE_FORBID != $export && PushIntent::PUSH_DISABLED != $type['export']) {
            $push_config = $pool_definition
              ->enablePush($entity_type);
            if ($push_config) {
              $push_config
                ->manually(PushIntent::PUSH_MANUALLY == $type['export'])
                ->asDependency(PushIntent::PUSH_AS_DEPENDENCY == $type['export'])
                ->pushDeletions(boolval($type['export_deletion_settings']['export_deletion']));
            }
          }

          if (Pool::POOL_USAGE_FORBID != $import && PullIntent::PULL_DISABLED != $type['import']) {
            $pull_configuration = $pool_definition
              ->enablePull($entity_type)
              ->manually(PullIntent::PULL_MANUALLY == $type['import'])
              ->asDependency(PullIntent::PULL_AS_DEPENDENCY == $type['import'])
              ->pullDeletions(boolval($type['import_deletion_settings']['import_deletion']))
              ->addToBatch($batch);

            $pool_configurations[$pool_id]['entity_types'][$entity_type_id_without_version] = $pull_configuration;

            foreach ($pull_condition as $property => $allowed_entity_ids) {
              $pull_configuration
                ->ifTaggedWith($property, $allowed_entity_ids);
            }
          }
        }
      }
    }

    if ($extend_only) {
      return;
    }

    // Always export required pools as well to prevent any potential issues.
    $subsequent = $this->subsequent;
    foreach ($export_pools as $pool) {
      $exporter = new SyncCorePoolExport($pool);

      $batch->prepend(
            $exporter->prepareBatch($subsequent, $force)
        );

      $subsequent = TRUE;
    }
  }

}

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

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