Skip to content

Commit

Permalink
Add Module Files - Content Sync. Import/Export content entity from/to…
Browse files Browse the repository at this point in the history
… single yaml file, Import/Export content site content entities from/to a tar file.
  • Loading branch information
Blanca.Esqueda committed Apr 26, 2017
1 parent 4cb6245 commit 133e862
Show file tree
Hide file tree
Showing 13 changed files with 1,671 additions and 0 deletions.
776 changes: 776 additions & 0 deletions content_sync.batch.inc

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions content_sync.info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: 'Content Sync'
type: module
description: 'Allows to import/export content using YAML files'
package: Custom
core: 8.x
configure: content.sync
5 changes: 5 additions & 0 deletions content_sync.links.menu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
content.sync:
title: 'Content synchronization'
description: 'Import and export your content.'
route_name: content.sync
parent: system.admin_config_development
34 changes: 34 additions & 0 deletions content_sync.links.task.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
content.sync:
title: 'Synchronize'
route_name: content.sync
base_route: content.sync

content.import:
title: 'Import'
route_name: content.import_full
base_route: content.sync

content.import_single:
title: 'Single Item Import'
route_name: content.import_single
parent_id: content.import

content.import_full:
title: 'Archive Import'
route_name: content.import_full
parent_id: content.import

content.export:
route_name: content.export_full
title: 'Export'
base_route: content.sync

content.export_single:
route_name: content.export_single
title: 'Single Item'
parent_id: content.export

content.export_full:
route_name: content.export_full
title: 'Archive'
parent_id: content.export
78 changes: 78 additions & 0 deletions content_sync.module
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
/**
* @file
* Allows site administrators to modify content.
*/

use Drupal\Core\Routing\RouteMatchInterface;

/**
* Implements hook_help().
*/
function content_sync_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.content':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Content Synchronization module provides a user interface for importing and exporting content changes between installations of your website in different environments. Content is stored in YAML format. For more information, see the <a href=":url">online documentation for the Content Synchronization module</a>.', [':url' => 'https://www.drupal.org/project/content_sync']) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Exporting the full content') . '</dt>';
$output .= '<dd>' . t('You can create and download an archive consisting of all your site\'s content exported as <em>*.yml</em> files on the <a href=":url">Export</a> page.', [':url' => \Drupal::url('content.export_full')]) . '</dd>';
$output .= '<dt>' . t('Importing a full content') . '</dt>';
$output .= '<dd>' . t('You can upload a full site content from an archive file on the <a href=":url">Import</a> page. When importing data from a different environment, the site and import files must have matching configuration values for UUID in the <em>system.site</em> configuration item. That means that your other environments should initially be set up as clones of the target site. Migrations are not supported.', [':url' => \Drupal::url('content.import_full')]) . '</dd>';
$output .= '<dt>' . t('Exporting a single content item') . '</dt>';
$output .= '<dd>' . t('You can export a single content item by selecting a <em>Content type</em> and <em>Content name</em> on the <a href=":single-export">Single export</a> page. The content and its corresponding <em>*.yml file name</em> are then displayed on the page for you to copy.', [':single-export' => \Drupal::url('content.export_single')]) . '</dd>';
$output .= '<dt>' . t('Importing a single content item') . '</dt>';
$output .= '<dd>' . t('You can import a single content item by pasting it in YAML format into the form on the <a href=":single-import">Single import</a> page.', [':single-import' => \Drupal::url('content.import_single')]) . '</dd>';
$output .= '</dl>';
return $output;

case 'content.export_full':
$output = '';
$output .= '<p>' . t('Export and download the full content of this site as a gzipped tar file.') . '</p>';
return $output;

case 'content.import_full':
$output = '';
$output .= '<p>' . t('Upload a full site content archive to the content sync directory to be imported.') . '</p>';
return $output;

case 'content.export_single':
$output = '';
$output .= '<p>' . t('Choose a content item to display its YAML structure.') . '</p>';
return $output;

case 'content.import_single':
$output = '';
$output .= '<p>' . t('Import a single content item by pasting its YAML structure into the text field.') . '</p>';
return $output;

case 'content.import_template':
$output = '';
$output .= '<p>' . t('Choose a content item to display its YAML structure.') . '</p>';
return $output;
}
}

/**
* Implements hook_file_download().
*/
function content_file_download($uri) {
$scheme = file_uri_scheme($uri);
$target = file_uri_target($uri);
if ($scheme == 'temporary' && $target == 'content.tar.gz') {
if (\Drupal::currentUser()->hasPermission('export content')) {
$request = \Drupal::request();
$date = DateTime::createFromFormat('U', $request->server->get('REQUEST_TIME'));
$date_string = $date->format('Y-m-d-H-i');
$hostname = str_replace('.', '-', $request->getHttpHost());
$filename = 'content' . '-' . $hostname . '-' . $date_string . '.tar.gz';
$disposition = 'attachment; filename="' . $filename . '"';
return [
'Content-disposition' => $disposition,
];
}
return -1;
}
}
9 changes: 9 additions & 0 deletions content_sync.permissions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
synchronize content:
title: 'Synchronize content'
restrict access: true
export content:
title: 'Export content'
restrict access: true
import content:
title: 'Import content'
restrict access: true
48 changes: 48 additions & 0 deletions content_sync.routing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
content.sync:
path: '/admin/config/development/content'
defaults:
_title: 'Synchronize'
_form: '\Drupal\content_sync\Form\ContentSync'
requirements:
_permission: 'synchronize content'

content.import_single:
path: '/admin/config/development/content/import/single'
defaults:
_title: 'Single Import'
_form: '\Drupal\content_sync\Form\ContentSingleImportForm'
requirements:
_permission: 'import content'

content.import_full:
path: '/admin/config/development/content/import/full'
defaults:
_title: 'Import Archives'
_form: '\Drupal\content_sync\Form\ContentImportForm'
requirements:
_permission: 'import content'

content.export_full:
path: '/admin/config/development/content/export/full'
defaults:
_title: 'Export Archives'
_form: '\Drupal\content_sync\Form\ContentExportForm'
requirements:
_permission: 'export content'

content.export_download:
path: '/admin/config/development/content/export/download'
defaults:
_controller: '\Drupal\content_sync\Controller\ContentController::downloadExport'
requirements:
_permission: 'export content'

content.export_single:
path: '/admin/config/development/content/export/single'
defaults:
_title: 'Single Export'
_form: '\Drupal\content_sync\Form\ContentSingleExportForm'
config_type: NULL
config_name: NULL
requirements:
_permission: 'export content'
64 changes: 64 additions & 0 deletions src/Controller/ContentController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace Drupal\content_sync\Controller;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\system\FileDownloadController;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Drupal\Component\Utility\Unicode;

/**
* Returns responses for content_yaml module routes.
*/
class ContentController implements ContainerInjectionInterface {

/**
* The file download controller.
*
* @var \Drupal\system\FileDownloadController
*/
protected $fileDownloadController;

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
new FileDownloadController()
);
}

/**
* Constructs a ContentController object.
*
* @param \Drupal\system\FileDownloadController $file_download_controller
* The file download controller.
*/
public function __construct(FileDownloadController $file_download_controller) {
$this->fileDownloadController = $file_download_controller;
}

/**
* Downloads a tarball of the site content.
*/
public function downloadExport() {
// NOTE: Getting - You are not authorized to access this page.
//$request = new Request(['file' => 'content.tar.gz']);
//return $this->fileDownloadController->download($request, 'temporary');
$filename = 'content.tar.gz';
$file_path = file_directory_temp() . '/' . $filename;
if (file_exists($file_path) ) {
unset($_SESSION['content_tar_download_file']);
$mime = \Drupal::service('file.mime_type.guesser')->guess($file_path);
$headers = array(
'Content-Type' => $mime . '; name="' . Unicode::mimeHeaderEncode(basename($file_path)) . '"',
'Content-Length' => filesize($file_path),
'Content-Disposition' => 'attachment; filename="' . Unicode::mimeHeaderEncode($filename) . '"',
'Cache-Control' => 'private',
);
return new BinaryFileResponse($file_path, 200, $headers);
}
return -1;
}
}
92 changes: 92 additions & 0 deletions src/Form/ContentExportForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

namespace Drupal\content_sync\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\ContentEntityType;

/**
* Defines the content export form.
*/
class ContentExportForm extends FormBase {

/**
* {@inheritdoc}
*/
public function getFormId() {
return 'content_export_form';
}

/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Export'),
];
return $form;
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Delete the content tar file in case an older version exist.
file_unmanaged_delete(file_directory_temp() . '/content.tar.gz');

//Entity types manager
$entityTypeManager = \Drupal::entityTypeManager();
$entityBundles = \Drupal::service("entity_type.bundle.info");
//Set batch operations by entity type/bundle
$operations = [];
$entity_type_definitions = $entityTypeManager->getDefinitions();
foreach ($entity_type_definitions as $entity_type => $definition) {
if ($definition instanceof ContentEntityType) {
$entity_bundles = $entityBundles->getBundleInfo($entity_type);
foreach ($entity_bundles as $entity_bundle => $bundle) {
//Get BundleKey
$bundleKey = \Drupal::entityTypeManager()->getStorage($entity_type)->getEntityType()->getKey('bundle');
if (!empty($bundleKey)) {
// Load entities by their property values.
$entities = \Drupal::entityTypeManager()
->getStorage($entity_type)
->loadByProperties(array($bundleKey => $entity_bundle));
}else{
$entities = \Drupal::entityTypeManager()
->getStorage($entity_type)
->loadMultiple();
}
$entity = [];
foreach($entities as $entity_id => $entity_obj) {
$entity['values'][] = [
'entity_type' => $entity_type,
'entity_bundle' => $entity_bundle,
'entity_id' => $entity_id
];
}
if(!empty($entity)) {
$operations[] = ['processContentExportFiles', $entity];
}
}
}
}
if(empty($operations)){
$operations[] = ['processContentExportFiles', [0=>0] ];
}
//kint($operations);
// exit;
//Set Batch
$batch = [
'operations' => $operations,
'finished' => 'finishContentExportBatch',
'title' => $this->t('Exporting content'),
'init_message' => $this->t('Starting content export.'),
'progress_message' => $this->t('Completed @current step of @total.'),
'error_message' => $this->t('Content export has encountered an error.'),
'file' => drupal_get_path('module', 'content_sync') . '/content_sync.batch.inc',
];
batch_set($batch);
}
}
Loading

0 comments on commit 133e862

Please sign in to comment.