contentserialize-8.x-1.x-dev/src/Commands/ContentSerializeCommands.php

src/Commands/ContentSerializeCommands.php
<?php

namespace Drupal\contentserialize\Commands;

use Drupal\bulkentity\EntityLoaderInterface;
use Drupal\contentserialize\Destination\FileDestination;
use Drupal\contentserialize\ExporterInterface;
use Drupal\contentserialize\ImporterInterface;
use Drupal\contentserialize\Source\FileSource;
use Drupal\contentserialize\Traversables;
use Drupal\contentserialize\Utility;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drush\Commands\DrushCommands;

/**
 * Provides drush 9 commands for Content Serialization.
 *
 * D8 standards are not to translate exception messages, but many/all used here
 * are user-facing, like eg. \Drush\Commands\sql\SqlSyncCommands::validate(), so
 * they're passed through dt().
 */
class ContentSerializeCommands extends DrushCommands {

  /**
   * The options provider.
   *
   * @var \Drupal\contentserialize\Commands\ContentSerializeOptionsProvider
   */
  protected $optionsProvider;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The entity type bundle information service.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $bundleInfo;

  /**
   * The bulk entity loader.
   *
   * @var \Drupal\bulkentity\EntityLoaderInterface
   */
  protected $bulkLoader;

  /**
   * The content exporter.
   *
   * @var \Drupal\contentserialize\ExporterInterface
   */
  protected $exporter;

  /**
   * The content importer.
   *
   * @var \Drupal\contentserialize\ImporterInterface
   */
  protected $importer;

  /**
   * Create the content serialization commands object.
   *
   * @param \Drupal\contentserialize\Commands\ContentSerializeOptionsProvider $options_provider
   */
  public function __construct(
    $options_provider,
    EntityTypeManagerInterface $entity_type_manager,
    EntityTypeBundleInfoInterface $bundle_info,
    EntityLoaderInterface $bulk_loader,
    ImporterInterface $importer,
    ExporterInterface $exporter
  ) {
    parent::__construct();
    $this->optionsProvider = $options_provider;
    $this->entityTypeManager = $entity_type_manager;
    $this->bundleInfo = $bundle_info;
    $this->bulkLoader = $bulk_loader;
    $this->importer = $importer;
    $this->exporter = $exporter;
  }

  /**
   * Exports a single entity
   *
   * @param $entity_type
   *   The entity type to export.
   * @param $entity_id
   *   The ID of the entity to export.
   * @param array $options An associative array of options whose values come
   *   from cli, aliases, config, etc.
   *
   * @option destination
   *   Folder to export to; you can also use the environment variable CONTENTSERIALIZE_EXPORT_DESTINATION; defaults to the current directory
   * @option format
   *   The serialization format
   *
   * @command contentserialize:export
   * @aliases cse,contentserialize-export
   * 
   * @throws \Exception
   *   On errors.
   */
  public function export($entity_type, $entity_id, array $options = ['destination' => self::REQ, 'format' => self::REQ]) {
    $entity = $this->loadContentEntity($entity_type, $entity_id);
    $destination = $this->getExportDestination($options);
    list($format, $context) = $this->optionsProvider->getFormatAndContext($options);
    $destination->save($this->exporter->export($entity, $format, $context));
  }

  /**
   * Exports an entity and any others that reference it
   *
   * @param $entity_type
   *   The entity type to export.
   * @param $entity_id
   *   The ID of the entity to export.
   * @param array $options
   *   An associative array of options whose values come from cli, aliases,
   *   config, etc.
   *
   * @option exclude
   *   Entity types and/or bundles to exclude
   * @option destination
   *   Folder to export to; you can also use the environment variable CONTENTSERIALIZE_EXPORT_DESTINATION; defaults to the current directory
   * @option format
   *   The serialization format
   *
   * @command contentserialize:export-referenced
   * @aliases cser,contentserialize-export-referenced
   *
   * @throws \Exception
   *   On error
   */
  public function exportReferenced($entity_type, $entity_id, array $options = ['exclude' => self::REQ, 'destination' => self::REQ, 'format' => self::REQ]) {
    $entity = $this->loadContentEntity($entity_type, $entity_id);

    $destination = $this->getExportDestination($options);
    $entities = Utility::enumerateEntitiesAndDependencies([$entity]);
    $excluded = $this->optionsProvider->getExcluded($options);
    if ($excluded) {
      // Filter out entity types and bundles specified in the exclude option.
      $entities = Traversables::filter($entities, function (ContentEntityInterface $entity) use ($excluded) {
        $entity_type = $entity->getEntityTypeId();
        $bundle = $entity->bundle();
        $type_allowed = !in_array($entity_type, $excluded['entity_type']);
        $bundle_allowed = empty($excluded['bundles'][$entity_type]) || !in_array($bundle, $excluded['bundles'][$entity_type]);
        return $type_allowed && $bundle_allowed;
      });
    }
    list($format, $context) = $this->optionsProvider->getFormatAndContext($options);
    $destination->saveMultiple($this->exporter->exportMultiple($entities, $format, $context));
  }

  /**
   * Exports all content from any appropriate entity types.
   *
   * @param array $options
   *    An associative array of options whose values come from cli, aliases,
   *    config, etc.
   *
   * @option exclude
   *   Entity types and/or bundles to exclude
   * @option destination
   *   Folder to export to; you can also use the environment variable CONTENTSERIALIZE_EXPORT_DESTINATION; defaults to the current directory
   * @option format
   *   The serialization format
   * @usage drush csea
   *   Export all content entities on the site into the current directory.
   * @usage drush csea --destination=/path/to/content
   *   Export all content entities into the specified directory.
   * @usage drush csea --exclude=taxonomy_term
   *   Export all content entities except taxonomy terms.
   * @usage drush csea --exclude=node:page:blog
   *   Export all content entities except the node bundles 'page' and 'blog'.
   * @usage drush csea --exclude=node:page,user
   *   Export all content entities except the node bundle 'page' and users.
   *
   * @command contentserialize:export-all
   * @aliases csea,contentserialize-export-all
   */
  public function exportAll(array $options = ['exclude' => self::REQ, 'destination' => self::REQ, 'format' => self::REQ]) {
    // Filter out any non-content entity types.
    /** @var \Drupal\Core\Entity\EntityTypeInterface[] $definitions */
    $definitions = $this->entityTypeManager->getDefinitions();
    $definitions = array_filter($definitions, function (EntityTypeInterface $definition) {
      return is_a($definition->getClass(), ContentEntityInterface::class, TRUE);
    });
    // Filter out entire entity types specified in the exclude option.
    $excluded = $this->optionsProvider->getExcluded($options);
    if ($excluded) {
      $definitions = array_filter($definitions, function (EntityTypeInterface $definition) use ($excluded) {
        return !in_array($definition->id(), $excluded['entity_type']);
      });
    }
    $destination = $this->getExportDestination($options);
    list($format, $context) = $this->optionsProvider->getFormatAndContext($options);

    $this->output()->writeln(dt("Exporting..."));
    foreach ($definitions as $entity_type_id => $definition) {
      // Filter out bundles specified in the exclude option.
      $bundles = NULL;
      if (!empty($excluded['bundle'][$entity_type_id])) {
        $all_bundles = array_keys($this->bundleInfo->getBundleInfo($entity_type_id));
        $bundles = array_diff($all_bundles, $excluded['bundle'][$entity_type_id]);
      }
      // @todo Make batch size configurable.
      $entities = $this->bulkLoader->byEntityType(50, $entity_type_id, $bundles);
      $destination->saveMultiple($this->exporter->exportMultiple($entities, $format, $context));
      $this->output()->writeln(' - ' . (string) $definition->getLabel());
    }
    $this->output()->writeln(dt("Completed"));
  }

  /**
   * Imports content from a folder.
   *
    * @param array $options An associative array of options whose values come from cli, aliases, config, etc.
   * @option source
   *   Folder(s) to import from in a comma-separated list; you can also use the environment variable CONTENTSERIALIZE_IMPORT_SOURCE; defaults to the current directory
   * @usage drush csi --source=/tmp/import
   *   Import all content in /tmp/import.
   *
   * @command contentserialize:import
   * @aliases csi,contentserialize-import
   *
   * @throws \Exception
   *   On import errors.
   */
  public function import(array $options = ['source' => self::REQ]) {
    $sources = $this->getImportSources($options);
    // Ensure the same entity isn't returned twice and that earlier entities
    // take priority over later ones.
    $merged = Traversables::uniqueByKey(Traversables::merge(...$sources));
    $result = $this->importer->import($merged);
    if ($result->getFailures()) {
      throw new \Exception(dt("There were errors on import."));
    }
    else {
      $this->io()->writeln(dt("Import completed successfully."));
    }
  }

  /**
   * Try to load the specified content entity.
   *
   * @param string $entity_type_id
   *   The entity type ID.
   * @param int|string $entity_id
   *   The entity ID.
   *
   * @return \Drupal\Core\Entity\ContentEntityInterface|false
   *   The loaded content entity, or FALSE on failure.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   *   If the entity type isn't valid.
   * @throws \Exception
   *   On error
   */
  protected function loadContentEntity($entity_type_id, $entity_id) {
    $storage = $this->entityTypeManager->getStorage($entity_type_id);
    $class = $storage->getEntityType()->getClass();
    if (!is_subclass_of($class, ContentEntityInterface::class, TRUE)) {
      throw new \Exception(dt("Content serialization can only export content entities."));
    }
    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = $storage->load($entity_id);
    if (!$entity) {
      throw new \Exception(dt("Couldn't load @entity_type with ID @entity_id", ['@entity_type' => $entity_type_id, '@entity_id' => $entity_id]));
    }

    return $entity;
  }

  /**
   * Get the export destination.
   *
   * @param array $options
   *   The command's options array; the 'format' key will be used if present.
   *
   * @return \Drupal\contentserialize\Destination\DestinationInterface
   *
   * @see \Drupal\contentserialize\Commands\ContentSerializeOptionsProvider::getExportFolder()
   */
  protected function getExportDestination($options) {
    return new FileDestination($this->optionsProvider->getExportFolder($options));
  }

  /**
   * Get the import sources.
   *
   * @param array $options
   *   The command's options array; the 'source' key will be used if present.
   *
   * @return \Drupal\contentserialize\Source\SourceInterface[]
   *   An array of import sources in priority order (an entity will only be
   *   imported the first time it's encountered).
   *
   * @see \Drupal\contentserialize\Commands\ContentSerializeOptionsProvider::getImportFolders()
   */
  protected function getImportSources(array $options) {
    return array_map(function ($source) {
      return new FileSource($source);
    }, $this->optionsProvider->getImportFolders($options));
  }

}

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

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