We need to add clone support to entities (such as Nodes) that have other entities embedded within them, such as Paragraphs. We're focusing primarily on Paragraphs because Field Collection has been deprecated in favour of it. (See #2784931: Proposal: Deprecate Field Collections for Drupal 8, focus on Entity Reference Revisions & Paragraphs for details.)

This issue does not cover recursive entity nesting (i.e. entities within entities within entities etc.). Support for that will be handled by the follow-up #2913949: Add support for recursive cloning.

What remains to be done

Original summary

Does the module support cloning e.g. a node that has paragraphs attached, and having the paragraphs entities cloned too rather than the new node pointing to the original paragraph entities?

CommentFileSizeAuthor
#147 interdiff-2706639_118_147.txt6.25 KBvpeltot
#147 entity_clone-clone_sub_entities-2706639-147.patch50.69 KBvpeltot
#144 interdiff-2706639-137-144.txt2.91 KBpguillard
#144 entity_clone-clone_sub_entities-2706639-144.patch50.89 KBpguillard
#137 interdiff-2706639-130-136.txt1.17 KBsam.spinoy@gmail.com
#137 entity_clone-clone_sub_entities-2706639-136.patch48.28 KBsam.spinoy@gmail.com
#137 Screen Shot 2018-03-14 at 10.31.07.png102.89 KBsam.spinoy@gmail.com
#134 interdiff_2706639-130-132.txt1.25 KBpguillard
#132 entity_clone-clone_sub_entities-2706639-132.patch48.13 KBsam.spinoy@gmail.com
#131 interdiff-2706639-127-130.txt564 bytespguillard
#131 entity_clone-clone_sub_entities-2706639-130.patch47.95 KBpguillard
#127 entity_clone-clone_sub_entities-2706639-127.patch47.31 KBpguillard
#125 interdiff_2706639_119-123.txt1.54 KBpguillard
#123 entity_clone-clone_sub_entities-2706639-123.patch47.73 KBsam.spinoy@gmail.com
#121 interdiff-2706639-118-119.txt1.36 KBpguillard
#119 entity_clone-clone_sub_entities-2706639-119.patch46.94 KBpguillard
#118 interdiff-2706639-108-118.txt14.41 KBvpeltot
#118 entity_clone-clone_sub_entities-2706639-118.patch46.94 KBvpeltot
#116 2706639-deep-clone-116.patch45.63 KBlarowlan
#116 interdiff-2706639-deep-clone-116.txt1.85 KBlarowlan
#114 Screenshot-2018-1-2 Clone Content Wyndham City.png30.63 KBlarowlan
#108 entity_clone-n2706639-108.patch44.06 KBDamienMcKenna
#108 entity_clone-n2706639-108.interdiff.txt863 bytesDamienMcKenna
#105 interdiff-2706639-102-105.txt1.26 KBvpeltot
#105 entity_clone-clone_sub_entities-2706639-105.patch44.1 KBvpeltot
#103 interdiff-2706639-89-102-do-not-test.diff21.79 KBcolan
#102 entity_clone-clone_sub_entities-2706639-102.patch43.47 KBvpeltot
#99 entity_clone-clone_sub_entities-2706639-99.patch43.07 KBvpeltot
#97 entity_clone-clone_sub_entities-2706639-97.patch43.21 KBvpeltot
#89 entity_clone-clone_sub_entities-2706639-89.patch71.25 KBcolan
#89 interdiff-2706639-83-89-do-not-test.diff9.97 KBcolan
#85 interdiff-2706639-80-83-do-not-test.diff48.78 KBcolan
#83 support_for_sub_entity-2706639-83.patch63.59 KBvpeltot
#80 interdiff-2706639-78-80-do-not-test.diff16.74 KBcolan
#80 entity_clone-add_support_for_cloning_subentities-2706639-80.patch35.13 KBcolan
#78 interdiff-2706639-63-78.txt12.36 KBvpeltot
#78 support_for_sub_entity-2706639-78.patch28.63 KBvpeltot
#76 interdiff-2706639-63-75.txt12.36 KBvpeltot
#76 support_for_sub_entity-2706639-75.patch28.63 KBvpeltot
#2 support_for_cloning-2706639-2.patch9.88 KBvpeltot
#5 2706639--support-paragraph-cloning.patch2.72 KBdpolant
#9 2706639--support-paragraph-cloning-2.patch2.68 KBdpolant
#16 support_for_recursive_clone_2706639_16.patch14.64 KBpogfra
#18 entity_clone-attached_entities-2706639-18.patch8.01 KBruloweb
#19 entity_clone-attached_entities-2706639-19.patch7.71 KBruloweb
#19 entity_clone-attached_entities-2706639-19-diff.txt2.87 KBruloweb
#25 entity_clone-attached_entities-2706639-25-diff.txt798 bytesweekbeforenext
#26 entity_clone-attached_entities-2706639-25.patch7.91 KBweekbeforenext
#38 entity_clone-attached_entities-2706639-38.patch7.9 KBmichaellander
#38 interdiff-2706639-25-38.txt2.5 KBmichaellander
#40 interdiff-2706639-38-39.txt1.92 KBmichaellander
#40 entity_clone-attached_entities-2706639-39.patch7.9 KBmichaellander
#41 entity_clone-allow_for_recursive_entity_cloning-2706639-41.patch8.98 KBcolan
#41 interdiff-2706639-40-41-do-not-test.diff7.75 KBcolan
#45 support_for_cloning-2706639-45.patch14.34 KBvpeltot
#46 support_for_cloning-2706639-46.patch14.48 KBvpeltot
#46 interdiff-2706639-45-46.txt2.61 KBvpeltot
#50 entity_clone-add_support_for_cloning_subentities-2706639-50.patch15.66 KBcolan
#50 interdiff-2706639-46-50-do-not-test.diff7.72 KBcolan
#53 support_for_cloning-2706639-53.patch14.76 KBvpeltot
#53 interdiff-2706639-50-53.txt2.01 KBvpeltot
#56 entity_clone-add_support_for_cloning_subentities-2706639-56.patch15.66 KBcolan
#56 interdiff-2706639-53-56-do-not-test.diff1.34 KBcolan
#63 support_for_sub_entity-2706639-63.patch17.86 KBvpeltot
#63 interdiff-2706639-56-63.txt14.78 KBvpeltot
#65 entity-clone-1.jpg172.21 KBrwam
#65 entity-clone-2.jpg224.14 KBrwam
#63 entity_clone_ui.png188.89 KBvpeltot
#74 support_for_sub_entity-2706639-74.patch28.72 KBvpeltot
#74 interdiff-2706639-63-74.txt12.45 KBvpeltot
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

DamienMcKenna created an issue. See original summary.

vpeltot’s picture

Title: Support for cloning nodes that have Paragraphs attached? » Support for cloning nodes that have another entities attached
Priority: Normal » Major
FileSize
9.88 KB

Currently the clone for content entities is fully supported.
On the other hand, as you point out, all referenced entities (with entity reference fields) are simply attached and all target entities are not cloned.

I had already started this development.

Now, with this patch, in the clone form, a new checkbox has appeared to propose you a "recursive mode".
All referenced entities (except Files / Images / Taxonomy terms) are cloned too.

It should work with all entities including entities provided by the paragraphs module.
If you have time, can you test this patch ?

vpeltot’s picture

Status: Active » Needs review
miro_dietiker’s picture

Status: Needs review » Needs work

Please consider the Entity Reference Revision definition that is the underlying field storage of Paragraphs:
Entity Reference Revision defines a composite relationship and it is never allowed to have a target entity reused.

You don't need a setting for that, instead you are required to ALWAYS recurse on composite relationship entity reference revision fields.
This support makes sense as other modules consider building on top of ERR and we already have similar integration for this.
- The diff module will also recurse to show diffs on host entity.
- The TMGMT module makes sure the paragraphs are also passed to translation of a node / host entity.
- The collect module also embeds the paragraphs.
Complexity significantly goes down.
Happy to mark our ERR / Paragraph issue as fixed when ready... #2676226: Needs tests: Support cloning

Also i recommend to you to define recursing on entity references on a per-field level. Entity references are used in so many different ways:
From user reference, over term references, to related content references.
A general "recurse cloning" simply doesn't work semantically.

dpolant’s picture

I've supplied a simpler patch that just handles ERR fields. It does not offer a setting since like miro said, you always have to clone them.

There is also a bit in the patch to make it work with Multiversion.

Status: Needs review » Needs work

The last submitted patch, 5: 2706639--support-paragraph-cloning.patch, failed testing.

The last submitted patch, 5: 2706639--support-paragraph-cloning.patch, failed testing.

DamienMcKenna’s picture

Two minor items:

  1. +++ b/src/EntityClone/Content/ContentEntityCloneBase.php
    @@ -59,6 +59,32 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
    +      $field_type = $field_definition->getType();
    

    Is there any need to create a local variable for this? Couldn't it just be used as-is in the if() statement?

  2. +++ b/src/Form/EntityCloneForm.php
    @@ -137,7 +137,12 @@ class EntityCloneForm extends FormBase {
    +    // If you leave this in, Multiversion does not track revisions properly.
    

    Comments should not be written in the second person, it should be e.g. "If this is left in then Multiversion will not track revisions properly."

dpolant’s picture

DamienMcKenna’s picture

Status: Needs work » Needs review
DamienMcKenna’s picture

Component: User interface » Code

Status: Needs review » Needs work

The last submitted patch, 9: 2706639--support-paragraph-cloning-2.patch, failed testing.

The last submitted patch, 9: 2706639--support-paragraph-cloning-2.patch, failed testing.

miro_dietiker’s picture

How about the status of multilingual support of this approach?
There's usually always more to consider with it than initially expected... ;-)

DamienMcKenna’s picture

@miro_dietiker: I suspect we'll need some tests..

For the tests, should it e.g. start with a node that has translations and then clone it, or something else?

pogfra’s picture

Here a first draft patch based on that of the second comment.
It add checkboxes on clone form to choose which entity have to be clone.
It do not add support for entity clone revisions/dynamic entity references yet

ruloweb’s picture

What if we add support to complex fields within an event?

I created a patch which dispatch some events before and after cloning #2800203: Event dispatcher for clone events.

ruloweb’s picture

Attached is a patch which depends on #2800203: Event dispatcher for clone events and implements recursives event subscribers to clone paragraphs and field collections.

I think this is a good approach because you just need to create an EventSubscriber class per each entity implementation, without the need to make changes on the existing files.

Cloning entity reference revisions is based on comment #2706639-9: Support for sub-entity cloning

I was able to clone entities like this one:

  • Node
    • String field
    • Image field
    • Paragraph field
      • Paragraph field
    • Paragraph field
      • Field Collection
      • Paragraph field
    • Field Collection
      • Field Collection
      • Paragraph field
        • Field Collection
ruloweb’s picture

New patch and its diff.

For field collections now it erases any previous values and then clone the new items. The last patch did that in the same foreach. It fixes some issues related to relations like Node -> Field Collection -> Paragraphs -> Field Collection.

Some typo fixed and deleted unnecessary functions.

Thanks!

RogerB’s picture

Tried #19 patch on a node with nested paragraphs. It did not work. Paragraphs are not being recursively cloned. The new node references the paragraphs of the original node. Edits to paragraphs of the clone appear in original.

Node structure:

Node
  Paragraph
    Text
    Image
  Paragraph
    Integer
    Integer
    Paragraph
      Text
      Image
    Paragraph
      Text
      Image
  Paragraph
    Text
    Image
ruloweb’s picture

@RogerB did you clear cache? Events needs to be subscribed in order to works.

ruloweb’s picture

@Rober and also you need to apply #2800203: Event dispatcher for clone events too, as I described in commit #18.

RogerB’s picture

Yes @ruloweb I later spotted that I had to add the #2800203: Event dispatcher for clone events patch as well. When I did it worked perfectly.

Kevin P Davison’s picture

@RoberB are these patches still working for you on Drupal 8.2.3? I'm getting WSOD on /entity_clone/node/### with

Uncaught PHP Exception Drupal\Component\Plugin\Exception\PluginNotFoundException: "The "field_collection_item" entity type does not exist." at /Applications/MAMP/htdocs/go-d8/core/lib/Drupal/Core/Entity/EntityTypeManager.php line 133

Sequence:

  1. entity_clone-event_dispatcher-2800203-5.patch
  2. entity_clone-attached_entities-2706639-19.patch
weekbeforenext’s picture

Status: Needs work » Needs review
FileSize
798 bytes

I added a condition to escape the onEntityCloned() method in FieldCollectionItem.php that tests to see if the 'field_collection_item' entity type exists. This fixes the error found in comment #24.

weekbeforenext’s picture

Status: Needs review » Needs work

The last submitted patch, 26: entity_clone-attached_entities-2706639-25.patch, failed testing.

Mars0test’s picture

+++ b/src/EventSubscriber/EntityReferenceRevisions.php
@@ -0,0 +1,68 @@
+use Drupal\entity_clone\Events\EntityCloneEvent;
+use Drupal\entity_clone\Events\EntityCloneEvents;

There are somethings missings, you call class who doesn't exist.

recrit’s picture

@BizuTétu: Both of those classes existed when I used the patches below. Note: The event subscriber patch #2800203: Event dispatcher for clone events is required for #2706639: Support for sub-entity cloning.

The following worked for me. I verified that the paragraphs on the clone node had new IDs.
Patches applied.

     "drupal/entity_clone": {
        "2800203 - Event dispatcher for clone events": "https://www.drupal.org/files/issues/entity_clone-event_dispatcher-2800203-5.patch",
        "2706639 - Support for cloning nodes that have another entities attached": "https://www.drupal.org/files/issues/entity_clone-attached_entities-2706639-25.patch",
        "2769823 - Getting error after clicking on abort clone button": "https://www.drupal.org/files/issues/entity_clone-abort_clone_causes_fatal_error-2769823-4.patch"
      }
steel-track’s picture

I can also verify that with the three patches in #29 applied, cloning a node with paragraphs creates new paragraph entities. A cache clear was required for it to start working correctly.

bdanin’s picture

The three patches as supplied in #29 appear to be working well for me too, thank you!
using 9265e35 specific dev version in composer: "drupal/entity_clone": "1.x-dev#9265e35",

anairamzap’s picture

anairamzap’s picture

fabiansierra5191’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: +DrupalPicNic

The tests were falling because they depend on other patches' issues.
These are related to the following patches:

I just applied the 3 patches of the comment #29 in the right order and cloning a node with multiple paragraphs, it created new paragraphs entities on Drupal 8.3.5 version.

rwam’s picture

After losing a bunch of contents after deleting only one node I detect same problems. All affected nodes refer to the same field and field revision entries because they are clones of one original node and after deletion all still existing nodes refer to the fields and revisions which are deleted.

I've tested #29 resp. #34 and the three patches work for me as well. Cloned node creates new entries in field and field revision tables and a deletion is possible without affecting the original.

I've tested this in a multilingual environment on Drupal 8.3.5. with Paragraphs 8.x-1.1 and Entity Reference Revisions 8.x-1.3

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 26: entity_clone-attached_entities-2706639-25.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

michaellander’s picture

I've updated the patch to reflect the changes from #2800203-10: Event dispatcher for clone events where the namespace Drupal\entity_clone\Events is changed to the singular Drupal\entity_clone\Event.

Status: Needs review » Needs work

The last submitted patch, 38: entity_clone-attached_entities-2706639-38.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

michaellander’s picture

Looks like EntityCloneEvents::PRE_SAVE was renamed to EntityCloneEvents::PRE_CLONE, and same with EntityCloneEvents::POST_SAVE. Updated patch for that issue as well. See #2800203-10: Event dispatcher for clone events.

colan’s picture

Fixed coding-standards violations and removed deep nesting.

Requires the patches from #2800203: Event dispatcher for clone events and #2908414: Error on abort and redirects - one patch to solve everything as prerequisites.

Didn't look too deeply into the failing tests, but I'm guessing that they're failing because the other patches haven't been applied yet. We should commit those, and then retest here.

vpeltot’s picture

Status: Needs review » Needs work

I just tested the last patch (in comment #41), but it doesn't work for me.
Step to reproduce:

  1. Install a new drupal instance with standard profile
  2. Add new entity reference field "field_article" in page content type to allow renferences with article content types
  3. Create an article content "Test article"
  4. Create a page content "Test page" including reference with the previous created article
  5. Clone the "Test page" content

Only the page is cloned.

The target of this issue is to clone recursively, with a choice (field by field), all referenced entities (entity_reference field type).

In this patch, only entity_reference_revisions and field_collection field are supported.

I think the best way to resolve this issue is re-rollling the #16 patch (that implement the correct way), and maybe include the entity_reference_revisions field type support.

vpeltot’s picture

Tests are now OK with the rerolled patch.
Now, from this patch, it remains to be done:

  • Allow entity_reference_revisions field to be cloned recursively
  • Improve the UX/UI for the recursive clone form

As for field_collection fields, why this module doesn't use an entity_reference or an entity_reference_revision fields?

colan’s picture

As per #2509254: Field collection fields should extend entity reference fields, it looks like Field Collection fields do extend Entity Reference fields in the third rewrite of the module (3.x). I can't find any reference to ERR over there.

Having said that, I think we should spend more time supporting Paragraphs/ERR and less time supporting Field Collection. After reading #2784931: Proposal: Deprecate Field Collections for Drupal 8, focus on Entity Reference Revisions & Paragraphs, I don't see too much continued effort going into Field Collection, especially when the following text is on the project page:

Paragraphs is likely to replace field collection for Drupal 8. Field collection is on its way to being deprecated. It is recommended to use paragraphs instead of field collection for Drupal 8 projects.

As far as this patch goes, I think we should get the above functionality in very soon, and create a new follow-up issue for recursion support. This way, we'll at least have basic cloning for these field types in alpha2, as planned. I've spun off #2913949: Add support for recursive cloning for that.

I should be able to review and test the above patch today, after which I'll either post another patch (if updates are required) or RTBC it. Barring any other major problems, we should be able to get this into Friday's release.

colan’s picture

Mars0test’s picture

Status: Needs review » Reviewed & tested by the community

Looks good for me.

You need to use interface instead of class directly :

+  protected function getChildren(FieldItemListInterface $field, FieldConfig $field_definition) {
+    $children = [];
+  public function __construct(EntityTypeManager $entity_type_manager, TranslationManager $translation_manager) {
+    $this->entityTypeManager = $entity_type_manager;
+    $this->translationManager = $translation_manager;
+  }
rwam’s picture

Status: Reviewed & tested by the community » Needs work

I've tried #50 with latest dev release and it doesn't work as expected. All paragraph items of cloned and original node will be deleted if I delete the cloned or the original node. It's the same behavior like described on #35.

I have only paragraphs attached to a content type, no recursion. With the mentioned patches in #29 it works well.

So I have to do a rollback to my last working version.

vpeltot’s picture

@colan
I think it's better to support entity_reference_revisions field now.
Many projects used the paragraphs module.
For the UX/UI improvement, I'm OK to postpone that

@rwam
The patch #50 does not allow the entity_reference_revisions field type to be cloned recursively.
Here a new patch.
Can you test this ?

vpeltot’s picture

Status: Needs work » Needs review
rwam’s picture

Status: Needs review » Needs work

Ups, cloning of node with paragraphs attached leads to:

Fatal error: Call to a member function getEntityTypeId() on null in /…/modules/entity_clone/src/EntityClone/Content/ContentEntityCloneFormBase.php on line 102

colan’s picture

I fixed that problem, but found some others. When I get checkboxes on the clone form (which I never got before), and don't select any, submitting the form leads to an error, with warnings leading up to it in the log:

  1. Warning: Illegal string offset 'target_id' in Drupal\entity_reference_revisions\Plugin\DataType\EntityReferenceRevisions->setValue() (line 111 of ...)
  2. Warning: Illegal string offset 'target_revision_id' in Drupal\entity_reference_revisions\Plugin\DataType\EntityReferenceRevisions->setValue() (line 111 of ...)
  3. Warning: Illegal string offset 'target_id' in Drupal\entity_reference_revisions\Plugin\DataType\EntityReferenceRevisions->setValue() (line 115 of ...)
  4. Warning: Illegal string offset 'target_revision_id' in Drupal\entity_reference_revisions\Plugin\DataType\EntityReferenceRevisions->setValue() (line 116 of ...)
  5. Error: Call to a member function getRevisionId() on null in Drupal\entity_reference_revisions\Plugin\Field\FieldType\EntityReferenceRevisionsItem->onChange() (line 214 of ...)

From the backtrace, it looks like it's coming from src/EntityClone/Content/ContentEntityCloneBase.php(99). This method is way too big to see what's going on. It needs to be broken into smaller ones as it is doing more than one thing. I'll see what I can do to fix.

In other news, I think I can finally see the UX problem. I get a form with 2 checkboxes, which both say the same thing. The text says,

Choose which referenced entity you want to clone, default action "alias entity".

This raises some questions:

  • If I get two referenced entities with the same name, which one do I choose? What's the difference? What happens if I select none? Or both? In my case, they both say 240 - Illum > Test paragraph.
  • What does default action "alias entity" mean? What are we aliasing here and why?
colan’s picture

Actually, I'll be out for part of the day so if someone else wants to pick this up, please do (and assign it to yourself first so we're not duplicating effort).

rwam’s picture

Sorry, the patch provided in #56 shows the same behavior: if I delete a cloned node, all paragraphs of the source node are missing/deleting too because of same field reference ;(

miro_dietiker’s picture

Yeah it's absolutely critical to test cover the delete case exactly as @rwam mentioned.

We had some similar custom code bug that caused so much pain because data is lost in context B while you act in context A. It took way too long to identify the issue and we couldn't simply revert the content DB anymore... Dangerous and painful.

colan’s picture

Title: Support for cloning nodes that have another entities attached » Support for sub-entity cloning
Issue summary: View changes

I've updated the issue summary with everything that needs to be done. (Thanks for the feedback!) Please edit as necessary. We can strike out items after they're completed.

I'd really like help in understanding what we're asking for on the clone form as that's really not clear to me now.

colan’s picture

Issue summary: View changes
vpeltot’s picture

Assigned: Unassigned » vpeltot
vpeltot’s picture

This patch contain:
* Refactor
* Little UI improvement
* New test to ensure referenced entities are cloned too

This patch works with entity_reference_revisions field types (used by paragraphs)

For example :
1 node (eg. article):
- Body field
- Entity reference revisions field to paragraphs (type A & type B)
- Entity reference field to tags taxonomy term
2 paragraphs types:
- type A with a simple text field
- type B with an entity reference revisions to the type A paragraphs

Here the clone Form:

vpeltot’s picture

Status: Needs work » Needs review
rwam’s picture

Status: Needs review » Needs work
FileSize
172.21 KB
224.14 KB

First: thank you guys for working on this.

I've tested patch #63, but it doesn't work out of the box ;( And I have several issues with this new patch. Cloning of nodes with paragraph items works indeed but only if you understand the clone form correctly. I will try to demonstrate it with a screenshot. Here you can see a working form:

working

but wait:

falied

One clicked option for cloning the user entity leads to:

Please try again later.Drupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'admin_cloned-en' for key 'user__name': INSERT INTO {users_field_data} (

)
in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 805 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).

Drupal\Core\Database\Statement->execute(Array, Array) (Line: 624)
Drupal\Core\Database\Connection->query('INSERT INTO {users_field_data} (uid, langcode, preferred_langcode, preferred_admin_langcode, name, pass, mail, timezone, status, created, changed, access, login, init, default_langcode, ldap_user_puid_sid, ldap_user_puid, ldap_user_puid_property, ldap_user_current_dn, ldap_user_last_checked, ldap_user_ldap_exclude) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11, :db_insert_placeholder_12, :db_insert_placeholder_13, :db_insert_placeholder_14, :db_insert_placeholder_15, :db_insert_placeholder_16, :db_insert_placeholder_17, :db_insert_placeholder_18, :db_insert_placeholder_19, :db_insert_placeholder_20)', Array, Array) (Line: 87)
Drupal\Core\Database\Driver\mysql\Connection->query('INSERT INTO {users_field_data} (uid, langcode, preferred_langcode, preferred_admin_langcode, name, pass, mail, timezone, status, created, changed, access, login, init, default_langcode, ldap_user_puid_sid, ldap_user_puid, ldap_user_puid_property, ldap_user_current_dn, ldap_user_last_checked, ldap_user_ldap_exclude) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11, :db_insert_placeholder_12, :db_insert_placeholder_13, :db_insert_placeholder_14, :db_insert_placeholder_15, :db_insert_placeholder_16, :db_insert_placeholder_17, :db_insert_placeholder_18, :db_insert_placeholder_19, :db_insert_placeholder_20)', Array, Array) (Line: 32)
Drupal\Core\Database\Driver\mysql\Insert->execute() (Line: 952)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->saveToSharedTables(Object) (Line: 890)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->doSaveFieldItems(Object, Array) (Line: 27)
Drupal\user\UserStorage->doSaveFieldItems(Object) (Line: 257)
Drupal\Core\Entity\ContentEntityStorageBase->doSave(NULL, Object) (Line: 392)
Drupal\Core\Entity\EntityStorageBase->save(Object) (Line: 796)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object) (Line: 377)
Drupal\Core\Entity\Entity->save() (Line: 109)
Drupal\entity_clone\EntityClone\Content\ContentEntityCloneBase->cloneEntity(Object, Object, Array) (Line: 18)
Drupal\entity_clone\EntityClone\Content\UserEntityClone->cloneEntity(Object, Object, Array) (Line: 83)
Drupal\entity_clone\EntityClone\Content\ContentEntityCloneBase->cloneEntity(Object, Object, Array) (Line: 150)
Drupal\entity_clone\Form\EntityCloneForm->submitForm(Array, Object)
call_user_func_array(Array, Array) (Line: 111)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 51)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 585)
Drupal\Core\Form\FormBuilder->processForm('entity_clone_form', Array, Object) (Line: 314)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 74)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 576)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array) (Line: 153)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 657)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
Why should clone a user? That's strange. In my opinion the new clone form decrease the User Experience dramatically. Our editors use the clone functionality quite often. This form will lead to frustration to the user because of they will have no idea what options need to use. Best practice from my point of view: no options. My favoritized and working approach is still #35
rwam’s picture

colan’s picture

It seems like we're trying to do too many things here. Here's a plan to get back to basics:

  • Remove the form from the process (no options).
  • Clone Entity Reference Revisions (e.g. Paragraphs) sub-entities.
  • Don't clone any other sub-entities.

This has the benefit of:

  • Streamlining the UX by reducing the number of steps.
  • Not confusing the user. (e.g. Which checkboxes should I check?)

I think it's safe to make assumptions about what types of entities to clone. Generally, we only want to clone entities that are tightly coupled with (and meaningless without) their host entities. For example, we do want to clone Paragraphs because they only exist in the host entity context, but we don't want to clone Users because they don't. Users exist on their own outside the referencing entity and have value in other contexts.

Even though Field Collections are another example of a tightly-coupled sub-entity, let's forget about them for now as they don't implement ERR and this makes it more complicated. This can be implemented in a separate follow-up issue. If there are use cases for cloning other types of sub-entities (those that aren't tightly coupled), these can be handled in other follow-up issues, and discussed there. Let's got a basic implementation of this working first so that we can cut another alpha release with it, and have something to build on.

Thoughts?

rwam’s picture

Hi @colan,

sounds good for me. And I'm ready to test further patches.

Ciao
Ralf

colan’s picture

@vpeltot: What do you think?

mvantuch’s picture

Hi, we have recently faced the issue with paragraph references on two projects and your proposed solution (#67) would be exactly solving our problem.

vpeltot’s picture

This module provide a core to allows cloning any kind of entities.

The clone system, and specially for this issue "Support for sub-entity cloning", must be the same regardless of the target entity types attached on entity_reference (maybe entity_reference_revisions) fields.

Not all sites use paragraphs, not all sites use field collections, but ALL SITES use some entity reference fields.
We can't consider and handle all use cases with this module.
We must be (as must be any contrib module) as generic as possible.

To solve this issue and this discussion, and improve the UX, what do you think about:

  • Keep the clone process as it is in #63 (with the form)
  • Add an admin UI to choose the default cloning action for each target entity types (cloning too, keep the same target, ...) and build the form considering this settings (checkboxes with default values TRUE/FALSE and maybe disable TRUE/FALSE).
  • Add an admin UI to choose if the form element with checkboxes (regarding the previous settings) must be viewed by the user.

To handle all other uses cases, this module add two handler in entities:

  • entity_clone
  • entity_clone_form

Everyone can be create their own handler classes for custom entities or override all existing handler classes.

colan’s picture

Add an admin UI to choose if the form element with checkboxes (regarding the previous settings) must be viewed by the user.

If by this you mean that there's a configuration option to skip the clone form (a checkbox like Allow users to specify sub-entity cloning behaviour that can be left unchecked), and just use the defaults, I think this is a good solution which (1) can provide a good UX (i.e. no clone form), and (2) allows for clone workflow flexibility. This should satisfy all of the feedback we've received so far.

colan’s picture

@vpeltot: Do you have time to work on this? If not, I can work on it in the next couple of weeks.

vpeltot’s picture

@colan, thanks for your help, but I started this feature since some days.
Here a first patch with new settings form /admin/config/system/entity-clone to define the entity clone form settings.
This form allows to set (for referenced entities in the entity clone form regarding the target entity type):

  • The default value checkboxes
  • Disable (TRUE/FALSE) checkboxes
  • Hide (TRUE/FALSE) the fieldset containing checkboxes

@colan, Can you test this patch? And maybe refine:

  • Wording
  • Settings UX

The last submitted patch, 74: support_for_sub_entity-2706639-74.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 76: support_for_sub_entity-2706639-75.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

vpeltot’s picture

colan’s picture

Assigned: vpeltot » colan

Yes, will test shortly. Thanks for working on this. I found some coding standards issues so fixing that and breaking up some of the big methods first.

colan’s picture

Here's the code clean-up. I didn't get a chance to test it yet, but I will shortly.

The last submitted patch, 80: entity_clone-add_support_for_cloning_subentities-2706639-80.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

colan’s picture

Assigned: colan » Unassigned

Noticed this failed so unassigning in case someone wants to take a look while I'm off for the day.

vpeltot’s picture

rwam’s picture

Status: Needs review » Needs work

Hm, the patch works only for the following settings:

- CHECKBOXES DEFAULT VALUE – checked
– DISABLE CHECKBOXES – not checked
- HIDE CHECKBOXES – not checked

If either »DISABLE CHECKBOXES« or »HIDE CHECKBOXES« are checked, cloning doesn't clone referenced entities. And deleting a cloned node will delete all paragraphs. And all affected nodes have missing references ;-(

The problem is situated in the cloning form. If you disable or hide the checkboxes, the default value setting is not considered by the cloning form.

I want to have the following settings to work:

- CHECKBOXES DEFAULT VALUE – checked
– DISABLE CHECKBOXES – not checked
- HIDE CHECKBOXES – checked

The editor gets an well known interface (not checkboxes) and cloning works for referenced entities too.

colan’s picture

Here's the last interdiff.

@vpeltot: The code looks a lot better now, which is great. Thanks for switching to ::class everywhere in entity_clone.module. That was the next step. I still think ContentEntityCloneBase::cloneReferencedEntities() is too long. Methods shouldn't be longer than 20 lines or so, unless they're producing a big form or some such. That's why I broke out getChildProperties() and getTargetIds(). Maybe these could use better names, but is there a reason we can't do something like this? It would make the code much more readable.

That aside, I'll start looking at functionality.

@rwam: Thanks for the extremely quick reviews!

colan’s picture

What I've found so far UX-wise:

  1. There's no configure link on the Extend (modules) page. I added this earlier, but it was removed. Not sure why.
  2. The configuration page is under Configuration -> System, which it would be more appropriate to be under Configuration -> Content authoring.
  3. We need a high-level description of what each form is about and why it's necessary, a short paragraph at the top. This can be implemented with $form['description'] = ['#markup' => 'Form description here'];. Needs to be done for both:
    • The config form
    • The clone form
  4. I'm not seeing a Your configuration settings have been saved message after saving the configuration form. Maybe we need to specify that it's an admin form?

We can worry about the above items later; I'm happy to get this thing working first.

Functionally, on running the clone operation with Paragraph fields, I wasn't getting new entities (even though it looked like I was as I could change the clone's values without it affecting the original). As mentioned above, deleting the clone would delete the original's values.

I believe I found the problem over here:

+++ b/src/EntityClone/Content/ContentEntityCloneBase.php
@@ -65,4 +86,49 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
+        && $properties['recursive'][$field_definition->id()]['references'][$referenced_entity->id()]['clone'] === 1) {

Dropping the ===1 seems to work better as the value is probably a string and not an integer (having come from the form submission). When I delete the clone, the original's values are still there. Can someone else confirm?

websiteworkspace’s picture

The ability to clone sub-entities, (entities within entities), is essential to be able to support cloning of Drupal Commerce 2.x entities. A Commerce entity always consists of a product entity with at least one product variation entities embedded, in which there can also be product attribute entities embedded within the product variation.

Currently, entity clone cannot correctly clone a Commerce 2.x entity.

rwam’s picture

I believe I found the problem over here:

+++ b/src/EntityClone/Content/ContentEntityCloneBase.php
@@ -65,4 +86,49 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
+ && $properties['recursive'][$field_definition->id()]['references'][$referenced_entity->id()]['clone'] === 1) {
Dropping the ===1 seems to work better as the value is probably a string and not an integer (having come from the form submission). When I delete the clone, the original's values are still there. Can someone else confirm?

It seems to work better, right. But I think there are more tests necessary, because it was a quick test and for paragraphs only.

colan’s picture

This should fix all of #85 and #86. Please test.

rwam’s picture

Status: Needs review » Needs work

Hi @colan,

settings in combination with hidden checkboxes work well, but the following setting results in the same error of corrupt clone with not cloned sub entities:

- CHECKBOXES DEFAULT VALUE – checked
– DISABLE CHECKBOXES – checked
- HIDE CHECKBOXES – not checked

By the way: I'm undecided because of the amount of text on the clone form page. It's also too technical from my side. Which content editor knows all kind of build in terms. Especially if all options are hidden this could lead to some frustrations to the editor. Any other thoughts to this topic are appreciated.

Ciao
Ralf

Johnny vd Laar’s picture

The patch works for me on a paragraph with a nested paragraph. But it's not working on the translation.

So my node:

node:
- paragraph
-- paragraph

has a translation NL & EN

The EN translation has correct new nested paragraphs. The NL has an incorrect lowest level paragraph (still the original). It also didn't change the NL node title with the clone suffix.

achton’s picture

I can confirm the bug in #86 re. "deleting the clone would delete the original's values", even with the latest patch.

I am working with a Paragraph field with multiple paragraphs, and while it appears that editing the original's paragraphs does not affect the cloned node, deleting the original node will delete the paragraphs in the new, cloned node.

Also, I was unable to hide the form shown when clicking the Clone menu item, regardless of the configuration of the module - is it forced shown for admin users?

andypost’s picture

Probably better to split the huge patch in parts, it has a lot of code style changes (array syntax & @file)

miro_dietiker’s picture

Hmm, stumbled across this and i have to admit that my wordings in #2706639-4: Support for sub-entity cloning was not fully correct.

ERR only is a forced composite relationship if it is annotated as such. (For instance Paragraphs annotates the fields that ERR can use as a parent reference).

If you use ERR without that annotation, it can be used to point to any revision of a non-composite entity and that case should be treated like regular ER. Side note: The ERR does not offer a widget at all that allows a user to see that the reference points to an outdated revision and neither offers tools to update that reference. This functionality could make sense for demanding legally strongly moderated content situations, but needs further investigation and support.

I think it's fine to focus on a simplified implementation and support the extra use-case in follow-ups.

vpeltot’s picture

@rwam

I tried to reproduce your use case, but I don't

My test, step by step:

Configuration:

  • Install a new drupal instance with standard profile
  • Enable Paragraphs module
  • Enable entity_clone module
  • Create 2 paragraphs types including the same title field:
    Paragraphs type A
    Paragraphs type B
  • Add 1 entity_reference_revision field in Article content type. This field reference the 2 previous types
  • Entity clone settings for paragraphs: 1 / 1 / 0 (Default value / Disable / Hide)

Create contents:

  • Create 1 Article content
  • Title: Article test
  • Paragraphs:
    Paragraph A
    Paragraph B

Clone:

  • Clone action: The form is correctly created regarding the entity clone settings
  • Do clone

After clone:

  • 2 articles with 2 paragraphs both:
    Article test
    Article test (Cloned)
  • Edit the cloned article, add 'Cloned' to the paragraphs A and paragraphs B title
  • Result:
    First article is always the same and paragraphs still the same too
    Cloned article and their paragraphs have the 'Cloned' values
rwam’s picture

Hi @vpeltot,

that's right, the revisions are different, but the entity id is the same. There is one more step missing:

Delete content:

  • Delete the cloned article
  • Result:
    All paragraphs are missing on the original too.

Ciao
Ralf

vpeltot’s picture

@rwam

Yeah ! I have reproduced your (last?) bug !

The cause was: When a form element is disabled, the #default_value is ignore in $form_state->getValues().

I've replace:
'#default_value' => $this->entityCloneSettingsManager->getDefaultValue($referenced_entity->getEntityTypeId()),
by
'#value' => $this->entityCloneSettingsManager->getDefaultValue($referenced_entity->getEntityTypeId()),

Here a new patch with:

Status: Needs review » Needs work

The last submitted patch, 97: entity_clone-clone_sub_entities-2706639-97.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 99: entity_clone-clone_sub_entities-2706639-99.patch, failed testing. View results

rwam’s picture

Hi @vpeltot,

Yeah ! I have reproduced your (last?) bug !

May be, we'll see ;)

I've tested your patch in #99 and it works fine. Cloning nodes with paragraphs and with disabled or hidden checkboxes (described in #84) creates new entities resp. revisions and it's possible to delete original or cloned content without losing any other content.

I think, other tests are necessary (Commerce, Media, Blocks), but it looks pretty good so far.

Thank you and ciao
Ralf

colan’s picture

Attached is an interdiff for easier code review between my last patch, and the last one here which fixes the deletion issue, the failing test, and some coding standards.

I've updated the list of things to do / test in the IS based on recent comments.

Can folks test to ensure that the data loss problem is fixed? If so, maybe we can commit this, and then get everything else done in follow-up issues. This issue is getting rather long and complex.

vpeltot’s picture

Issue summary: View changes

Let's end with this issue.

I've created a new issues for less critical todo:

Remaining tasks:

  • Test coverage: Delete cloned entities has no impact for original entity
vpeltot’s picture

vpeltot’s picture

Issue summary: View changes

Tests OK, no more remains to be done.

john.oltman’s picture

Successfully tested on 8.4.3 with deeply nested Paragraphs. However, when the content has a Paragraph that references a Menu via an Entity Reference field on the Paragraph Type, the following error is thrown immediately after the Clone link is clicked:

Recoverable fatal error: Argument 1 passed to Drupal\entity_clone\EntityClone\Content\ContentEntityCloneFormBase::getChildren() must implement interface Drupal\Core\Entity\ContentEntityInterface, instance of Drupal\system\Entity\Menu given.

This is certainly a less common use case, but since Paragraphs can reference entities that aren't content, probably worth fixing at some point. FWIW, I am using the menu_reference_render module to output the referenced menu entity, although that isn't coming into play during the clone.

DamienMcKenna’s picture

Would this help, verify that the $referenced_entity is a ContentEntityInterface before processing it?

larowlan’s picture

larowlan’s picture

larowlan’s picture

  1. +++ b/src/EntityClone/Content/ContentEntityCloneBase.php
    @@ -54,15 +58,136 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
    +    $type_is_clonable = in_array($field_definition->getType(), $clonable_field_types);
    
    +++ b/src/EntityClone/Content/ContentEntityCloneFormBase.php
    @@ -0,0 +1,188 @@
    +        if ($field_definition instanceof FieldConfigInterface && in_array($field_definition->getType(), ['entity_reference', 'entity_reference_revisions'])) {
    

    nit, should use third argument, as we know these are strings

  2. +++ b/src/EntityClone/Content/ContentEntityCloneBase.php
    @@ -54,15 +58,136 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
    +      if (isset($properties['recursive'][$field_definition->id()]['references'][$referenced_entity->id()]['clone'])
    +        && $properties['recursive'][$field_definition->id()]['references'][$referenced_entity->id()]['clone']) {
    

    can just use !empty() here

  3. +++ b/src/EntityClone/Content/ContentEntityCloneBase.php
    @@ -54,15 +58,136 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
    +  protected function formatTargetIdsAsArray($target_id, $target_revision_id) {
    +    return [
    +      'target_id' => $target_id,
    +      'target_revision_id' => $target_revision_id,
    +    ];
    

    in theory, this shouldn't be needed. The setValue call with an entity object should handle this for you at the typed data layer. i.e. you should be able to set the value using the entity objects. See http://cgit.drupalcode.org/drupal/tree/core/lib/Drupal/Core/Field/Plugin... and http://cgit.drupalcode.org/drupal/tree/core/lib/Drupal/Core/Field/Plugin...

  4. +++ b/src/EntityClone/Content/ContentEntityCloneFormBase.php
    @@ -0,0 +1,188 @@
    +  public function __construct(EntityTypeManager $entity_type_manager, TranslationManager $translation_manager, EntityCloneSettingsManager $entity_clone_settings_manager) {
    

    These should typehint interfaces, not concrete classes

  5. +++ b/src/EntityClone/Content/ContentEntityCloneFormBase.php
    @@ -0,0 +1,188 @@
    +    if ($entity instanceof FieldableEntityInterface) {
    +      foreach ($entity->getFieldDefinitions() as $field_id => $field_definition) {
    +        if ($field_definition instanceof FieldConfigInterface && in_array($field_definition->getType(), ['entity_reference', 'entity_reference_revisions'])) {
    +          $field = $entity->get($field_id);
    +          /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $value */
    +          if ($field->count() > 0) {
    +            $form['recursive'] = array_merge($form['recursive'], $this->getRecursiveFormElement($field_definition, $field_id, $field));
    +          }
    +        }
    +      }
    ...
    +  protected function getRecursiveFormElement(FieldConfigInterface $field_definition, $field_id, FieldItemListInterface $field) {
    

    what about base fields? it is possible to define an entity reference field or paragraph field as a base field, using FieldConfigInterface we're limiting our options

  6. +++ b/src/EntityClone/Content/ContentEntityCloneFormBase.php
    @@ -0,0 +1,188 @@
    +      $form_element[$field_definition->id()]['references'][$referenced_entity->id()]['clone'] = [
    +        '#type' => 'checkbox',
    +        '#title' => $this->t('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()),
    +      ];
    

    this should include an access check, '#access' => $referenced_entity->access('view label'),

  7. +++ b/src/EntityClone/Content/ContentEntityCloneFormBase.php
    @@ -0,0 +1,188 @@
    +  public function getValues(FormStateInterface $form_state) {
    +    return $form_state->getValues();
    

    is this needed?

Removed the related issue, I missed the fact that the form already called that.

larowlan’s picture

Also, there are a lot of coding standards changes in the patch.

In my opinion, to minimize the disruption and size of the patch, those should be split into their own issue.

larowlan’s picture

E.g, this patch conflicts with #2845094: Batch field creation but only because of the coding standards changes

larowlan’s picture

Issue summary: View changes
Status: Needs review » Needs work
FileSize
30.63 KB
+++ b/src/Form/EntityCloneForm.php
@@ -102,11 +102,26 @@ public function getFormId() {
+      $form['description'] = [
+        '#markup' => t("
+          <p>Specify the child entities (the entities referenced by this entity) that should also be cloned as part of
+          the cloning process.  If they're not included, these fields' referenced entities will be the same as in the
+          original.  In other words, fields in both the original entity and the cloned entity will refer to the same
+          referenced entity.  Examples:</p>
+

This should be hidden if all checkboxes are also hidden.

See screenshot

larowlan’s picture

  1. +++ b/src/EntityClone/Content/ContentEntityCloneBase.php
    @@ -54,15 +58,136 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
    +   * @param Drupal\Core\Field\FieldDefinitionInterface $field_definition
    

    missing leading \

  2. +++ b/src/EntityClone/Content/ContentEntityCloneBase.php
    @@ -54,15 +58,136 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
    +  /**
    +   * Fetches the properties of a child entity.
    +   *
    +   * @param array $properties
    +   *   Properties of the clone operation.
    +   * @param \Drupal\Core\Field\FieldConfigInterface $field_definition
    +   *   The field definition.
    +   * @param \Drupal\Core\Entity\EntityInterface $referenced_entity
    +   *   The field's target entity.
    +   */
    ...
    +    return $child_properties;
    

    Missing @return tag

larowlan’s picture

larowlan’s picture

this also needs an update hook to create the new config object and clear the cache, to setup the entity_clone_form handlers on the entity types

vpeltot’s picture

@larowlan Thanks for this review.

In this patch:

#111

  1. Done
  2. Done
  3. Done
  4. Done
  5. I think it would be better to create a new issue with a concrete use case and no longer block this issue
  6. Done
  7. Yes, this method is needed and used by \Drupal\entity_clone\Form\EntityCloneForm::submitForm to get form values from specific form handlers

#115
Done

#116
Included with rework. Description and method descriptionShouldBeShown moved in \Drupal\entity_clone\EntityClone\Content\ContentEntityCloneFormBase

#117
Done

pguillard’s picture

Thanks for this patch ! RTBC ++

  • All cloned entities have a new id (they are really cloned)
  • The EntityCloneSettingsForm is working well

Just corrected 3 typos (some trailing whitespace when applying the patch..)

I guess some english natives should verify the form description.
At least I suggest this one :

For each type of child entity (the entity that's referenced by the entity being cloned), please set your cloning preferences.

=>

Please set your cloning preferences for each type of child entity referenced by the entity being cloned.

Status: Needs review » Needs work

The last submitted patch, 119: entity_clone-clone_sub_entities-2706639-119.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

pguillard’s picture

pguillard’s picture

I guess the 2 failing tests are not related to this patch, but also failing also on the 8.x-1.x branch !
Can't find why..

sam.spinoy@gmail.com’s picture

Awesome work here with this patch! Been testing it on a site that has lots of content and references, and I regularly run into this error:

Error: Call to a member function getValue() on null in Drupal\entity_clone\EntityClone\Content\ContentEntityCloneFormBase->getRecursiveFormElement() (line 160 of /modules/contrib/entity_clone/src/EntityClone/Content/ContentEntityCloneFormBase.php)

This happens when a reference field contains a target_id that points to an entity that has been deleted. I've added a new patch based on the previous one, where we simply skip the deleted entity instead of trying to load/clone it.

colan’s picture

#123: Please provide an interdiff.

pguillard’s picture

Status: Needs work » Needs review
FileSize
1.54 KB

Attached an interdiff for the last patch #123.

Status: Needs review » Needs work

The last submitted patch, 123: entity_clone-clone_sub_entities-2706639-123.patch, failed testing. View results

pguillard’s picture

Status: Needs work » Needs review
FileSize
47.31 KB

Some .DS_Store stuff was introduced in #123, so this is a new patch

Status: Needs review » Needs work

The last submitted patch, 127: entity_clone-clone_sub_entities-2706639-127.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

amy.h’s picture

Does this support cloning panels pages? Along with the variants and block plugins inside it.

DamienMcKenna’s picture

@matthew.h: I believe Panels pages are config entities, and this module works on content entities, so that'd be "no".

pguillard’s picture

Status: Needs work » Needs review
FileSize
47.95 KB
564 bytes

This new one should pass tests.

I guess this is the change : Issue #2911806: Remove unnecessary Crypt::hashBase64() call from Action UI by tim.plunkett.
This is impacting the whole module, not this patch particulary.
(I made another ticket there #2950432: EntityCloneActionTest fails)

sam.spinoy@gmail.com’s picture

In relation to this ticket https://www.drupal.org/project/entity_clone/issues/2945192

I noticed that all form elements in the formElement() method in the ContentEntityCloneFormBase class get built no matter what, even if the user has no access to them (because the "Hide checkboxes" option is checked at /admin/config/system/entity-clone). I've made an addition to the patch that simply skips the fields if we cannot access them.

This does not actually solve the problem of the timeout in #2945192 due to recursive looping, but it does offer a workaround: if an admin decides how to clone entities (and thus checks all the "Hide checkboxes" on the config page), we don't need to build a render array and get no error.

Again, I know it doesn't actually solve the problem but I think it's a good addition either way, no need to build stuff that will not be rendered anyway. The cloning actions seems to be successful without this "invisible" form too, though that might be because of my specific setup. I'm sure one of the module maintainers will have a more qualified opinion on this :)

colan’s picture

#132: Please provide an interdiff so we can more easily review changes. Thanks.

pguillard’s picture

Interdiff

sam.spinoy@gmail.com’s picture

Actually that latest change of mine makes it so that sub-entities don't get cloned :/ The cloned node just refers to the same entities as the original page. So please disregard the patch.

sam.spinoy@gmail.com’s picture

sam.spinoy@gmail.com’s picture

I guess the problem for issue 2945192 lies in the fact that recursive cloning can get quite complicated depending on your setup. Looking at the image below you can see that I'm already 5 levels deep, and that is just from one node referencing a paragraph that than in turn references another node that has another paragraph, ...
.

I am thinking that not displaying anything below the first unchecked checkbox by default could help, and when a user checks the "yes let me clone this entity" checkbox, ajax in the sub-elements? It would in any case avoid the rending of a huge form with a lot of nested elements from the beginning.

For the project that I'm working on now I've created a patch that does not display any sub-elements if the parent type shouldn't be cloned. It works for me because the editors have no control over what they can clone or not, so all the checkboxes are hidden by default. This is not a generic solution though.

Status: Needs review » Needs work

The last submitted patch, 137: entity_clone-clone_sub_entities-2706639-136.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

colan’s picture

#137: Please create a follow-up issue for that.

sam.spinoy@gmail.com’s picture

A follow-up issue on what? There is already an issue here https://www.drupal.org/project/entity_clone/issues/2945192 but I figured I'd keep it all in one thread since it's about the same functionality.

colan’s picture

I was talking about this UX issue you raised:

I am thinking that not displaying anything below the first unchecked checkbox by default could help, and when a user checks the "yes let me clone this entity" checkbox, ajax in the sub-elements? It would in any case avoid the rending of a huge form with a lot of nested elements from the beginning.

My point was that we should focus exclusively on getting the primary goal here finalized and committed. UX improvements and the like can be handled afterwards, in separate issues. If we try to do too much in this issue, we'll never get it done. As can be seen in #2945192: Fatal error: Maximum function nesting level of '256' reached, aborting! With Support for sub-entity cloning patch, a lot of folks are waiting for this.

sam.spinoy@gmail.com’s picture

I agree, but I don't think the ajaxing in of sub-elements is a UX improvement, I saw it as a way of solving issue #2945192. But it might not be the best way, I don't know.

pguillard’s picture

I added another follow-up issue/proposition : #2953641: Possibility to set fields that should not be cloned

pguillard’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
50.89 KB
2.91 KB

Patch at #137 needs some extra work on the EntityCloneContentRecursiveTest.
A schema for our entity_clone form_settings was also missing.

Pejka’s picture

This patch can not be applied to alpha2 version

pguillard’s picture

You should try it on the 8.x-1.x-dev branch

vpeltot’s picture

#129 / #130
@matthew.h @DamienMcKenna This module supports to clone config entities, and provide a clone base / core concept for all drupal core entities.
If an entity (like panels & co) doesn't supported by this module, I suggest to create modules for each specificities (eg. entity_clone_panels)

#132 / #137 / ...
All problems around #2945192: Fatal error: Maximum function nesting level of '256' reached, aborting! With Support for sub-entity cloning patch must be discussed / resolved in #2945192: Fatal error: Maximum function nesting level of '256' reached, aborting! With Support for sub-entity cloning patch

This new patch has been created from #118 and contains all @pguillard updates. All updates about #2945192: Fatal error: Maximum function nesting level of '256' reached, aborting! With Support for sub-entity cloning patch was removed.

voleger’s picture

At least patch helps to clone paragraph references correctly.
I had added the checkbox for paragraphs entity references, and now deletion of the cloned entity has no influence on the references of the original entity.

Mars0test’s picture

Status: Needs review » Reviewed & tested by the community

Ok it's fine for me.
For a next feature improve the ux can be great. ;)

  • vpeltot committed 877cc4c on 8.x-1.x
    Issue #2706639 by vpeltot, colan, pguillard, samspinoy, michaellander,...
vpeltot’s picture

Status: Reviewed & tested by the community » Fixed

Commited !
Thanks @all

pguillard’s picture

Cool, thanks !

rwam’s picture

Great news. Thanks @all.

hudri’s picture

Thanks a lot for all the work done here, the editors in my office are really keen on this patch, will save them a lot of time. Could we get a new release for this in the alpha channel?

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

jibran’s picture

Just saw this commit in latest dev I think we should address these before next release.

  1. +++ b/entity_clone.install
    @@ -0,0 +1,30 @@
    + * Implements hook_update_N().
    

    Desc should be a summary of what this update is performing.

  2. +++ b/entity_clone.install
    @@ -0,0 +1,30 @@
    +function entity_clone_update_8001() {
    

    This should be post-update hook.

colan’s picture

Can you repost in #2930403: [META] Beta1 release? This issue is closed/fixed.

acbramley’s picture

websiteworkspace’s picture

Thanks for working on this problem.

I am putting this code update on my todo list for regression testing on a test site, to see if this works properly now with custom content types that contain paragraphs, and with drupal commerce 2.x products and so forth which also contain nested entities.

-

Also, when will those code change make its way into an alpha/beta release and not just in the dev channel release?

Chris Matthews’s picture