Module Description
Introduction This module allows you to export content entities in a zip file. Then you can import this content in another environment. This is useful for sharing and updating content betweens several environment of site (prod, staging, development...)
Need : cocur/slugify ( automaticly pulled by composer )
How to use Export
Once you enable the module, an "Export" fieldset will appear on each entity edit form. With this form part, you will be able to export the single entity or add it to an "Export entity" that allows you to download several entities in a single export. For example you can donwload several nodes that you have created in your staging project, and you want to send it to your production project. So first you have to create and download a zip of your staging content :
Single entity export The export entity button in the entity form will simply create a zip file. All content, referenced entities, and referenced files will be stocked in this archive. So if a single entity has many references, the archive can be heavy. The module doesn't take care of the configuration. It only stockes content data in some json files.
Several entities export If you want to add several entities to an export, you first have to create an Export entity : 1. Go to Content > Content Synchronizer > Export > Add Export. 2. Create an export with a name. 3. Then, in the entities edit form, you will see the list of exports in the "Export" fieldset. Choose the exports in which you want to add your entity. 4. Go back in Content > Content Synchronizer > Export. Choose your export. In the view tab you will see the list of entities you have added. You can select only the entities you want to download. 5. Launch the Export to download the archive.
Export entity action There is a faster way to add several entities (such as nodes) to an export by using the content view action. In the content view you can select several nodes and then select the "Export entity" in the bulk action list. Then you will be able to add selected entities to an export or create a zip on the fly.
Import
Create an import entity Once you have downloaded a zip file containing the content (and its dependencies) you want to import, you have to create an import entity with this zip archive file. 1. Go to Content > Content Synchronizer > Import 2. Add a new Import. And upload the zip file you just created during the export step. 3. Go to the view tab of your new import. You will see the list of the entities you want to import. In the view, there is a the status of the entity : create or update.
In some case, as the dependencies are exported, the zip file will be to heavy (according to media or whatever) for a simple upload via the web interface. In this case you can create an import entity from a zip file already uploaded on your server by a drush command : drush csci /absolute/path/to/the/file.zip
Launch an import In the import entity view, before launching the import, you can choose several options for the creation and update of the entities you import. 1. Entity creation : - Automatically publish the entity that will be created. - Do not publish the entity that will ne created. This option is available only for publishable entities.
2. Entity update : - Always update existing entity with importing content : This will always update the existing entity with imported content. It doesn't matter of the last change date. - Update existing entity with importing content only if the last change date of importing content is more recent than the last change date of the corresponding existing entity This will check the last change date of the existing entity and the corresponding entity being imported. If the last change date of the entity being imported is more recent than the last change date of the existing entity, the existing entity will be updated. If the entity is revisionnable, the process will create a new revision of the existing entity with the imported data. - Do not update existing content This will not update existing entity.
Developers Process
The export process Here is the process when exporting an entity :
* Get the entity type plugin (EntityProcessorPlugin)
* Call the "export" method of the plugin.
* The plugin then will call the "getDataToExport" that returns an array of data
* The "getDataToExport" will parse each field of the entity
* Get the field type plugin (TypeProcessorPlugin)
* Call "getExportedData" that returns an array of values of the field. The type processor plugin will treat dependencies if it references other entities
* The array of data is stocked in a .json file named with the entity type id
The import process Here is the process when importing an entity :
* Parse the .json file of the entity type
* Get the entity type plugin (EntityProcessorPlugin)
* Call the "getEntityToImport" method.
* The "getEntityToImport" will parse each field of the entity
* Get the field type plugin (TypeProcessorPlugin)
* Call "initImportedEntity" that inits the imported entity with field data. The type will treat dependencies if it references other entities.
* The entity is created or updated according to import options
Export custom entities
As you can see in the export process, if you want to create an export process for custom entities, you will have to create two plugins, one for the entity processor, and another one for the field type processor. The two plugins have to implements to methods, one for the import process, and another one for the export process. You can see examples in the module sources.
The entity processor plugin example : namespace Drupal\content_synchronizer\Plugin\content_synchronizer\entity_processor; use Drupal\content_synchronizer\Processors\Entity\EntityProcessorBase; use Drupal\Core\Entity\Entity; use Drupal\node\Entity\Node; /** * Plugin implementation of the 'accordion' formatter. * * @EntityProcessor( * id = "content_synchronizer_node_processor", * entityType = "node" * ) */ class NodeProcessor extends EntityProcessorBase { /** * {@inheritdoc} */ public function getEntityToImport(array $data, Entity $existingEntity = NULL) { if (is_null($existingEntity)) { $existingEntity = Node::create(['type' => $this->getDefaultLanguageData($data)['type']]); } return parent::getEntityToImport($data, $existingEntity); } /** * {@inheritdoc} */ public function getDataToExport(Entity $entityToExport) { // Init data to export: $data = parent::getDataToExport($entityToExport); // Add bundle : $data['type'] = $entityToExport->bundle(); return $data; } } The type processor plugin example : namespace Drupal\content_synchronizer\Plugin\content_synchronizer\type_processor; use Drupal\Core\Entity\Entity; use Drupal\Core\TypedData\TypedData; use Drupal\content_synchronizer\Processors\Type\TypeProcessorBase; /** * Plugin implementation For the type processor . * * @TypeProcessor( * id = "content_synchronzer_field_item_list_type_processor", * fieldType = "Drupal\Core\Field\FieldItemList" * ) */ class FieldItemListProcessor extends TypeProcessorBase { /** * {@inheritdoc} */ public function getExportedData(TypedData $propertyData) { $data = []; foreach ($propertyData as $order => $value) { $data[] = $value->getValue(); } return $data; } /** * {@inheritdoc} */ public function initImportedEntity(Entity $entityToImport, $propertyId, array $data) { if (array_key_exists($propertyId, $data)) { $entityToImport->set($propertyId, $data[$propertyId]); } } } Available hooks
You can use hooks in order to set entity data that will be exported, or set entity before import.
/** * Update entity data before export. * * @param array $exportedData * The generated data. * @param \Drupal\Core\Entity\Entity $entity * The entity to export */ function MODULE_content_synchronizer_export_data_alter(array &$exportedData, \Drupal\Core\Entity\Entity $entity) { // @todo : Do wathever you want on the $exportedData before it is written in the .json file. } /** * Update entity before import. * * @param \Drupal\Core\Entity\Entity|NULL $entity * Entity that will be saved. * @param \Drupal\Core\Entity\Entity|NULL $existingEntity * Clone of an existing entity before the entity has been set with data to import. * @param array $dataToImport * The data to import. */ function MODULE_content_synchronizer_import_entity_alter(\Drupal\Core\Entity\Entity $entity = NULL, \Drupal\Core\Entity\Entity $existingEntity = NULL, array $dataToImport = []) { // @todo : Do wathever you want on the $entity before it is saved } Drush commands drush content-synchronizer-create-import (drush csci)
Create an import from a specified zip file. This command is usefull when export files are to heavy to be uplaoded in browser. So you can create an import from a big zip file from this drush command. Ex : drush csci ./my_export.zip
drush content-synchronizer-clean-temporary-files (drush csctf)
Clean temporary files created by content_synchronizer. Ex : drush csctf
drush content-synchronizer-launch-export (drush cslex)
Launch the specified export from the specified export id. This will generate a zip file and output the path of the generated archive. Ex : drush cslex 13
drush content-synchronizer-launch-import (drush cslim)
Launch the specified import from the specified import id. Ex: drush cslim 2
Need : cocur/slugify ( automaticly pulled by composer )
How to use Export
Once you enable the module, an "Export" fieldset will appear on each entity edit form. With this form part, you will be able to export the single entity or add it to an "Export entity" that allows you to download several entities in a single export. For example you can donwload several nodes that you have created in your staging project, and you want to send it to your production project. So first you have to create and download a zip of your staging content :
Single entity export The export entity button in the entity form will simply create a zip file. All content, referenced entities, and referenced files will be stocked in this archive. So if a single entity has many references, the archive can be heavy. The module doesn't take care of the configuration. It only stockes content data in some json files.
Several entities export If you want to add several entities to an export, you first have to create an Export entity : 1. Go to Content > Content Synchronizer > Export > Add Export. 2. Create an export with a name. 3. Then, in the entities edit form, you will see the list of exports in the "Export" fieldset. Choose the exports in which you want to add your entity. 4. Go back in Content > Content Synchronizer > Export. Choose your export. In the view tab you will see the list of entities you have added. You can select only the entities you want to download. 5. Launch the Export to download the archive.
Export entity action There is a faster way to add several entities (such as nodes) to an export by using the content view action. In the content view you can select several nodes and then select the "Export entity" in the bulk action list. Then you will be able to add selected entities to an export or create a zip on the fly.
Import
Create an import entity Once you have downloaded a zip file containing the content (and its dependencies) you want to import, you have to create an import entity with this zip archive file. 1. Go to Content > Content Synchronizer > Import 2. Add a new Import. And upload the zip file you just created during the export step. 3. Go to the view tab of your new import. You will see the list of the entities you want to import. In the view, there is a the status of the entity : create or update.
In some case, as the dependencies are exported, the zip file will be to heavy (according to media or whatever) for a simple upload via the web interface. In this case you can create an import entity from a zip file already uploaded on your server by a drush command : drush csci /absolute/path/to/the/file.zip
Launch an import In the import entity view, before launching the import, you can choose several options for the creation and update of the entities you import. 1. Entity creation : - Automatically publish the entity that will be created. - Do not publish the entity that will ne created. This option is available only for publishable entities.
2. Entity update : - Always update existing entity with importing content : This will always update the existing entity with imported content. It doesn't matter of the last change date. - Update existing entity with importing content only if the last change date of importing content is more recent than the last change date of the corresponding existing entity This will check the last change date of the existing entity and the corresponding entity being imported. If the last change date of the entity being imported is more recent than the last change date of the existing entity, the existing entity will be updated. If the entity is revisionnable, the process will create a new revision of the existing entity with the imported data. - Do not update existing content This will not update existing entity.
Developers Process
The export process Here is the process when exporting an entity :
* Get the entity type plugin (EntityProcessorPlugin)
* Call the "export" method of the plugin.
* The plugin then will call the "getDataToExport" that returns an array of data
* The "getDataToExport" will parse each field of the entity
* Get the field type plugin (TypeProcessorPlugin)
* Call "getExportedData" that returns an array of values of the field. The type processor plugin will treat dependencies if it references other entities
* The array of data is stocked in a .json file named with the entity type id
The import process Here is the process when importing an entity :
* Parse the .json file of the entity type
* Get the entity type plugin (EntityProcessorPlugin)
* Call the "getEntityToImport" method.
* The "getEntityToImport" will parse each field of the entity
* Get the field type plugin (TypeProcessorPlugin)
* Call "initImportedEntity" that inits the imported entity with field data. The type will treat dependencies if it references other entities.
* The entity is created or updated according to import options
Export custom entities
As you can see in the export process, if you want to create an export process for custom entities, you will have to create two plugins, one for the entity processor, and another one for the field type processor. The two plugins have to implements to methods, one for the import process, and another one for the export process. You can see examples in the module sources.
The entity processor plugin example : namespace Drupal\content_synchronizer\Plugin\content_synchronizer\entity_processor; use Drupal\content_synchronizer\Processors\Entity\EntityProcessorBase; use Drupal\Core\Entity\Entity; use Drupal\node\Entity\Node; /** * Plugin implementation of the 'accordion' formatter. * * @EntityProcessor( * id = "content_synchronizer_node_processor", * entityType = "node" * ) */ class NodeProcessor extends EntityProcessorBase { /** * {@inheritdoc} */ public function getEntityToImport(array $data, Entity $existingEntity = NULL) { if (is_null($existingEntity)) { $existingEntity = Node::create(['type' => $this->getDefaultLanguageData($data)['type']]); } return parent::getEntityToImport($data, $existingEntity); } /** * {@inheritdoc} */ public function getDataToExport(Entity $entityToExport) { // Init data to export: $data = parent::getDataToExport($entityToExport); // Add bundle : $data['type'] = $entityToExport->bundle(); return $data; } } The type processor plugin example : namespace Drupal\content_synchronizer\Plugin\content_synchronizer\type_processor; use Drupal\Core\Entity\Entity; use Drupal\Core\TypedData\TypedData; use Drupal\content_synchronizer\Processors\Type\TypeProcessorBase; /** * Plugin implementation For the type processor . * * @TypeProcessor( * id = "content_synchronzer_field_item_list_type_processor", * fieldType = "Drupal\Core\Field\FieldItemList" * ) */ class FieldItemListProcessor extends TypeProcessorBase { /** * {@inheritdoc} */ public function getExportedData(TypedData $propertyData) { $data = []; foreach ($propertyData as $order => $value) { $data[] = $value->getValue(); } return $data; } /** * {@inheritdoc} */ public function initImportedEntity(Entity $entityToImport, $propertyId, array $data) { if (array_key_exists($propertyId, $data)) { $entityToImport->set($propertyId, $data[$propertyId]); } } } Available hooks
You can use hooks in order to set entity data that will be exported, or set entity before import.
/** * Update entity data before export. * * @param array $exportedData * The generated data. * @param \Drupal\Core\Entity\Entity $entity * The entity to export */ function MODULE_content_synchronizer_export_data_alter(array &$exportedData, \Drupal\Core\Entity\Entity $entity) { // @todo : Do wathever you want on the $exportedData before it is written in the .json file. } /** * Update entity before import. * * @param \Drupal\Core\Entity\Entity|NULL $entity * Entity that will be saved. * @param \Drupal\Core\Entity\Entity|NULL $existingEntity * Clone of an existing entity before the entity has been set with data to import. * @param array $dataToImport * The data to import. */ function MODULE_content_synchronizer_import_entity_alter(\Drupal\Core\Entity\Entity $entity = NULL, \Drupal\Core\Entity\Entity $existingEntity = NULL, array $dataToImport = []) { // @todo : Do wathever you want on the $entity before it is saved } Drush commands drush content-synchronizer-create-import (drush csci)
Create an import from a specified zip file. This command is usefull when export files are to heavy to be uplaoded in browser. So you can create an import from a big zip file from this drush command. Ex : drush csci ./my_export.zip
drush content-synchronizer-clean-temporary-files (drush csctf)
Clean temporary files created by content_synchronizer. Ex : drush csctf
drush content-synchronizer-launch-export (drush cslex)
Launch the specified export from the specified export id. This will generate a zip file and output the path of the generated archive. Ex : drush cslex 13
drush content-synchronizer-launch-import (drush cslim)
Launch the specified import from the specified import id. Ex: drush cslim 2
Module Link
Project Usage
2020
Security Covered
Covered By Security Advisory
Version Available
Release Candidate
Module Summary
This module aims to solve the problem of exporting content entities in a zip file for sharing and updating content between different environments of a site.
Data Name
content_synchronizer