Hi,
Issue: Save entity variable in a Loop through a view result variable saves only 1 entity
The first loop goes ok, the second loop re-saves the first entity with new values.
So my issue is when you have a save entity variable action on a loop it's saving the same entity instead of creating a new entity. I believe it has something to do with the uuid.
Also receive an warning when you loop:
Warning: array_flip(): Can only flip STRING and INTEGER values! in Drupal\Core\Entity\EntityStorageBase->loadMultiple() (line 264 of core/lib/Drupal/Core/Entity/EntityStorageBase.php).
Drupal\Core\Entity\EntityStorageBase->loadMultiple(Array) (Line: 249)
Drupal\Core\Entity\EntityStorageBase->load(NULL) (Line: 527)
Drupal\Core\Entity\Entity::load(NULL) (Line: 643)
Drupal\business_rules\Util\BusinessRulesProcessor->evaluateVariables(Object, Object) (Line: 473)
Drupal\business_rules\Util\BusinessRulesProcessor->executeAction(Object, Object) (Line: 316)
Drupal\business_rules\Util\BusinessRulesProcessor->processItems(Array, Object, 'entity_insert_ato') (Line: 261)
Drupal\business_rules\Util\BusinessRulesProcessor->processTriggeredRules(Array, Object) (Line: 168)
Drupal\business_rules\Util\BusinessRulesProcessor->process(Object) (Line: 136)
Drupal\business_rules\EventSubscriber\BusinessRulesListener->process(Object, 'business_rules.entity_insert', Object)
call_user_func(Array, Object, 'business_rules.entity_insert', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('business_rules.entity_insert', Object) (Line: 115)
business_rules_entity_insert(Object)
call_user_func_array('business_rules_entity_insert', Array) (Line: 403)
Comments
Comment #2
pepe roni commentedDid you reset the entity fields (especially uuid and id) when filling the entity fields again?
Comment #3
c.e.a commentedCan you please provide step by step on how to reproduce this issue ?
Comment #4
c.e.a commentedComment #5
c.e.a commentedComment #6
lexsoft00 commentedHi @C.E.A,
* 3 content types: Article, Basic Page, Test.
1. Create 5 Basic Pages and display their NID in a view
2. Create a views variable result variable
3. Create a empty entity variable for Article
4. Create a empty entity variable for Basic Page
5. Create a loop variable result action
6. Create action to Fetch entity variable by id and add the {{views-variable-result->nid}}
7. Create action Fetch and set values to entity variable with empty entity variable Article, Article bundle and content type, add field title with {{empty-entity-variable-basic-page->title}}
8. Create action Save entity variable to Article variable
Add 6. 7. and 8. to 5. loop variable result action
Add a Rule entity update on Test content type node and add 5. loop variable result action to it.
Test by create a Test node and update it.
Comment #7
lexsoft00 commentedComment #8
lexsoft00 commentedI've got something working.
Comment #9
lexsoft00 commentedMissing 1 closure
Comment #10
Deno commentedThis still isn't fixed in beta8. Patch works AFAIK, at least it did before - we will test on beta8 tomorrow.
Comment #11
Deno commentedMy assumption is that the entity variable gets assigned a nid when saved the first time and then this nid is used in all subsequent saves. This is what I see when debugging block is enabled.
Unfortunately, there is no way (that I can see) to reset a field value that was set before. In general, the GUI will not allow you to assign empty value to a field. In my opinion, this is the actual bug and the failure to use this in a loop is then just a logical consequence.
Comment #12
Deno commentedComment #13
Deno commentedApparently not working in beta8.
Btw, I took a look at the patch and it confirmed what I already suspected: rules are confused weather to save this as a new node or to update old one. In the meantime I'm convinced that the approach described in #3076481: "Save as new entity" option is a way to go: define two actions (one for adding new entities and one for trying to update if possible) or a Boolean switch that forces adding new entities rather than try to be clever about this.
People writing the rules know what they want (e.g. add new entities in the loop) and if they have an "always add new nodes" option to choose, they will do it.
In which case the code simplifies to something like this:
if ($always_add) {
$entity->uuid->value = $uuid_new;
$entity->nid->value = NULL;
$entity->save();
}
Where "$always_add" is a boolean.
No checking if uuids already exist or not, we simply force the system to generate a new item. As a bonus, we get a nice new functionality: the nodes can be easily used as templates - just load a "template" node, change a parameter or two as needed and store it as new node. That would resolve #3076481: "Save as new entity" option and #3076410: Fetch, update and save as new node not possible, while making the #3076450: Assigning values to fields in an entity variable is badly broken far less urgent.
Comment #14
Deno commentedUpdate: https://www.drupal.org/docs/8/api/entity-api/working-with-the-entity-api..., and the documentation states the following:
I suppose something like this would then work to force saving as new:
Not sure about uuid, maybe one has to create a new one instead of setting it to NULL?
Maybe
$entity->uuid->generate();?Comment #15
Deno commentedOK, there was a misunderstanding earlier... I had a good look at the patch again (sorry, I'm not a developer) and realized that it checks if the UUID changed and if it did saves the entity as new. This is pretty much what I suggested earlier..
I added a "put random number in UUID" as a part of the set action and it still didn't work. Then I double-checked and found out that the patch still wasn't applied on the server because it doesn't apply correctly on beta 8. However, the patch is really simple so we applied it "per hand" and now the rule works as expected.
As I said, I'm assigning a random number to UUID in a loop, which results in an invalid but definitely assures that the new uuid is always different from the old one. Before patching this resulted in ONE node that had invalid UUID in it (I'm surprised that this isn't checked by entity code). After patching, this results in several nodes generated and they have valid UUIDs
All in all, this works now. Moreover, it probably resolves #3076410: Fetch, update and save as new node not possible too, I'll test that next.
Comment #16
Deno commentedGood news: it is indeed possible to "save as new" entity variables that were loaded from existing entities in a loop (and outside it) once this patch is applied. Thus cloning with rules is suddenly possible, this is a very cool feature.
One little thing could (should) be added in the patch though: setting the time fields to the current values. See #3076410: Fetch, update and save as new node not possible for more details.
Comment #17
totolearn commentedOK, I think it is related to this problem for I did the search to all related issues.
In this process, I did applied #9 patch on current dev/beta 9 version but I still getting error:
Warning: array_flip(): Can only flip STRING and INTEGER values! 位於 Drupal\Core\Entity\EntityStorageBase->loadMultiple()
It has detail error with :
core/lib/Drupal/Core/Entity/EntityBase.php(531): Drupal\Core\Entity\EntityStorageBase->load(NULL) #5 ..../business_rules/src/Util/BusinessRulesProcessor.php(643): Drupal\Core\Entity\EntityBase::load(NULL) #6 ..../business_rules/src/Util/BusinessRulesProcessor.php(473) .....business_rules/src/Util/BusinessRulesProcessor.php(473): Drupal\business_rules\Util\BusinessRulesProcessor->evaluateVariables(Object(Drupal\business_rules\VariablesSet), Object(Drupal\business_rules\Events\BusinessRulesEvent)) #7....
total # form 30 to #52. the rest after #7 seems ok.
The setup to got this error is:
01. Create Level01: empty entity variable
02. Create Level02: empty entity variable
03. using Loop through a multi-value field variable, to get a multi-value referenced ID, in the loop
03-1: for each ref-ID fetch the entity put into 01's Level01 entity
03-2: set Entity variables to Level02 entity (with the values from Level01 entity and other calculated results)
03-3: Save the Level02 entity
the error is casued by 03-3
I planned to save multiple 03-3 entities, but even one already got the error.
On 03-2 it even put the uuid with random numbers but still getting the error.
Any advise will be appreciated.
Comment #18
totolearn commentedOK, the update for this issue, and it relates to https://www.drupal.org/project/business_rules/issues/3052265
Now, I used Beta-9 Feb/07/2020 version, the situation is:
when I applied #9 patch, it will create the new entities in the loop OK. But it will cause the problem of "New node created instead of updating existing node" when I modified an existing entity field when do a new entity by "before saving an entity", the same issue happened as in 3052265.
So, it has to do with the code added that need to separate the existed entity inside the loop from the new entity trigger the rule.
Anyone have the idea what to do?
Comment #19
Deno commentedI can confirm that my nicely working set of rules stopped working after update to beta9. The reason is not clear to me.
First, looking at my updates, the error must be either in entity or in busines rules. Second, the patch we are applying only changes one file in busines rules and this file has not changed from b3 to b4.
Here is the whole patch:
What the patch does is the following:
1. If someone changes the UUID while manipulating the in-memory copy of an entity, then a new entity should be generated.
2. To do so, a new UUID should be generated before saving.
3. This can be done by calling:
4. And a new entity is generated on save if the nid is unset and the uuid is given the new vaue that we just generated.
If any of this fails, things will not work.
Moreover, the changes from b3 to b4 appear to be minor. Here are the files that changed:
Mostly yaml files or related to drush, this leaves just a few files that might be causing the issue. SetFieldValue.php maybe?
Alternatively, it could be a change in entity module?
Comment #20
totolearn commentedin #18 my example, it should never need to create new UUID, the UUID changed duriing the processes.
03-1 step, fetch the 1st UUID to the first Empty Entity Variable, and
03-2 step, by the loop will get 2 UUID, to the Empty Entity Variables created and filled by fetched entities by ID referenced from 03-1's Entity.
And, when to saved the updated field value at 2nd level UUIID, instead of using the UUID, it got generated new UUID.
Then, it resulted 2 new Entities were created with all the value from 03-2 steps fetched entities.
So, what should be modified in the patch #9 to know the different level's UUID? Should we stacked the Entity Variables, I am not familiar with to coding format. Anyone?
Comment #21
djween commentedHi,
Use Case:
For every content id in Bundle A returned in view results, create a new node in bundle B and copy some values from A to B, such as title.
My Setup:
-View A - outputs a set of NIDs of type Bundle A
-View results variable A references View A, argument passed [node:nid]
-Empty entity variable A for Bundle A
-Empty entity variable B for Bundle B
-Rule: entity insert event. Target bundle: C
-- Loop action: loop view A.
---Fetch entity variable by id action: entity id field: nid, target bundle: A, entity variable: empty entity variable A, value: {{empty entity variable A->nid}}
---Set values to entity variable action: target bundle: B, entity variable: empty entity variable B, updating title field with token referencing bundle A title.
---Save entity variable action: target bundle: B, entity variable: empty entity variable B
Result:
-Views successfully passes array of multiple bundle A NIDs to variable. Confirmed with BR Debug.
-Bundle C node is created as expected.
-only 1 new bundle B node is created (it should create multiple bundle B nodes though based on view results). New node contains title and other data from bundle C (it should use data values from bundle A).
I applied patch but wasn't working. Anyone having success with patch on latest release or dev version at this point?
Comment #22
lexsoft00 commentedAre you using the action "
Set values to entity variable" ?I've added a patch for updating an entity but it's not creating a new one.
Comment #23
djween commented@lexsoft00
Yes, I am using "Set values to entity variable". I have updated my comment #21 to clarify this further.
Without your patch in #22, I have already been able to loop through a view and update the fetched entities. However, I was only able to do so when target bundle did not have other rules applied to it that leveraged variables - even if not the same variable. I have this issue posted regarding that matter: https://www.drupal.org/project/business_rules/issues/3136784
I am using BR version: 8.x-1.0-beta9+2-dev on D8.8.5
Comment #24
lexsoft00 commentedI use
Comment #25
djween commented@lexsoft00 I updated my installed BR module with all patches mentioned in #24.
I also updated it with patch in #22.
Using: D8.8.6, BR 8.x-1.0-beta9+2-dev
I am coming across 2 issues after testing further:
1) Unwanted duplicated node
I believe I am seeing same issue as Totolearn in #18...
when I have patch #9 installed, BR will create a duplicate node rather than just updating it. I use the fetch, set, and save actions (without any loop action) to update the current node on view entity event. The field I need updated gets updated successfully but it also duplicates the node which I do not want it to do. When I remove patch #9 it just updates the field as per my desired requirement and as I would expect it to do.
Either there is an issue here or it is not clear how I would specify to update vs create or do both with patch #9 in place.
2) New nodes successfully created but can't set field values with variables
In my setup mentioned in comment #21 and with patch #9, #22, and the others mentioned above installed, my BR rule only partially works. It correctly creates new nodes during the loop action however, it doesn't set field values with variables. Below are comments on my steps from my setup described in comment #21 which provide more detail on the issue:
-View A - outputs a set of NIDs of type Bundle A
-View results variable A references View A, argument passed [node:nid]
-Empty entity variable A created for Bundle A
-Empty entity variable B created for Bundle B
-Rule: entity insert event. Target bundle: C
-- Loop action: loop view A.
---Fetch entity variable by id action: entity id field: nid, target bundle: A, entity variable: empty entity variable A, value: {{empty entity variable A->nid}}.
---Set values to entity variable action: target bundle: B, entity variable: empty entity variable B, updating title field with token referencing bundle A title.
---Save entity variable action: target bundle: B, entity variable: empty entity variable B
Comment #26
lexsoft00 commentedLeaving the bugs for a second, I'm trying to understand why are you using "Fetch entity variable by id action" when you are already looping?
Can you not have all the data present in the view and pass it down?
If I understand correctly you have 3 content types
Let's call them:
1. Articles
2. Basic Page
3. Duplicate Page
You have the content type Articles that has an entity reference to the Basic Page.
On entity insert rule used on the bundle Articles you would like to clone the Basic Page to Duplicate Page?
Comment #27
djween commentedFor several reasons that are irrelevant now, I was doing it incorrectly. I added more fields to my view and am using view results variables to set my fields. This rule on its own works without issue now. Thank you @lexsoft00.
To hopefully save someone else some time, here is my working setup for reference:
Use Case: there is templated content and each user can create their own instance of this content.
Uses 4 content types:
Rule Setup
Comment #28
djween commented@lexsoft00 - I didn't realize initially that patch #22 adds a new action to set and save (and not create new node). In my comment #25 point #1:
your patch resolves this issue for me from my initial testing. I was able to set and save static data, tokens, and BR variables and no new node is created. I replaced my empty entity variable, and variable actions: fetch, set, and save with the single new action: "Set entity fields values to any entity and save". Much easier! Thank you.
Comment #29
lexsoft00 commentedHi @djween,
Glad that it works!
Comment #30
djween commentedAnyone know if this issue is resolved in version 2 release as I see version 2 does not include the action: Set entity fields values to any entity and save.
Comment #31
djween commentedSave entity variable in a Loop through a view result variable saves only 1 entity still occurs in version 2 of BR.
None of the patches here resolve this feature of business rules.Curious if anyone has a solution to resolve?patch #9 works. just need to manually update file as it failed via composer.
Comment #32
coaston commentedHi djween,
I tried to replicate your case #27 due to learning process, however I am getting following issue once I want to create a new node with User Agenda Parent
Drupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'title' cannot be null: INSERT INTO "node_field_data" ("nid", "vid", "type", "langcode", "status", "uid", "title", "created", "changed", "promote", "sticky", "default_langcode", "revision_translation_affected") 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); Array ( [:db_insert_placeholder_0] => 157630 [:db_insert_placeholder_1] => 219667 [:db_insert_placeholder_2] => user_agenda_children [:db_insert_placeholder_3] => en [:db_insert_placeholder_4] => 1 [:db_insert_placeholder_5] => 3 [:db_insert_placeholder_6] => [:db_insert_placeholder_7] => 1676649418 [:db_insert_placeholder_8] => 1676649418 [:db_insert_placeholder_9] => 0 [:db_insert_placeholder_10] => 0 [:db_insert_placeholder_11] => 1 [:db_insert_placeholder_12] => 1 ) in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 811 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).I am not sure why the title is null - i have configured "set values to entity variable action" with {{setup_a_view_results_variable_->title}}
Also I am not sure about contextual filter , have you configured "provide the default value" ??
Comment #33
djween commented@coaston
--First check your view outside of business rules. As in create a page from your view and make sure there are actual results.
--yes, in my case I have provided default value in the contextual filter. I am using "content id from url" in my particular case to filter the view.
--And in BR in the views variable, for the argument I have: [node:nid].
--Also make sure you have patch #9 installed.