Jun 30 2011
Jun 30

I've been a lazy adopter of Drupal 7. I admit it, mea culpa, but I'll leave this discussion to another post. What happened in the mean time is that VBO for D7 languished for a year or so in a zombie state until it was rescued in early May by Bojan Živanović, bojanz on d.o. He started out by announcing a sandbox project containing his code, and a few days later, I was convinced that this was the way to go for VBO on D7. He agreed to become co-maintainer for VBO in charge of D7 - maybe unaware of what awaited him in terms of issue queue support!

Bojan made not one, but two radical changes to VBO, solving a long-standing issue and enhancing Views itself with a cool new feature. Let me explain:

  • VBO was initially designed by yours truly as a style plugin. It obviously worked, but the side effect was that a VBO could only be displayed as a table (implemented by the module itself), not as a grid, carousel, or any other crazy Views style. In hindsight, this was not the ideal choice since what was needed was only to add a checkbox to each row, which is really a field thing. That's what Bojan did: package the VBO functionality in a Views field handler instead of a style plugin.

  • To achieve this, Views core needed to be retrofitted with the ability to display forms during its own rendering. Again, Bojan built a proof of concept that was later submitted as a patch to Views and committed to Views 3 on both D6 and D7. Let's look at what this means for a Views developer:

There's an example Views 3 plugin for D6 that illustrates the idea of embedding form elements in a view. This example module provides a new field that exposes an HTML text input. The view automatically creates a multistep form whose first page contains all the text inputs (one for each row) and adds a "Save" button. The module also adds validation and submission functions. Here's the code:

<?php
// @file views_form_example.views.inc/**
* Implementation of hook_views_data_alter().
*/
function views_form_example_views_data_alter(&$data) {
 
$data['node']['views_form_example'] = array(
   
'title' => t('Views Form Example field'),
   
'help' => t('Demonstrates a form'),
   
'field' => array(
     
'handler' => 'views_form_example_handler_field',
    ),
  );
}
/**
* Implementation of hook_views_handlers().
*/
function views_form_example_views_handlers() {
  return array(
   
'info' => array(
     
'path' => drupal_get_path('module', 'views_form_example'),
    ),
   
'handlers' => array(
     
'views_form_example_handler_field' => array(
       
'parent' => 'views_handler_field',
      ),
    ),
  );
}
?>

Nothing new here, just a declaration of our field handler.

<?php
// @file views_form_example_handler_field.incclass views_form_example_handler_field extends views_handler_field {
  function
query() {}  function render($values) {
    return
'<!--form-item-' . $this->options['id'] . '--' . $this->view->row_index . '-->';
  }  function
views_form(&$form, &$form_state) {
   
// The view is empty, abort.
   
if (empty($this->view->result)) {
      return;
    }   
$field_name = $this->options['id'];
   
$form[$field_name] = array(
     
'#tree' => TRUE,
    );
   
// At this point, the query has already been run, so we can access the results
   
foreach ($this->view->result as $row_id => $row) {
     
$form[$field_name][$row_id] = array(
       
'#type' => 'textfield',
       
'#title' => t('Your name'),
       
'#default_value' => '',
      );
    }
  }  function
views_form_validate($form, &$form_state) {
   
$field_name = $this->options['id'];
    foreach (
$form_state['values'][$field_name] as $row_id => $value) {
      if (
$value == 'Bojan') {
       
form_set_error($field_name . '][' . $row_id, "You can't be named Bojan. That's my name.");
      }
    }
  }
}
?>

Things get a bit interesting here: The render() method return special syntax that instructs Views to expect a form element with the given identifier. Views then calls the views_form() method to allow the handler to create the form elements, making sure that the resulting identifiers match the ones returned by render. In the case of this example, the expected identified is obtained by concatenating the field identifier with the row index - because the form element's structure will generate these identifies via Form API. The handler also declares a form validation function.

Now for the module file itself:

<?php
// @file views_form_example.module/**
* Implementation of hook_views_api().
*/
function views_form_example_views_api() {
  return array(
   
'api' => 3,
  );
}
/**
* Gets our field if it exists on the passed-in view.
*
* @return
*  The field object if found. Otherwise, FALSE.
*/
function views_form_example_get_field($view) {
  foreach (
$view->field as $field_name => $field) {
    if (
is_a($field, 'views_form_example_handler_field')) {
     
// Add in the view object for convenience.
     
$field->view = $view;
      return
$field;
    }
  }
  return
FALSE;
}
/**
* Confirmation step of the views multistep form.
*/
function views_form_example_confirmation_form($form, $form_state, $view, $output) {
 
$form = confirm_form($form,
   
t('Are you sure you want to give your name to total strangers?'),
    array(
'path' => $_GET['q'], 'query' => $view->get_exposed_input())
  );  return
$form;
}
/**
* Implementation of hook_views_form_submit().
*/
function views_form_example_views_form_submit($form, &$form_state) {
 
$field = views_form_example_get_field($form['#parameters'][2]);
  if (!
$field) {
    return;
  } 
// Advance to the confirmation form.
 
if ($form_state['storage']['step'] == 'views_form_views_form') {
   
$form_state['storage']['step'] = 'views_form_example_confirmation_form';
  }
  elseif (
$form_state['storage']['step'] == 'views_form_example_confirmation_form') {
   
drupal_set_message('We have a winner!');
   
drupal_goto($_GET['q']);
  }
}
?>

The interesting function here is views_form_example_views_form_submit() which gets called, not surprisingly, upon form submission. It finds the example field (the view object is passed to the $form structure) and then decides on the next step, like any multistep form handler. The difference is that the step name is actually the form function for the given step, which in our case is the confirmation form views_form_example_confirmation_form.

These changes made to Views are a generalization of what VBO did in D6. The fact that they were included in Views means that other modules will now be able to create specialized views forms and act upon them. In addition to VBO for D7, Drupal Commerce is also using those innovations.

Kudos to Bojan for his great work on VBO and Views. With his contribution, I am sure that VBO will rock even more on D7!

Mar 23 2011
Mar 23

DrupalCon is a Mecca for thousands of companies and individuals that call the Drupal community home and, naturally, several of the Larks attended DrupalCon Chicago earlier this month.

We’re very involved in our local and global professional communities and we participated at DrupalCon Chicago on several levels, from volunteering to organizing to presenting.

Sessions and BoFs (birds of a feather sessions)

Rain Breaw, who heads up our Drupal training program, presented to a filled auditorium on Views Demystified, a Drupal 7 update to her immensely popular session from DrupalCamp LA and DrupalCon San Francisco. Rain was also a DrupalCon volunteer and you may have seen her at conference registration.

Also at the conference was our Director of Business Development, Cary Gordon. Cary is a Board Member of the Drupal Association, the organization dedicated to Drupal’s funding, promotion and infrastructure, and he has been working to help build the Association’s professional events team. You may have seen Cary at the Library BoFs (I and II), the Domain Access BoF and several of the Core Conversations sessions.

As for myself, I co-presented on Building Successful Local Communities: Insights and Best Practices. I also participated in the DrupalCamp Organizing Round Table, where I shared how the Los Angeles Drupal community, already one of the largest Drupal user groups in the world, is dealing with the growing pains of nearly doubling in size in less than a year.

Drupal Fit: Drupal’s fitness movement and support group

For fun, I participated with dozens of others in the Drupal Fit BoF that ran throughout the entire conference. Drupal and fitness might sound like an unusual combination, but as Dries Buytaert, Drupal’s creator and project lead, once told me, “We want the Drupal community to be fit so that we make better open source software.”

During the conference, I recorded several new Drupal Fit interviews that will shine the spotlight on members of the community who are focused on getting and staying fit.

Looking to the future

DrupalCon is one of our favorite events and DrupalCon Chicago was no different. This time, DrupalCon felt like another turning point for the Drupal community. As Rudyard Kipling once said, “I have struck a city — a real city — and they call it Chicago,” and DrupalCon Chicago has without a doubt left a similar impression on everyone who attended and exhibited.

See you at the next DrupalCon at DrupalCon London!

Mar 09 2011
Mar 09

I gave my "Views for hackers" talk at DrupalCon Chicago yesterday. This was definitely the biggest attendance I've ever had in my short experience as a speaker! Thanks everyone for attending and for the great questions. Please rate it at the DrupalCon site, this will help me improve it. Thanks!

Here are the slides as uploaded to SlideShare:

AttachmentSize 191.42 KB 272.33 KB
Jan 12 2010
Jan 12

This page holds links to documentation about the module “heartbeat” for drupal 6. From here you will find how to install the module, how to use it and how to implement its hooks.
Heartbeat can be used with the rules module. Rules allows other modules to describe default rules events and actions, and that’s what heartbeat does. The rules as well as the messages you build are exportable into defaults. Developers can of course use an api function to log on custom criteria.
After installing, a couple of heartbeat activity messages (and default rules are activated). Add some content, change your profile or reply on some content, messages will be logged immediately. You can use the blocks and pages to view the result. With the heartbeat views submodule, you have a little more control but it is not that convenient all the time. I recommend the built-in blocks and pages.

Before you start using heartbeat

You must be aware that there are two interfaces you will be dealing with, when setting up your heartbeat. You will learn here about how to compose messages and set features to them, but you will have to learn how rules work.
You can always try it out the trial-and-error way. Suites me most of the time :-).

Heartbeat messages

Heartbeat messages are custom made messages that serve as template. When heartbeat activity gets logged, it is always linked to a heartbeat message. Depending on how you configured a message, the result messages go through a merging and grouping mechanism to (re)build the messages that seem related.
E.g. Stalski posted page1, page2 and page3.
For this to work properly as you planned, you have to think a bit about how you will group your variables. You group by user (E.g. !username) to summarize nodes (E.g. !title).

Tip: You can use html in your messages if you want to wrap something with a css class to give a link another colour for instance.

Dumb logger, smart viewer

All heartbeat does is log all we want it to, for each available language in the site. You’ ll see that you can log message activity as long as you configured a heartbeat message to link it to this activity stream (see $message_id). So what i mean with dumb logger is the fact that there are no restrictions on the logging itself. It is the display that determines what needs to be fetched and shown.
There are two ways on how to log something to the database table heartbeat_activity:
1/ use the api function

  1. /**

  2.  * API function to log a message from custom code

  3.  *

  4.  * @param string $message_id

  5.  *   Id of the message that is known in the message

  6.  * @param integer $uid

  7.  *   Actor or user performing the activity

  8.  * @param integer $uid_target [optional]

  9.  *   user id of the target user if present. Target users can be an addresse or a

  10.  *   user relation transaction with the actor $uid

  11.  * @param integer $nid [optional]

  12.  *   Node id for content (for context node)

  13.  * @param integer $nid_target [optional]

  14.  *   Node id for content that is related to other content

  15.  * @param array $variables [optional]

  16.  *   Variables can be used if you used them in the used message. Take care to use

  17.  *   the @-sign for words that are prefix with the question mark sign in the messages

  18.  * @param integer $access

  19.  *   The access to restrict the message

  20.  */

  21. function heartbeat_api_log($message_id, $uid, $uid_target = 0, $nid = 0, $nid_target = 0, $variables = array(), $access = HEARTBEAT_PUBLIC_TO_ALL) {

  22.    

  23. }

2/ use a heartbeat action triggered by the rules event based system.

The screenshot shows a rules rule edit form. Choose an event, digg into the conditions and use the heartbeat user activity logger as action.
Customizing the action is basically nothing more than setting tokens to its variables. Instead of typing a message here, we choose a heartbeat message we defined earlier or that came as default. This will openup a textarea with prefilled variables from the original message. Same thing here, assign tokens to the variables, each line for another variable.
Save this and make sure the rule is active. Rules will do the rest and start logging on occurring events.

It is even possible to add your own tokens to build really nice heartbeat views. Like a gallery with image_fupload. I did this and the result will be maybe included later as image_fupload integration submodule, if there is request for it.

Heartbeat blocks

With this module come a couple of default blocks. The built sql for this depends mostly on the scope of users that performed the activity. Everyone , only your friends or only your own activity.
Here I need a little more work because this is not scalable at all. So let’s say it is on my todo list.
Another block in the heartbeat core is the flag message form. With this form, users can flag each other by chosing one of the existing flag messages to form messages like “user slaps other user in the face”. Again, build as many template flag messages you like.

Administer settings

Settings for heartbeat regulate the way things are logged and viewed.  Even a couple of template stuff.

Submodules

Heartbeat has integration for some other contributes that are important because they describe user activity on a drupal site. A person that becomes friends with another or decides to subscribe to some group or channel can be logged as heartbeat message.

Heartbeat rules

This module is the module that allows you to create heartbeats with UI only.

Shouts

A shout is something like twitter or facebook’s “what are you doing”. It comes with a form block you can place on your site and let people shout. The messages appear in the heartbeat messages.
Important as well is to mention that these shouts live in a separate table as well. One could decide to show the shouts in a separte way and build their views with views2.

Og activity

Organic groups is a module that has a lot of user interaction going on. At the hearbeat activity settings page, some extra settings are provided if the submodule is set to on. Organic group describes extra events and conditions that heartbeat can use and uses.

Friendlist activity

Friendlist implementation into heartbeat activity with a user-to-user interaction. By all means it is user activity. A extra default message and rule comes with this installation.

Features

  • Messages can be grouped together when activities happen more than once in a set timespan.
  • Messages contain variable names you can choose yourself
  • It’s possible to write your own tokens to build sofisticated messages
  • You can use the message_alter hook to filter messages. (Sometimes conflicts can occur when building exactly the same messages on more than one event with the group setting on)

This entry was posted on Tuesday, January 12th, 2010 at 11:36 pm and is filed under Drupal, Heartbeat. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web