Commit c1472b02 authored by larowlan's avatar larowlan

Merge pull request #15 from dawehner/export-dependencies

provide support to export entities with all its references
parents 1406ebc1 698ac6c3
......@@ -10,6 +10,7 @@
*/
function default_content_modules_installed($modules) {
// @todo Move this to an event once we have HookEvent.
\Drupal::service('router.builder')->rebuild();
foreach ($modules as $module) {
if (!\Drupal::isConfigSyncing()) {
\Drupal::service('default_content.manager')->importContent($module);
......
......@@ -18,6 +18,19 @@ function default_content_drush_command() {
'options' => [
'file' => dt('Write out the exported content to a file instead of stdout'),
],
'aliases' => ['dce'],
'required-arguments' => 2,
];
$items['default-content-export-references'] = [
'description' => dt('Exports an entity and all its referenced entities.'),
'arguments' => [
'entity_type' => dt('The entity type to export.'),
'entity_id' => dt('The ID of the entity to export.'),
],
'options' => [
'folder' => dt('Folder to export to, entities are grouped by entity type into directories.'),
],
'aliases' => ['dcer'],
'required-arguments' => 2,
];
......@@ -31,9 +44,6 @@ function default_content_drush_command() {
* The entity type ID.
* @param $entity_id
* The entity ID to export.
*
* @return string
* The rendered export as hal.
*/
function drush_default_content_export($entity_type_id, $entity_id) {
/** @var \Drupal\default_content\DefaultContentManagerInterface $manager */
......@@ -47,3 +57,28 @@ function drush_default_content_export($entity_type_id, $entity_id) {
drush_print($export);
}
}
/**
* Exports a piece of content and all its referenced entities.
*
* @param string $entity_type_id
* The entity type ID.
* @param mixed $entity_id
* The entity ID to export.
*/
function drush_default_content_export_references($entity_type_id, $entity_id) {
/** @var \Drupal\default_content\DefaultContentManagerInterface $manager */
$manager = \Drupal::service('default_content.manager');
$folder = drush_get_option('folder', '.');
$serialized_by_type = $manager->exportContentWithReferences($entity_type_id, $entity_id);
foreach ($serialized_by_type as $entity_type => $serialized_entities) {
// Ensure that the folder per entity type exists.
$entity_type_folder = "$folder/$entity_type";
file_prepare_directory($entity_type_folder, FILE_CREATE_DIRECTORY);
foreach ($serialized_entities as $entity_id => $serialized_entity) {
file_put_contents($entity_type_folder . '/' . $entity_id . '.json', $serialized_entity);
}
}
}
......@@ -7,6 +7,9 @@
namespace Drupal\default_content;
use Drupal\Component\Utility\String;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityManager;
use Drupal\Core\Session\AccountInterface;
use Drupal\rest\Plugin\Type\ResourcePluginManager;
......@@ -165,6 +168,65 @@ class DefaultContentManager implements DefaultContentManagerInterface {
return $this->serializer->serialize($entity, 'hal_json', ['json_encode_options' => JSON_PRETTY_PRINT]);
}
/**
* {@inheritdoc}
*/
public function exportContentWithReferences($entity_type_id, $entity_id) {
$storage = $this->entityManager->getStorage($entity_type_id);
$entity = $storage->load($entity_id);
if (!$entity) {
throw new \InvalidArgumentException(String::format('Entity @type with ID @id does not exist', ['@type' => $entity_type_id, '@id' => $entity_id]));
}
/** @var \Drupal\Core\Entity\ContentEntityInterface[] $entities */
$entities = [$entity];
$entities = array_merge($entities, $this->getEntityReferencesRecursive($entity));
$serialized_entities_per_type = [];
// Serialize all entities and key them by entity TYPE and uuid.
foreach ($entities as $entity) {
$serialized_entities_per_type[$entity->getEntityTypeId()][$entity->uuid()] = $this->serializer->serialize($entity, 'hal_json', ['json_encode_options' => JSON_PRETTY_PRINT]);
}
return $serialized_entities_per_type;
}
/**
* Returns all referenced entities of an entity.
*
* This method is also recursive to support usecases like a node -> media
* -> file.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The entity.
* @param int $depth
* Guard against infinite recursion.
*
* @return \Drupal\Core\Entity\EntityInterface[]
*/
protected function getEntityReferencesRecursive(ContentEntityInterface $entity, $depth = 0) {
$entity_dependencies = $entity->referencedEntities();
foreach ($entity_dependencies as $id => $dependent_entity) {
// Config entities should not be exported but rather provided by default
// config.
if ($dependent_entity instanceof ConfigEntityInterface) {
unset($entity_dependencies[$id]);
}
else {
$entity_dependencies = array_merge($entity_dependencies, $this->getEntityReferencesRecursive($dependent_entity, $depth + 1));
}
}
// Build in some support against infinite recursion.
if ($depth > 5) {
return $entity_dependencies;
}
return array_unique($entity_dependencies, SORT_REGULAR);
}
/**
* Utility to get a default content scanner
*
......
......@@ -44,4 +44,17 @@ interface DefaultContentManagerInterface {
*/
public function exportContent($entity_type_id, $entity_id);
/**
* Exports a single entity and all its referenced entity.
*
* @param string $entity_type_id
* The entity type ID.
* @param mixed $entity_id
* The entity ID to export.
*
* @return string[][]
* The serialized entities keyed by entity type and UUID.
*/
public function exportContentWithReferences($entity_type_id, $entity_id);
}
<?php
/**
* @file
* Contains \Drupal\default_content\Tests\DefaultContentManagerIntegrationTest.
*/
namespace Drupal\default_content\Tests;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\simpletest\KernelTestBase;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\user\Entity\User;
/**
* @coversDefaultClass \Drupal\default_content\DefaultContentManager
* @group default_content
*/
class DefaultContentManagerIntegrationTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* The tested default content manager.
*
* @var \Drupal\default_content\DefaultContentManager
*/
protected $defaultContentManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', ['router', 'sequences']);
}
/**
* Tests exportContent().
*/
public function testExportContent() {
\Drupal::moduleHandler()->install(['taxonomy', 'default_content']);
\Drupal::service('router.builder')->rebuild();
$this->defaultContentManager = \Drupal::service('default_content.manager');
$vocabulary = Vocabulary::create(['vid' => 'test']);
$vocabulary->save();
$term = Term::create(['vid' => $vocabulary->id(), 'name' => 'test_name']);
$term->save();
$term = Term::load($term->id());
/** @var \Symfony\Component\Serializer\Serializer $serializer */
$serializer = \Drupal::service('serializer');
$expected = $serializer->serialize($term, 'hal_json', ['json_encode_options' => JSON_PRETTY_PRINT]);
$exported = $this->defaultContentManager->exportContent('taxonomy_term', $term->id());
$exported_decoded = json_decode($exported);
// Ensure the proper UUID is part of it.
$this->assertEqual($exported_decoded->uuid[0]->value, $term->uuid());
$this->assertEqual($exported, $expected);
}
/**
* Tests exportContentWithReferences().
*/
public function testExportWithReferences() {
\Drupal::moduleHandler()->install(['node', 'default_content']);
\Drupal::service('router.builder')->rebuild();
$this->defaultContentManager = \Drupal::service('default_content.manager');
$user = User::create(['name' => 'my username']);
$user->save();
// Reload the user to get the proper casted values from the DB.
$user = User::load($user->id());
$node_type = NodeType::create(['type' => 'test']);
$node_type->save();
$node = Node::create(['type' => $node_type->id(), 'title' => 'test node', 'uid' => $user->id()]);
$node->save();
// Reload the node to get the proper casted values from the DB.
$node = Node::load($node->id());
/** @var \Symfony\Component\Serializer\Serializer $serializer */
$serializer = \Drupal::service('serializer');
$expected_node = $serializer->serialize($node, 'hal_json', ['json_encode_options' => JSON_PRETTY_PRINT]);
$expected_user = $serializer->serialize($user, 'hal_json', ['json_encode_options' => JSON_PRETTY_PRINT]);
$exported_by_entity_type = $this->defaultContentManager->exportContentWithReferences('node', $node->id());
// Ensure that the node type is not tryed to be exported.
$this->assertEqual(array_keys($exported_by_entity_type), ['node', 'user']);
// Ensure the right UUIDs are exported.
$this->assertEqual([$node->uuid()], array_keys($exported_by_entity_type['node']));
$this->assertEqual([$user->uuid()], array_keys($exported_by_entity_type['user']));
// Compare the actual serialized data.
$this->assertEqual(reset($exported_by_entity_type['node']), $expected_node);
$this->assertEqual(reset($exported_by_entity_type['user']), $expected_user);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment