Executing a View with a Rule

Events happening in the community are now at Drupal community events on www.drupal.org.
jcicolani's picture

In short: I need to execute a view, or series of views, with a rule or rule set (or trigger).

In not nearly so short: Use Case - An on-line workshop site utilizing OG for classrooms (there may be other solutions, but OG encapsulates all the functionality the client needs). Students will purchase enrollments into workshops using sign-up and Ubercart. I have two views. The first queries users with a sign-up for workshops starting the next day and, using a php field in the view which calls og_enroll_user, adds them to the group. The second queries users in a workshop that ended the day before and removes them from the group. Another will remove all student contributed content from the group.

Problem - I need a solution to execute the views systematically during cron maintenance. I am preparing to write a module or custom trigger to do it, but would rather use existing functionality if it exists.

Any direction would be appreciated.

Thanks

Comments

Consider switching to VBO

itangalo's picture

It seems a bit risky to have actions carried out just by calling a view – I would consider using Views Bulk Operations instead (if possible). (VBO can call rule sets that you make, if the rule set has exactly one argument and that argument matches the type of the view.)

I wrote a blog post some time ago explaining how to call VBO from Rules. (Sorry for linking instead of explaining.)

Having that said, here's the code for executing a view with PHP:

<?php
$view
= views_get_view($view_name);
$view->set_display($display_name);
$view->set_arguments($view_arguments);
$view->execute();
?>

Cheers!
//Johan Falk, NodeOne, Sweden

A little more direction?

jcicolani's picture

Help me out a little, because I'm having some trouble wrapping my head around how VBO works. How would you go about using VBO in this situation?

View01 Identifies users with a sign-up for a workshop session starting the next day and the appropriate OG for the workshop they have signed up for. The view needs to be run nightly (or when cron maintenance is run) and will return users signed up for one (or more) of several workshops and the node ID of the workshop. Currently, uses a PHP custom field to pass the user and the node ID of OG to og_enroll_user.

View02 Identifies users enrolled in the OG of a workshop which ended the day before. Like View01, this view will be run nightly (or at cron maintenance) and will return the users enrolled in the group and the node ID of the group. It then uses a PHP custom field to pass the user and the node ID to og_delete_subscription which removes them from the group.

View03 (yet to be created) will identifiy the contributed content in a workshop OG from users who are not the instructor and remove it (the exact criteria is still being worked on... it will likely be content from users with role 'student' and not the specified 'instructor' for the workshop). It, too, will run nightly and look for workshops which ended the previous day.

The views need to run without user input. So, obviously, the VBO command will be executed on each user in the return result. How would I pass the NID of the OG as an argument?

Thanks

Some thoughts

itangalo's picture

The way I normally would go about the tasks you describe is the following:

  1. Create a rule set that takes a user (and only a user) as an argument. The rule set would then have to somehow find the corresponding OG and then do whatever actions should be done.
  2. Create a user View that identifies all the users that should be processed.
  3. Turn the View into a VBO, and have it execute the rule set in (1).
  4. Create a rule that triggers on cron run, and somehow checks whether it is time to process the users. If so, it programmatically calls the VBO.

In this case, step 1 will most likely be a problem. The support for rule sets in VBO requires that the set has exactly one argument, but in this case you need both the user and the OG. If there's a quick and easy way to "load OG for user" or something like that in Rules, everything is fine – but most likely a different strategy will be necessary.

One way of solving that dilemma is to add a field to (say) a user profile, which (somehow) is populated with the relevant OG on beforehand. If that works, "load the OG for user" will be a quick match for Rules.

In this case you could also consider using Rules and Views Integration module. I used it when it was called Rules Executor a few months ago, and it would give you two advantages:
* It can call rule sets with as many arguments as you like.
* It can be set to be executed once per day without any hazzle.

The downside is that the module is still in dev.

I hope this can make it easier to find a way forward!
//Johan Falk, NodeOne, Sweden

Unfortunate news

jcicolani's picture

Thanks for the help. It sounds like I'm doing something completely out in left field (again). Which sucks, because this is a very straight forward operation in the enterprise database application world... at a specified time interval (time based database trigger) identify a group of subjects (SQL query) and execute a specific action on each (SQL function or sub-query).

So, that leaves me with two option...

1) write my own module/action/trigger
2) depend on a contributed module currently in dev (rules views)

Bummer, because I'm not much of a coder (yet) and I'd really rather not use a dev module on a prod site.

Thanks again.

Mini-modules

jefkin's picture

Hi Jeff,

I think this sounds like you need a mini-module. By mini-module I mean a simple little module that does just the thing you need. Nothing more, nothing less. Some times we're tempted to write the I_can_do_it_all module, even before we start, and this can make module writing daunting. I often focus my team on working on the problem at hand. I'd rather have 50 tiny modules that each do one simple thing, but do it well, then a single do it all function, with fingers in every pie, as it were.

You can, with a well set-up system, execute your jobs at any time if they're defined under hook_cron(). (There are other resources about using crontab or other systems to get your hook_cron() functions firing at the right time, I wont focus on that.) I usually have my system hitting the drupal cron link 4-6 times a day, and use a bit of logic in my hook_cron() functions with a call to strftime() to specify which tasks need to be run.

Example:
Let's say our system cron hits the drupal cron link at: 1:00am, 7:00am, 1:00pm, 7:00pm.

Then our demo_module.module might have a hook_cron() that says:

from file: demo_module.module

<?php
/*
** demo_module_cron(): hook_cron() implementation that will do our time-of-day specific
**                     work when needed.
*/
function demo_module_cron()
{
 
$hour = strftime("%H");

 
/*
  ** this could be a switch/case, or some other control structure, depending on your
  ** needs, and the specifics of your problem.
  */
 
if ((0 < $hour) && (2 > $hour)) // 1:00am do  "mid-night" work.
 
{
   
demo_module_late_night();
  }
  elseif ((
6 < $hour) && (8 > $hour)) // 7:00am do the "morning" work.
 
{
   
demo_module_morning();
  }
  elseif ((
12 < $hour) && (14 > $hour)) // 1:00pm do "mid-day" work.
 
{
   
demo_module_midday();
  }
  elseif ((
18 < $hour) && (20 > $hour)) // 7:00pm do the "evening" work.
 
{
   
demo_module_evening();
  }
}
?>

At this point you can stick your sql queries in those time of day functions.

If you're already familiar with PHP coding (to do your PHP fields), I think you'll find working with a straight functional flow from the cron job will be much easier to both write and maintain. Of course, I tell you this as a serious coder, and YMMV, but I avoid even using CCK because it rarely does exactly what I need, and I can define it much better by rolling my own.

Of course as a mini module, you may only have one of those time code blocks in your hook_cron(), (that's how I prefer it).

Good luck though.

Jeff

Thanks!

Renee S's picture

Hey Jeff, thanks for the example, it kicked my brain in exactly the right direction :)