Aside from not having to add 35 "set a data value" actions just to populate an entity with 35 properties/fields, it would also be very useful in terms of reducing multiple integrity checks. This action would allow you to change multiple properties/fields for an already existing entity in a single action. I guess the condition to check an entity's bundle type would be required in order for a particular entity to be available to this new modify action.

The basis for this feature request comes from discussion in #1322682: Many conditions may result in memory crashes?

fago suggests the following as a potential methodology:

select the entity and the properties in a first step and get forms for all properties then.
Files: 
CommentFileSizeAuthor
#45 rules-modify-entity-action-1421368-44.patch11.23 KBacrazyanimal
PASSED: [[SimpleTest]]: [MySQL] 329 pass(es).
[ View ]
#37 rules-modify-entity-action-1421368-37.patch11.19 KBacrazyanimal
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]
#36 rules-modify-entity-action-1421368-36.patch9.51 KBkrlucas
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch rules-modify-entity-action-1421368-36.patch. Unable to apply patch. See the log in the details link for more information.
[ View ]
#35 rules-modify-entity-action-1421368-35.patch9.83 KBkrlucas
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]
#28 rules-modify-entity-action-1421368-22.patch9.85 KBacrazyanimal
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]
#22 rules-modify-entity-action-1421368-21.patch9.78 KBacrazyanimal
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]
#20 rules-update-entity-action-1421368-19.patch8.4 KBacrazyanimal
FAILED: [[SimpleTest]]: [MySQL] 249 pass(es), 1 fail(s), and 0 exception(s).
[ View ]
#15 rules-update-entity-action-1421368-15.patch8.02 KBacrazyanimal
FAILED: [[SimpleTest]]: [MySQL] 250 pass(es), 0 fail(s), and 2 exception(s).
[ View ]

Comments

fago’s picture

Component:Rules Core» Rules Engine

Yep, I think that would be a very useful action in many situations. I'd work on it if I'd find the time :/ Still I'm happy to provide directions if anyone wants to take care of it.

AndrzejG’s picture

Something similar to Components/Rule or Rule Set? They accept as many variables as required.

Recently I added one to my Rules requiring 256 MB memory. Now 512 sometimes crashes. It seems memory hunger increases exponentially or even faster.

acrazyanimal’s picture

@fago: If you have some time to provide some directions I would be happy to start on this. I get how to define rule actions, but the parts that I would find difficult would be the loading of the entity's fields and respective form "setter" elements... and all that jazz.

I can see two potential workflows for this action:

1. first configuration form for the action would be to select the entity you want to modify. Once chosen and "continue" is clicked, all the available fields and properties we know about the entity are loaded. I'm guessing in this case it would mean that all of the current values for every element would have to be loaded and saved regardless of whether you wanted to only modify a couple of the fields or all of them.

2. the first configuration form for the action would have the same entity selector field, then potentially some ajax to load all the properties and fields as checkboxes to select the ones you want to set. Once everything is chosen and you click continue, the next configuration form would have all those fields loaded for you to set.

Note: I would also want to make this action available even if you have just created the entity in the action before this one.

bojanz’s picture

VBO has an action like this, so maybe it can be used for inspiration.
(uses entity metadata for properties, just like rules)

acrazyanimal’s picture

@bojanz I've been looking through the views interface for views based on several different entity types including content and when I add the vbo field I haven't come across a "modify entity" action yet. Is it more specific? Can you point me at how to enable such an operation.

I've been browsing through the modify.action.inc file and this seems like the code you are referring to, but I can't figure out how to test it out?

cheers.

bojanz’s picture

You should definitely be seeing "Modify entity values" in the VBO field settings (Views UI) for any entity type, including Content.
Retry as admin (if you weren't before), maybe it's a permission issue? And make sure you have the latest -dev (but then you say you found the modify.action.inc file, so it sounds like it is the latest...)

acrazyanimal’s picture

Weird, I have the latest dev release of views 3.x and am logged in as the site admin, but only see the following in the operations dropdown:

  • Change the author of content (node_assign_owner_action)
  • Delete item (views_bulk_operations_delete_item)
  • Display a message to the user (system_message_action)
  • Execute arbitrary PHP script (views_bulk_operations_script_action)
  • Make content sticky (node_make_sticky_action)
  • Make content unsticky (node_make_unsticky_action)
  • Pass ids as arguments to a page (views_bulk_operations_argument_selector_action)
  • Promote content to front page (node_promote_action)
  • Publish content (node_publish_action)
  • Redirect to URL (system_goto_action)
  • Remove content from front page (node_unpromote_action)
  • Save content (node_save_action)
  • Send e-mail (system_send_email_action)
  • Unpublish content (node_unpublish_action)
  • Unpublish content containing keyword(s) (node_unpublish_by_keyword_action)

The view is just a simple content based view of 'article' type with title and status fields for display in a table.

bojanz’s picture

You need to have the very latest VBO -dev.

acrazyanimal’s picture

I thought I had the latest dev, but turns out I did not. I see it now. Thanks.

fago’s picture

2. the first configuration form for the action would have the same entity selector field, then potentially some ajax to load all the properties and fields as checkboxes to select the ones you want to set. Once everything is chosen and you click continue, the next configuration form would have all those fields loaded for you to set.

I think that's the way it should work. Thus, we need a "properties" parameter which is just used to determine which properties we are setting. The general workflow for implementing such an action is to

1. implement action_info_alter() to alter in new parameters depending on already settings, i.e. alter in parameters for properties that should be changed.

2. implement action_form_alter() to implement the form-workflow using #ajax and multiple steps. Forms for added-in properties will be automatically generated once the form is reloaded and your alter-info adds in the properties.

An similar example working the same way is the existing 'entity_create' action.

acrazyanimal’s picture

great thanks for the input all. I should actually start working on this tomorrow.

acrazyanimal’s picture

@fago: is there a simple way that I can make a parameter (an array or list) that is displayed as a series of checkboxes? That is the roadblock that I am running into at the moment. I'm just not sure how to display the field options.

fago’s picture

You can define a list-parameter using an options list. I think it's going to be a multiple-select by default though. Still you can alter it using the form_alter callback.

acrazyanimal’s picture

Right on, that seems to work. I'll see where I can get from here.

acrazyanimal’s picture

Status:Needs review» Active
StatusFileSize
new8.02 KB
FAILED: [[SimpleTest]]: [MySQL] 250 pass(es), 0 fail(s), and 2 exception(s).
[ View ]

Ok here is my initial patch against the latest 7.x-2.x dev branch in git. It works well from what I've tested, but haven't tested in enough scenarios to be certain. Hoping the community will help out. The new action is called 'update entity' and I didn't bother overriding the property selection as checkboxes, because I rather like the select box as it is.

Areas of concern:

1. Not sure if the entity is validated for me or not to make sure we are infact dealing with a proper entity before updating. I think it is, but am relying on ->applyDataSelector to determine this.
2. Not sure if I should check access for particular fields before allowing them to be changed? I am most certainly not doing this at the moment.
3. I disabled ajax from the entity selection widget as it didn't seem to work and consequently not everything appears in the first step or two automatically without pressing a button. Not really an issue, but thought I'd mention it in case you know a work around.

Note: you can go backwards and ultimately change the entity you're updating, but you must first deselect all properties from the listbox, choose your new entity to update, and click the reload button. Consequence of 3rd area of concern above.

In the process of adding this functionality I noticed a few other issues that I'll post as separate issues and upload patches for.

cheers.

acrazyanimal’s picture

Status:Active» Needs review
acrazyanimal’s picture

Status:Active» Needs review

Anyone else what to help test out this baby?

AndrzejG’s picture

Maybe in a few days. Or rather nights..

Status:Needs review» Needs work

The last submitted patch, rules-update-entity-action-1421368-15.patch, failed testing.

acrazyanimal’s picture

Status:Needs work» Needs review
StatusFileSize
new8.4 KB
FAILED: [[SimpleTest]]: [MySQL] 249 pass(es), 1 fail(s), and 0 exception(s).
[ View ]

Looks like I forgot to add a condition to the access callback for the rule. Its in there now and should pass the tests.

fago’s picture

Status:Needs review» Needs work

Thanks! Here is a review:

1. Not sure if the entity is validated for me or not to make sure we are infact dealing with a proper entity before updating. I think it is, but am relying on ->applyDataSelector to determine this.

It's fine to rely upon really getting an entity.

2. Not sure if I should check access for particular fields before allowing them to be changed? I am most certainly not doing this at the moment.

We should implement an _access callback to incorporate those checks, just as the data_set action does.

+++ b/modules/entity.eval.inc
@@ -138,6 +138,58 @@ function rules_action_entity_delete($wrapper, $settings, $state, $element) {
+    foreach ($element->pluginParameterInfo() as $name => $info) {
+      if (($name != 'data') && ($name != 'props')) {
+        try {

Let's better just read our "properties" variable.

+++ b/modules/entity.eval.inc
@@ -138,6 +138,58 @@ function rules_action_entity_delete($wrapper, $settings, $state, $element) {
+      $element_info['parameter']['props'] = array (
+        'type' => 'list<text>',
+        'label' => t('@label\'s parameter(s) to update', array('@label' => ($label) ? $label : 'Entity')),
+        //'label' => t('test'),
+        'description' => t('Check the properties that you would like to update for this entity.'),
+        'options list' => 'rules_action_entity_update_properties_list_options_list',
+      );

Let's come up with a better parameter name. What about just "properties" ? Also, let's fix the label to talk about modifying properties not parameters.

Then, we should use the type 'list' and just define the parameter as usually in hook_rules_action_info() with a constant label like just "Properties".

+++ b/modules/entity.eval.inc
@@ -138,6 +138,58 @@ function rules_action_entity_delete($wrapper, $settings, $state, $element) {
+        if (isset($element->settings['props'][$name])) {
+          $childinfo += array('type' => 'text');

I think we should add a validation callback that checks that each selected property exists and is writable (has a 'setter callback' set).
That way Rules is going to show errors if a modified property goes away afterwards.

+++ b/modules/entity.rules.inc
@@ -162,6 +162,27 @@ function rules_entity_action_info() {
+  ¶
+  $return['entity_update'] = array(
+    'label' => t('Update entity'),

Let's call the action "entity_modify" and "Modify an entity". I think that should better communicate you can use the action for newly created entities too.

Also, there is some whitespace in the empty line.

+++ b/modules/entity.rules.inc
@@ -162,6 +162,27 @@ function rules_entity_action_info() {
+    'parameter' => array(
+      'data' => array(
+        'type' => 'entity',

'data' should be called 'entity' as that's the usual variable name for entities.

+++ b/modules/entity.rules.inc
@@ -162,6 +162,27 @@ function rules_entity_action_info() {
+        'description' => t('Specifies the entity, for which you would like to update field/parameter values.'),

Let's say "The entity which should be modified."

+++ b/modules/entity.rules.inc
@@ -269,6 +290,93 @@ function rules_entity_type_options($key = NULL) {
+    // The possible values of the "parameter" are those of the particular entity "property".
+    if (isset($wrapper->$property_name)) return $wrapper->$property_name->optionsList();

Take care of the coding style.

+++ b/modules/entity.rules.inc
@@ -269,6 +290,93 @@ function rules_entity_type_options($key = NULL) {
+  return $options;  ¶

Trailing whitespaces.

acrazyanimal’s picture

StatusFileSize
new9.78 KB
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]

Took me a while to get back to this, but here is an updated version with the changes you recommended fago. I added access checking to it, but I'd like to get your opinion on it. I had problems with the following at least with integration in the ECK module; which could very well just be an issue in the ECK module, but am wondering if other modules may have a similar issue if they may not necessarily use the entity_access hook.

/**
* Returns the options list of available properties for the chosen entity in entity_modify.
*/
function rules_action_entity_modify_properties_list_options_list(RulesAbstractPlugin $element, $param_name=null) {
  $options = array();
  if ($wrapper = $element->applyDataSelector($element->settings['entity:select'])) {
    foreach ($wrapper as $name => $child) {
      $childinfo = $child->info();
  $access = $child->access('edit');
      if ((FALSE !== $access) && !empty($childinfo['setter callback'])){
        $options[$name] = $childinfo['label'];
      }
    }
  }
  return $options;
}

The problem I saw with ECK is simply that $access is always false for all properties so the property list will be empty for all ECK defined entities. If I comment out (FALSE !== $access) && then all the properties show up for the ECK entities. However, it seemed to work flawlessly for user and node entities.

Anyway it would be good to get some further feedback. Also, I'm reconsidering the dropdown for properties and making them individual checkboxes since the ajax is somewhat annoying and disorienting with a dropdown.

cheers.

acrazyanimal’s picture

Status:Needs work» Needs review
Nick Fedchik’s picture

I use VBO operation "Modify entity values (views_bulk_operations_modify_action)".
Well, it's possible to mass add references from some entities (nodes) to one entity.
But impossible to do mass unlink operation.
I hope this patch helps to solve such tasks?
Is it any progress?

acrazyanimal’s picture

@Nick Fedchik: The intention of this new 'modify entity' action is not to mass update lots of entities at the same time, but to be able to modify multiple fields/properties on a single entity rather then having to update them individually using multiple 'set data value' actions. However, you can already use rules to mass update lots of entities in many different ways. You could use the load entity by field value action to load a list of entities and then add a loop to the rule to loop over the entities and perform whatever actions you want on them. In your case load all the entities that are linked to a specific other entity, loop over them, and either use the 'data set value' or this new 'modify entity' action to change the 'link' ... or unlink it as you say. You could also use VBO to pass entities to a rules component that takes in the entities you want to modify and performs the necessary actions on them individually.

Please note that this is not the issue, or queue, to be discussing your particular problem with VBO.

cheers.

bojanz’s picture

Plus, there's even an open VBO issue for what Nick is describing: #1421656: Extend the "modify entity values" action to add a delete mode for multiple-value properties and fields. So, anyone interested in that can go there and make it happen.

Nick Fedchik’s picture

Sorry that I miss by my question and thanks for answers - I take a look on that solutions.

acrazyanimal’s picture

StatusFileSize
new9.85 KB
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]

Ok I think I have the access stuff nailed down now. This patch includes some changes that assume its okay to modify entities and entity properties that do not have an 'access callback' defined.

acrazyanimal’s picture

Just tested a little more and it seems with this newer version that includes any updates in the last couple months for rules, I'm now getting an ajax error where I never had one before.

So it seems the form api cannot find the rules_action_type_form_submit_rebuild callback function anymore. It works for other actions using this function like 'schedule' action in rules scheduler, but not for the modify entity action. It fails after you select an entity to update and click continue. I have been racking my brain all day but cannot for the life of me figure out how to ensure the callback function can be found.

Anyone have suggestions to where I'm going wrong?

After applying the latest patch above you can find the submit callback (rules_action_type_form_submit_rebuild) for 'modify entity' on line 333. Here is a snippet of the ajax error:

An AJAX HTTP error occurred.
HTTP Result Code: 200
Debugging information follows.
Path: /system/ajax
StatusText: OK
ResponseText:
( ! ) Fatal error: Call to undefined function rules_action_type_form_submit_rebuild() in /home/dm7/includes/form.inc on line 1432
Call Stack
#TimeMemoryFunctionLocation
10.0004192328{main}(  )../index.php:0
20.438865771800menu_execute_active_handler( $path = ???, $deliver = ??? )../index.php:21
30.438965771800call_user_func_array
( ???, ??? )../menu.inc:517
40.438965771800ajax_form_callback(  )../menu.inc:517
50.456169093272drupal_process_form( $form_id = ???, $form = ???, $form_state = ??? )../ajax.inc:370
60.495777016872form_execute_handlers( $type = ???, $form = ???, $form_state = ??? )../form.inc:846
acrazyanimal’s picture

I'm still having this issue and stuck on it. Hmm, maybe I'll try catching someone on IRC.

acrazyanimal’s picture

Ok so I tried rebuilding the registry for the site and all works perfectly fine. Weird. I have no idea what stopped it from working, but it seems to be just fine.

Anyway if anyone gets around to it, its all ready for review again.

mitchell’s picture

Title:Add a "Modify entity" action» Action: "Modify an entity"
Priority:Normal» Major
Status:Needs review» Needs work

I tested #28 and can't get past Fatal error: Call to undefined function rules_action_type_form_submit_rebuild() in .../includes/form.inc on line 1443 , either. So, changing this back to 'needs work'.
--

Marked #1721298: Action "Attach Fields" as a duplicate. The intended use case of #1472752: Add an "entity is of bundle" condition might also be covered here. Note from #1240364: Create a new entity: Ease populating custom fields, an important use case to cover in the docs will be loading entities from reference fields and modifying them. Also, raising priority based on the number of duplicate issues.

mitchell’s picture

> form_alter & rebuild
See, #1681510: Add plugin factory to UI!

krlucas’s picture

Component:Rules Engine» Rules Core

I applied the patch in #28 and also had the problem with "Fatal error: Call to undefined function rules_action_type_form_submit_rebuild() in .../includes/form.inc on line 1443", even after rebuilding the registry. However I was able to get around the issue by changing:
+ '#submit' => array('rules_action_type_form_submit_rebuild'),
to
+ '#submit' => array('rules_form_submit_rebuild'),

rules_action_type_form_submit_rebuild is in data.eval.inc, not entity.*.inc so it would make sense (to me) that it's not in scope. It just calls rules_form_submit_rebuild then sets $form_state['parameter_mode'] = array(); I don't know if that's needed for this form?

After fixing that I created a Rules component using WSClient module to retrieve a data structure, create a new entity (a node), and modify the entity.

When I tried to assign a property of the data structure that was (in this case) empty to a property of the entity, the whole Entity Modify action failed with a Rules Exception 'The variable or parameter %name is empty.' When I used a Set data action with the empty data property, I get no error.

I tried with my own custom data structure (in a custom module) and also had the same problem when trying to assign NULL values. I'm not sure if this is a problem with how I/WSClient are initializing our data structures or if this patch should prevent an exception in this case.

I'd love help continue with this patch but need a bit of guidance.

krlucas’s picture

Status:Needs work» Needs review
StatusFileSize
new9.83 KB
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]

Here's the patch from #28 with the minor change I mention in #34.

krlucas’s picture

StatusFileSize
new9.51 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch rules-modify-entity-action-1421368-36.patch. Unable to apply patch. See the log in the details link for more information.
[ View ]

I added an "allow null" to the property info alter callback for the action and that did the trick. I've been using this all day on a project for mapping and importing stuff and so far so good.

Right now, my only complaint is the UI is unwieldy especially with entities with a lot of fields. My current thought would be to get rid of the multi-select in favor of an "Add Another" and "Remove" field buttons.

acrazyanimal’s picture

Title:Action: "Modify an entity"» Action: "Modify an entity" [PATCH]
StatusFileSize
new11.19 KB
PASSED: [[SimpleTest]]: [MySQL] 327 pass(es).
[ View ]

Ok I think that I have my final version of this patch ready to be committed. Here are the changes that I have made to make it better and work properly:

  • For the issue I had above in #29 I had applied the same fix as krlucas.
  • I've also improved the user friendliness of the property selection by converting the select box into a three column list of property chekcboxes. Makes it so much easier to use! If anyone has applied any of the previous patches in this thread its fine to update with this patch. It won't mess up your existing rules that use this action.
  • I also got rid of the option to use the data selection mode for the list of properties because that doesn't make sense anyway.
  • I've found that data selection mode for each property is usually what I use so I made that default for all property parameters.
  • Each property parameter can also now accept null values. If we don't have this, the action just fails and you get failed rule messages in the site log

.

FYI: The patch is also git aware. To commit git am can be used.

krlucas’s picture

I have applied the patch and it's working well. The UI improvements are great.

However, some fields have "sub-fields". For instance Addressfield which is required by Drupal Commerce. You can't assign the individual address components using "Modify Entity" the way you can with "Set a Data Value".

acrazyanimal’s picture

@krlucas: Yes you could assign an address field to an address field, but not its sub components. Just like you wouldn't be able to set individual members of a list field. You would only be able to set a list to a list. Thats just the way these things work. In both those cases you would do a set data value like you mentioned or add a value to a list.

krlucas’s picture

@acrazyanimal I understand what you are saying about assigning lists to lists but this seems a little different to me. I'm specifically talking about Fields that describe their underlying property info through the API.

When I use "set a data value", and use the data selector input with an AddressField it reveals:
billing-profile:address:country
or
billing-profile:address:thoroughfare
or
billing-profile:address:[whatever]
as assign-able options.

Unlike a list type which is a numerically indexed collection, AddressField has named components and somehow has provided the data selector in Rules with enough information to show the components.

If I chose "Modify an Entity", chose "billing-profile", why couldn't
address:country
address:thoroughfare
address:whatever
be available as checkboxes in your new UI? I don't even know if you can create an entity-less field data structure with Rules so just having "address" might not be helpful.

Not to be too obsessed with Addressfield or complex fields in general--it could be a future enhancement. I'm willing to mark as tested and reviewed if you think handling complex Fields is outside the scope of this patch.

krlucas’s picture

Status:Needs review» Needs work

In #37 the throw of RulesEvaluationException in rules_action_entity_modify references $settings['entity:select'] which is not defined in that context.

acrazyanimal’s picture

@krlucas: can you provide a little more feedback as to how you produced the exception you're seeing? I don't fully understand what you mean by:

$settings['entity:select'] which is not defined in that context.

What context? Or is that the error message you see?

Regardless if you could explain how to reproduce the error it would really help. thx.

Also, as for your feedback in #40, I understand what you're saying and I agree that would be totally awesome, but perhaps would be best suited for a later enhancement. It would require really reworking the UI and would make it super complex. As far as I know you cannot create an entity-less field but you could at least copy the value(s) from one entity to another. That is where I have found it most useful.

For a multi-value field like an address field I would think you should at least be able to switch to direct input method to fill out the individual fields? no?

acrazyanimal’s picture

Hmmm ... just checked out modifying an entity with an address field and no, you cannot use the direct data input method. The option doesn't even show up. Too bad. :(

krlucas’s picture

@acrazyanimal sorry for being vague.

On line 153 of the patched version of entity.eval.inc the variable $settings is referenced but is never defined in the function:

throw new RulesEvaluationException('Unable to modify the "@label" property for "@selector": ' . $e->getMessage(), array('@label' => $label, '@selector' => $settings['entity:select']));

This results in unhelpful exception messages like 'Unable to modify the "whatever" property for "": '.

Regarding multi-columned fields, I don't think the UI would change much at all. Just instead of having one checkbox for an "field_my_addressfield" instance you'd have a checkbox for field_my_addressfield:country, field_my_addressfield:city, field_my_addressfield:state, etc... But, anyway, better to get this RTBC first.

acrazyanimal’s picture

Status:Needs work» Needs review
StatusFileSize
new11.23 KB
PASSED: [[SimpleTest]]: [MySQL] 329 pass(es).
[ View ]

Found another issue with the checkboxes wanting a default value. Fixed that an what @krlucas mentions in 44.

rudy2342’s picture

rudy2342’s picture

Issue summary:View changes

Forgot to remove some pasted in text.

SocialNicheGuru’s picture

Issue summary:View changes

this seems, well, brilliant.
can I export the "modify entity" action as part of a feature?