Subentities referenced by BaseFieldDefinition field are not duplicated

Created on 29 October 2020, about 4 years ago
Updated 2 September 2024, 3 months ago

Problem/Motivation

I created a custom entity and I want to be able to clone it. This entity has a reference to another custom entity through a field created by the BaseFieldDefinition::create('entity_reference') function.

When I clone a custom content, the subentities cannot be duplicated because they are not shown in the clone form confirmation (when you select if you want to duplicate subentities). Once the clone is done, the subentities referenced by the clone are the same as the original content.

I think this module is not made to handle field created by BaseFieldDefinition. In the file /src/EntityClone/Content/ContentEntityCloneFormBase.php at line 93, the code detect if the field definition is an instance of FieldConfigInterface, and it is not the case for the field created from the BaseFieldDefinition:

foreach ($entity->getFieldDefinitions() as $field_id => $field_definition) {
    if ($field_definition instanceof FieldConfigInterface && in_array($field_definition->getType(), ['entity_reference', 'entity_reference_revisions'], TRUE)) {
        // ...
    }
    // ...
}

I tagged this issue as a bug because if base fields are correctly duplicated, it is not possible to duplicate them. If it is the attended behaviour then we should update the documentation accordingly.

Steps to reproduce

  • Create a custom entity
  • Add a base field definition in the entity (in the baseFieldDefinitions function of the entity class
  • Clone the entity and see that the option to select if subentities should be be duplicated is the present

Proposed resolution

Adapt the functions formElement and getRecursiveFormElement from the ContentEntityCloneFormBase class to make it work with base field definitions. I think this is not trivial because it currently call $field_definition->id() and base field definition don't have id() function.

Remaining tasks

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Needs review

Version

2.0

Component

Code

Created by

πŸ‡¨πŸ‡­Switzerland faeby

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • First commit to issue fork.
  • Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    Not currently mergeable.
  • @dieterholvoet opened merge request.
  • Status changed to Needs review about 1 year ago
  • πŸ‡§πŸ‡ͺBelgium dieterholvoet Brussels
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 10.1.x + Environment: PHP 8.2 & MySQL 8
    last update about 1 year ago
    27 pass, 6 fail
  • πŸ‡ΊπŸ‡¦Ukraine vselivanov Kyiv, Ukraine

    I have this issue with cloning custom entity and fixed it with MR 53 and custom code.

    With entity_clone 2.0.0-beta6 we have isClonable() method in src/EntityCloneClonableField.php which also checks
    $field_definition instanceof FieldConfigInterface
    But all custom reference fields are instance of BaseFieldDefinition class.
    So we need additional changes to this method.

    I tried to remove this FieldConfigInterface check, but it adds a lot of not needed fields and caused recursions and "Circular reference detected" errors.

    Finally I managed to clone custom entities with:
    1. Apply patch from the MR 53 (attached it)
    2. Extend EntityCloneClonableField class in the custom module and add hardcoded custom entity types check.

    Example with 2 files:

    1. File modules/custom/my_module/src/MyModuleServiceProvider.php

    <?php
    
    namespace Drupal\my_module;
    
    use Drupal\Core\DependencyInjection\ContainerBuilder;
    use Drupal\Core\DependencyInjection\ServiceProviderBase;
    
    /**
     * Overrides EntityCloneClonableField class.
     */
    class MyModuleServiceProvider extends ServiceProviderBase {
    
      /**
       * {@inheritdoc}
       */
      public function alter(ContainerBuilder $container) {
        if ($container->hasDefinition('entity_clone.clonable_field')) {
          /** @var \Symfony\Component\DependencyInjection\Definition $definition */
          $definition = $container->getDefinition('entity_clone.clonable_field');
          $definition->setClass('Drupal\my_module\EntityCloneClonableField');
        }
      }
    
    }
    

    2. File modules/custom/my_module/src/EntityCloneClonableField.php

    <?php
    
    namespace Drupal\my_module;
    
    use Drupal\Core\Field\BaseFieldDefinition;
    use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
    use Drupal\Core\Field\FieldDefinitionInterface;
    use Drupal\Core\Field\FieldItemListInterface;
    use Drupal\entity_clone\EntityCloneClonableField as EntityCloneClonableFieldSource;
    
    /**
     * Manage entity clone clonable field.
     */
    class EntityCloneClonableField extends EntityCloneClonableFieldSource {
    
      /**
       * {@inheritDoc}
       */
      public function isClonable(FieldDefinitionInterface $field_definition, FieldItemListInterface $field): bool {
        $isClonable = parent::isClonable($field_definition, $field);
    
        // Add custom entities fields as clonable.
        $customClonableEntityTypes = [
          'custom_entity_1',
          'custom_entity_2',
        ];
        if (!$isClonable && in_array($field_definition->getTargetEntityTypeId(), $customClonableEntityTypes)
          && $field_definition instanceof BaseFieldDefinition
          && $field instanceof EntityReferenceFieldItemListInterface && $field->count() > 0) {
          return TRUE;
        }
    
        return $isClonable;
      }
    
    }
    
  • There is one more place, where the field key variable needs to be changed: /src/EntityClone/Content/ContentEntityCloneFormBase.php line 205
    Or in human terms: The part of the content clone form, which displays referenced entities for which cloning is enforced.

Production build 0.71.5 2024