i'm about to port views_send and look for the best way to integrate the legacy action code.
README tells me i can use
1) hook_action_info
2) hook_node_operations / hook_user_operations
3) hook_rules_action_info

legacy code uses 1) but as i can see i get as action input
* $object
* $context

in my use case i join a node (which i receive in $object, alright) with some user info (which i dont see how to get).

how do i get the fields of my view? is one of the other interfaces a better choice?

tia! and after all, reloaded rocks!

Comments

geek-merlin’s picture

Title: get fields from "reloaded" vbo action » get fields (joint across several entities) in "reloaded" vbo action
bojanz’s picture

Doesn't matter whether you use 1) or 3).
I prefer Rules 2 because of more flexibility and reusability, but Drupal core actions are simpler and there's no reason to avoid them if they do the job for you.

In any case, you get the same data in both methods. Your action is invoked once for each selected entity, and that's what it gets ($entity, not $object).
So if you create a view of users, once VBO fires, it will call your action with each user $entity (+ the info you got through the config form, in your case the message).
So you can $entity->mail quite happily.
The only downside to all this is that you need to know the exact field that has the email address. If it's a random $node field, you need to know its name...

You don't get the view or the view row. If you need additional info not present on the entity, you have to load it yourself.

I'm a bit tired so I don't know how clear I am, leaving the issue open so feel free to ask for clarification.

geek-merlin’s picture

>You don't get the view or the view row.
> If you need additional info not present on the entity, you have to load it yourself.
that's the point for me: how?
in the end i need the view row.
how do i get info about the additional fields that i need to load them?
is there a code snippet for that anywhere?

bojanz’s picture

You get the selected entity (user or node or whatever). You have the entire drupal api at your disposal.
If the VBO is on nodes, then $entity is a node. Do entity_load('user', array($entity->uid)) to load the author(s). Or query the database directly for non-entities.

Can't help you more without a concrete example. In general, if your module is about mass emailing, can't you make VBO on the users table, and in your action use $entity->mail to get the address for each row?

geek-merlin’s picture

Title: get fields (joint across several entities) in "reloaded" vbo action » vbo action cannot get all $views->result anymore

i just grokked the new code a bit and think i get the working:

there are 2 kinds of "views result classes" (i'm quite sure this is not the correct wording but you might get the point):
1) entity views - that spit out sets of entities (eg select format "unformatted list" where you cant choose fields)
2) row views - that spit out rows with fields you choose

with 2) row views you can join your view across tables

what i see in source and what you say means:
"you cannot use 2) anymore, you get the entities from the base table and have to get the rest yourself"
which for most use cases means "duplicate the view in your code"

live example:
select a list of invoice nodes and join them with some other table (user or profile) to get the email.

so the question is: ca we evolve the api so as to again get access to $view->result like it was?
otherwise modules like views_send have no workable upgrade path with vbo.

bojanz’s picture

You can use 2) row views just as before, you just get an entity loaded. It was a conscious design decision, and so was the decision not to pass any part of the view. It gets seriously heavy once you start storing everything for batch api and queues.

I don't see in your example why you absolutely need the row, so much that without it your module is useless.
As far as I've understood you only need the email address.
If you have a view of invoice nodes, and you are joining in users for the email address, then add User: Bulk operations to the view, and your action will get the user object with the email. Same for profiles (assuming you're using profile2 or some other way of having profiles as entities).

Passing the original row is possible and my decision is not set in stone, but as far as I can see, your use case doesn't require it, so I'm not yet convinced.

geek-merlin’s picture

why is the views result important?
the short answer i've given above: we need to paremetrize our action by selecting views fields.
if that info is not accessible in the action, i have to double the parametrization in my module.
in fact i would look for another solution or roll my own or fork or whatever.

so let's assume (simplified) my view needs 4 vields: name, email, subject, body.
in views i can choose those fields.
and if i change my schema (say, we introduce a invoice-email that comes from a company node connected with the user) i just change my view and dont need to bother in my action code if my fields come from 1 or 4 entities. (or even can be a math field)

in the end: if i cannot use views result i would have to code my own fieldbuilder (that views already has).
what this means to me is to stop upgrading that module, move away from vbo or patch or fork it.

bojanz’s picture

Title: vbo action cannot get all $views->result anymore » Pass the selected views row(s) to the action
Category: support » task

Threatening to fork a module if your wishes don't get fulfilled is rude at best and just makes me (or any other maintainer) want to "won't fix" the issue even though it has merit.

I asked for a convincing use case, providing "so let's assume (simplified) my view needs 4 vields: name, email, subject, body." would have been enough. The rest was just pure bad communication on your part.

So, _views_bulk_operations_execute() needs to be changed.
$params needs to include the selected rows (taken from $vbo->view->result). Also, the batch function needs to take in the row ids so that it knows what to take from $params.

I'm busy in the next 48h, feel free to provide a patch if it's more urgent than that.

geek-merlin’s picture

bojanz,

i'm a bit threatened by my tasks right now and what i meant by forking is "roll and maintain my private version" because that would have been the least pain to me.

so sorry for that unthoughtful communication of mine, you are completely right.

i've just made a patch like you said and will post it after some tests.

hansfn’s picture

@axel.rutz: I fear I have wasted a lot of time since you didn't announce that you started the porting of views_send to Drupal 7 in #1052040: Port Views Send to Drupal 7. Anyway, I have something working now - see that issue ... Take a look at my code and see if you can improve it (or use some of my code to solve your problems).

geek-merlin’s picture

short status update from me:
some stuff "exploded" in my project so i've been interrupted from this for quite some days.

@hansfn: thanks for the note, i'll look into it as soon as i come back to that.
for my part it looks as it won't be a simple port but aomething like a rewrite and i'm not sure if will be "the same" modul ein the end.

BenK’s picture

Subscribing

BenK’s picture

Subscribing

bojanz’s picture

Status: Active » Fixed

Committed.

You need to specify "pass rows" => TRUE in your hook_action_info(), and then you'll be able to use $context['rows'] (array of selected rows keyed by entity id) in your action function.
This was made optional because it has a performance impact while not being needed by most actions.

bojanz’s picture

Version: 7.x-3.x-dev » 6.x-1.x-dev
Status: Fixed » Patch (to be ported)

Just for the record, the commit is: http://drupalcode.org/project/views_bulk_operations.git/commitdiff/842e6...

I want infojunkie to examine this approach for 6.x-1.x, it would help with memory issues (like the ones mentioned in #869776: Batch API performance/memory Question/Suggestion).
As I said, most actions shouldn't need the rows, and those who need (like the send function) can say so for themselves (they are getting a small number of rows anyway).

webankit’s picture

Please also post this feature for D7

bojanz’s picture

This has already been committed to the D7 branch. It's now waiting to be ported to D6.

bojanz’s picture

Version: 6.x-1.x-dev » 7.x-3.x-dev
Status: Patch (to be ported) » Closed (fixed)

The described functionality has changed a bit in the meantime (in 7.x-3.x).

I'm gonna close this issue because it doesn't look like 6.x-1.x will be getting any major work done to it, and not passing rows by default, while a good idea, is a massive BC break.

nagiek’s picture

Status: Closed (fixed) » Needs work

Sorry to open a closed issue, but this new feature could use some documentation.

bojanz’s picture

The README has this:

CONTEXT
-------
By default (for performance reasons), VBO doesn't pass the selected views rows
to actions.

However, when a Drupal core action declares 'pass rows' => TRUE in its
definition (hook_action_info()), VBO does pass the full rows through the $context array.
So $context['rows'] has an array of selected rows in the form of $row_index => $views_row.
If the action is using aggregation, $context['rows'] will include all selected
rows. Otherwise, only the current row (that is being operated on) will be included.

Using this feature has a memory cost and is not recommended for actions
that process a big number of rows. Also, if all rows on all pages are selected,
only the rows from the first page will be passed through. This is a known issue.

Right now there is no way for a Rules 2 component to receive context, but there
are plans to change that.

Is it not enough?

I am planning to move the docs to drupal.org, but seem to be having an issue where I can't edit the existing VBO docs page.
EDIT: It was a permissions issue, now fixed. So I should be able to put the whole README online.

nagiek’s picture

Status: Needs work » Closed (fixed)

sounds good to me!

harryohtl’s picture

Issue summary: View changes
Issue tags: -

First off, thank you very much for the wonderful VBO module and all the useful comments here.
Second, please forgive a possibly amateurish question, but I've spent a lot of time trying to figure this out and have run out of ideas.

I have:

  1. Created an custom postgres table and identified it as an entity in Drupal
  2. Managed to create a view and have my fields (table columns) accessible/usable in the Views UI
  3. Created a very simple action which is not quite doing what i need it to

Here is the code for the custom action:

<?php
/**
 * Implements hook_action_info().
 */
function mbas_dispatch_action_info() {
  return array(
    'send_items_action' => array(
      'type' => 'entity',
      'label' => t('Dispatch items'),
      'behavior' => array('changes_property'),
      'configurable' => TRUE,
      'vbo_configurable' => FALSE,
      'pass rows' => TRUE,
      'triggers' => array('any'),
      'aggregate' => TRUE
    ),
  );
}


function send_items_action_form(&$entity, $context) {
  sdpm($entity);
  sdpm($context);
  sdpm($context['rows']);
  sdpm($context['entityType'] );
  $form = array();
  return $form;
}

?>

The form is not to do anything at the moment, but just show me what information I've managed to send from the view. I have obviously not understood the proper usage of "'pass rows' => TRUE," since I expected my information about my selected rows in the view to be in $entity or $context, but can't make sense of what is in these structures.

Your help would be greatly appreciated.

H

Edit: I just edited the code to reflect exactly what I'm running and here is one more error message when I run the above: Notice: Undefined index: rows in send_items_action_form()

mpp’s picture

This seems to be available for Drupal 8 in https://www.drupal.org/node/2884847