View source
<?php
namespace Drupal\entity_clone\EntityClone\Content;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\ContentEntityStorageInterface;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\FieldConfigInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Drupal\entity_clone\EntityClone\EntityCloneFormInterface;
use Drupal\entity_clone\EntityCloneSettingsManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ContentEntityCloneFormBase implements EntityHandlerInterface, EntityCloneFormInterface {
protected $translationManager;
protected $entityTypeManager;
protected $entityCloneSettingsManager;
protected $discoveredEntities = [];
public function __construct(EntityTypeManagerInterface $entity_type_manager, TranslationManager $translation_manager, EntityCloneSettingsManager $entity_clone_settings_manager) {
$this->entityTypeManager = $entity_type_manager;
$this->translationManager = $translation_manager;
$this->entityCloneSettingsManager = $entity_clone_settings_manager;
}
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static($container
->get('entity_type.manager'), $container
->get('string_translation'), $container
->get('entity_clone.settings.manager'));
}
public function formElement(EntityInterface $entity, $parent = TRUE, &$discovered_entities = []) {
$form = [
'recursive' => [],
];
if ($entity instanceof FieldableEntityInterface) {
$discovered_entities[$entity
->getEntityTypeId()][$entity
->id()] = $entity;
foreach ($entity
->getFieldDefinitions() as $field_id => $field_definition) {
if ($field_definition instanceof FieldConfigInterface && in_array($field_definition
->getType(), [
'entity_reference',
'entity_reference_revisions',
], TRUE)) {
$field = $entity
->get($field_id);
if ($field
->count() > 0 && $this->entityTypeManager
->getStorage($field
->getSetting('target_type')) instanceof ContentEntityStorageInterface) {
$form['recursive'] = array_merge($form['recursive'], $this
->getRecursiveFormElement($field_definition, $field_id, $field, $discovered_entities));
}
}
}
if ($parent) {
$form = array_merge([
'description' => [
'#markup' => $this
->getFormDescription($form, $entity),
'#access' => TRUE,
],
], $form);
}
}
return $form;
}
protected function getRecursiveFormElement(FieldConfigInterface $field_definition, $field_id, FieldItemListInterface $field, array &$discovered_entities) {
$form_element = [
'#tree' => TRUE,
];
$fieldset_access = !$this->entityCloneSettingsManager
->getHiddenValue($field_definition
->getFieldStorageDefinition()
->getSetting('target_type'));
$form_element[$field_definition
->id()] = [
'#type' => 'fieldset',
'#title' => $this->translationManager
->translate('Entities referenced by field <em>@label (@field_id)</em>.', [
'@label' => $field_definition
->label(),
'@field_id' => $field_id,
]),
'#access' => $fieldset_access,
'#description_should_be_shown' => $fieldset_access,
];
foreach ($field as $value) {
if (!($referenced_entity = $value
->get('entity')
->getTarget())) {
continue;
}
$referenced_entity = $value
->get('entity')
->getTarget()
->getValue();
if (isset($discovered_entities[$referenced_entity
->getEntityTypeId()]) && array_key_exists($referenced_entity
->id(), $discovered_entities[$referenced_entity
->getEntityTypeId()])) {
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['is_circular'] = [
'#type' => 'hidden',
'#value' => TRUE,
];
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['circular'] = [
'#type' => 'item',
'#markup' => $this->translationManager
->translate('Circular reference detected'),
];
}
else {
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['clone'] = [
'#type' => 'checkbox',
'#title' => $this->translationManager
->translate('Clone entity <strong>ID:</strong> <em>@entity_id</em>, <strong>Type:</strong> <em>@entity_type - @bundle</em>, <strong>Label:</strong> <em>@entity_label</em>', [
'@entity_id' => $referenced_entity
->id(),
'@entity_type' => $referenced_entity
->getEntityTypeId(),
'@bundle' => $referenced_entity
->bundle(),
'@entity_label' => $referenced_entity
->label(),
]),
'#default_value' => $this->entityCloneSettingsManager
->getDefaultValue($referenced_entity
->getEntityTypeId()),
'#access' => $referenced_entity
->access('view label'),
];
if ($this->entityCloneSettingsManager
->getDisableValue($referenced_entity
->getEntityTypeId())) {
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['clone']['#attributes'] = [
'disabled' => TRUE,
];
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['clone']['#value'] = $form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['clone']['#default_value'];
}
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['target_entity_type_id'] = [
'#type' => 'hidden',
'#value' => $referenced_entity
->getEntityTypeId(),
];
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['target_bundle'] = [
'#type' => 'hidden',
'#value' => $referenced_entity
->bundle(),
];
if ($referenced_entity instanceof ContentEntityInterface) {
$form_element[$field_definition
->id()]['references'][$referenced_entity
->id()]['children'] = $this
->getChildren($referenced_entity, $discovered_entities);
}
}
}
return $form_element;
}
protected function getChildren(ContentEntityInterface $referenced_entity, array &$discovered_entities) {
if ($this->entityTypeManager
->hasHandler($referenced_entity
->getEntityTypeId(), 'entity_clone_form')) {
$discovered_entities[$referenced_entity
->getEntityTypeId()][$referenced_entity
->id()] = $referenced_entity;
$entity_clone_form_handler = $this->entityTypeManager
->getHandler($referenced_entity
->getEntityTypeId(), 'entity_clone_form');
return $entity_clone_form_handler
->formElement($referenced_entity, FALSE, $discovered_entities);
}
return [];
}
public function getValues(FormStateInterface $form_state) {
return $form_state
->getValues();
}
protected function getFormDescription(array $form, EntityInterface $entity) {
$has_recursive = FALSE;
$elements_visible = FALSE;
if (isset($form['recursive'])) {
$has_recursive = TRUE;
}
array_walk_recursive($form['recursive'], function ($item, $key) use (&$elements_visible) {
if ($key === '#description_should_be_shown') {
$elements_visible = $elements_visible || $item;
}
});
if ($has_recursive && $elements_visible) {
return $this->translationManager
->translate("\n <p>Specify the child entities (the entities referenced by this entity) that should also be cloned as part of\n the cloning process. If they're not included, these fields' referenced entities will be the same as in the\n original. In other words, fields in both the original entity and the cloned entity will refer to the same\n referenced entity. Examples:</p>\n\n <p>If you have a Paragraph field in your entity, and you choose not to clone it here, deleting the original\n or cloned entity will also delete the Paragraph field from the other one. So you probably want to clone\n Paragraph fields.</p>\n\n <p>However, if you have a User reference field, you probably don't want to clone it here because a new User\n will be created for referencing by the clone.</p>\n\n <p>Some options may be disabled here, preventing you from changing them, as set by your administrator. Some\n options may also be missing, hidden by your administrator, forcing you to clone with the default settings.\n It's possible that there are no options here for you at all, or none need to be set, in which case you may\n simply hit the <em>Clone</em> button.</p>\n ");
}
else {
return $this->translationManager
->translate("<p>Do you want to clone the <em>@type</em> entity named <em>@title</em>?</p>", [
"@type" => $entity
->getEntityType()
->getLabel(),
"@title" => $entity
->label(),
]);
}
}
}