Skip to content
Snippets Groups Projects

Apply patch from issue #3100117

Compare and
3 files
+ 210
14
Compare changes
  • Side-by-side
  • Inline
Files
3
@@ -2,11 +2,13 @@
namespace Drupal\quick_node_clone\Entity;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityFormBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormState;
@@ -16,7 +18,9 @@ use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\group\Entity\GroupContent;
use Drupal\group\Entity\GroupRelationship;
use Drupal\node\Entity\Node;
use Drupal\layout_builder\Plugin\Block\InlineBlock;
use Drupal\layout_builder\Section;
use Drupal\layout_builder\SectionComponent;
use Drupal\Core\Render\Markup;
/**
@@ -68,6 +72,13 @@ class QuickNodeCloneEntityFormBuilder extends EntityFormBuilder {
*/
protected $privateTempStoreFactory;
/**
* The UUID service.
*
* @var \Drupal\Component\Uuid\UuidInterface
*/
protected $uuid;
/**
* QuickNodeCloneEntityFormBuilder constructor.
*
@@ -87,8 +98,10 @@ class QuickNodeCloneEntityFormBuilder extends EntityFormBuilder {
* Private temp store factory.
* @param \Drupal\Core\StringTranslation\TranslationInterface $stringTranslation
* The string translation service.
* @param \Drupal\Component\Uuid\UuidInterface $uuid
* The UUID service.
*/
public function __construct(FormBuilderInterface $formBuilder, EntityTypeBundleInfoInterface $entityTypeBundleInfo, ConfigFactoryInterface $configFactory, ModuleHandlerInterface $moduleHandler, EntityTypeManagerInterface $entityTypeManager, AccountInterface $currentUser, PrivateTempStoreFactory $privateTempStoreFactory, TranslationInterface $stringTranslation) {
public function __construct(FormBuilderInterface $formBuilder, EntityTypeBundleInfoInterface $entityTypeBundleInfo, ConfigFactoryInterface $configFactory, ModuleHandlerInterface $moduleHandler, EntityTypeManagerInterface $entityTypeManager, AccountInterface $currentUser, PrivateTempStoreFactory $privateTempStoreFactory, TranslationInterface $stringTranslation, ?UuidInterface $uuid = NULL) {
$this->formBuilder = $formBuilder;
$this->entityTypeBundleInfo = $entityTypeBundleInfo;
$this->configFactory = $configFactory;
@@ -96,6 +109,13 @@ class QuickNodeCloneEntityFormBuilder extends EntityFormBuilder {
$this->entityTypeManager = $entityTypeManager;
$this->currentUser = $currentUser;
$this->privateTempStoreFactory = $privateTempStoreFactory;
if (is_null($uuid)) {
@trigger_error('Calling ' . __METHOD__ . '() without the $uuid argument is deprecated in quick_node_clone:1.20.0 and will be required in quick_node_clone:2.0.0. See https://www.drupal.org/node/3486344', E_USER_DEPRECATED);
// @phpstan-ignore-next-line
$uuid = \Drupal::service('uuid');
}
$this->uuid = $uuid;
$this->setStringTranslation($stringTranslation);
}
@@ -131,6 +151,8 @@ class QuickNodeCloneEntityFormBuilder extends EntityFormBuilder {
/** @var \Drupal\node\Entity\Node $translated_node */
$translated_node = $new_node->getTranslation($langcode);
$translated_node = $this->cloneParagraphs($translated_node);
$this->cloneInlineBlocks($translated_node);
$this->moduleHandler->alter('cloned_node', $translated_node, $original_entity);
// Unset excluded fields.
$config_name = 'exclude.node.' . $translated_node->getType();
@@ -201,25 +223,25 @@ class QuickNodeCloneEntityFormBuilder extends EntityFormBuilder {
}
/**
* Clone the paragraphs of a node.
* Clone the paragraphs of an entity.
*
* If we do not clone the paragraphs attached to the node, the linked
* paragraphs would be linked to two nodes which is not ideal.
* If we do not clone the paragraphs attached to the entity, the linked
* paragraphs would be linked to two entities which is not ideal.
*
* @param \Drupal\node\Entity\Node $node
* The node to clone.
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity to clone.
*
* @return \Drupal\node\Entity\Node
* The node with cloned paragraph fields.
* @return \Drupal\Core\Entity\FieldableEntityInterface
* The entity with cloned paragraph fields.
*/
public function cloneParagraphs(Node $node) {
foreach ($node->getFieldDefinitions() as $field_definition) {
public function cloneParagraphs(FieldableEntityInterface $entity) {
foreach ($entity->getFieldDefinitions() as $field_definition) {
$field_storage_definition = $field_definition->getFieldStorageDefinition();
$field_settings = $field_storage_definition->getSettings();
$field_name = $field_storage_definition->getName();
if (isset($field_settings['target_type']) && $field_settings['target_type'] == "paragraph") {
if (!$node->get($field_name)->isEmpty()) {
foreach ($node->get($field_name) as $value) {
if (!$entity->get($field_name)->isEmpty()) {
foreach ($entity->get($field_name) as $value) {
if ($value->entity) {
$value->entity = $value->entity->createDuplicate();
foreach ($value->entity->getFieldDefinitions() as $field_definition) {
@@ -240,7 +262,91 @@ class QuickNodeCloneEntityFormBuilder extends EntityFormBuilder {
}
}
return $node;
return $entity;
}
/**
* Clone the inline blocks of a node's layout.
*
* For nodes that have layout builder enabled, the inline blocks needs
* be to cloned as well.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity being cloned.
*/
public function cloneInlineBlocks(FieldableEntityInterface $entity) {
$field_name = 'layout_builder__layout';
if (!$entity->hasField($field_name)) {
return;
}
/** @var \Drupal\layout_builder\SectionListInterface $layout_field */
$layout_field = $entity->$field_name;
foreach ($layout_field->getSections() as $sid => $section) {
$section = $this->cloneLayoutSection($section);
$layout_field->insertSection($sid, $section);
$layout_field->removeSection($sid + 1);
}
}
/**
* Clone a layout section.
*
* For nodes that have layout builder enabled, the inline blocks in a section
* need be to cloned as well.
*
* @param \Drupal\layout_builder\Section $section
* The section being cloned.
*/
public function cloneLayoutSection(Section $section) {
// Create a duplicate of each component.
foreach ($section->getComponents() as $component) {
$block = $component->getPlugin();
// Only clone inline blocks.
if (!$block instanceof InlineBlock) {
continue;
}
$component_array = $component->toArray();
$configuration = $component_array['configuration'];
// Fetch the block content.
$block_content = NULL;
if (!empty($configuration['block_serialized'])) {
$block_content = unserialize($configuration['block_serialized']);
}
elseif (!empty($configuration['block_revision_id'])) {
$block_content = $this->entityTypeManager->getStorage('block_content')
->loadRevision($configuration['block_revision_id']);
}
// Create a duplicate block.
if ($block_content) {
/** @var \Drupal\block_content\BlockContentInterface $block_content */
$cloned_block_content = $block_content->createDuplicate();
$this->cloneParagraphs($cloned_block_content);
// Unset the revision and add the serialized block content.
$configuration['block_revision_id'] = NULL;
$configuration['block_serialized'] = serialize($cloned_block_content);
}
$new_component = new SectionComponent(
$this->uuid->generate(),
$component_array['region'],
$configuration,
$component_array['additional']
);
// Remove existing components from the section and append a fresh copy.
$section->insertAfterComponent($component->getUuid(), $new_component);
$section->removeComponent($component->getUuid());
}
return $section;
}
/**
Loading