Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Expose database fields to views in a custom drupal module

Parent Feed: 

Developers who wrote a custom node module in drupal will know that you always have to make a couple of choices at the start of a project. Will I write a custom node module or use CCK to generate a content module. Or when using views, you might ask yourself it is better to write your own view. Or could it be wiser to use it all and take the best of all things into your project. Once I have such questions, I hear a little voice in my head “Time to test and compare”.

The initial project

We want a system with shops, products and presentations where shops are categorized in shop regions.

Fair enough, let’s start and build a couple of cck node types (content types) . So go to cck > add content type and prepare shops, products and presentations. In this fictive example a shop will have products and the shop would like to show presentations at location, to show their products. We can use taxonomy “shop groups” to group the shops.
Now we can make some views like “latest presentations” or “shops list per region” and so on … . This works very nice for simple projects and i get the feeling cck and views is more than enough for this. Besides there is no faster framework or website system that achieves what Drupal does in only ten minutes. With cck you can add all kinds of fields and use them in the views under the “content” section. Customizable and unbelievably fast.

new request for proposal

The presentatons should be shown with a preview button in the list, that shows an flash movie slideshow with the prensentations and thus product images. After that we would like to clone a presentation if a new one is required that differs little from an existing one.

Damn, I’d say, why didnt I write that presentation custom in my own code so I could change whatever I want. Could we build a list of presentations with views that shows a preview button to load a movie and a clone button to clone a presentation? Is it then also possible to add code to clone a presentation and yet showing the clone button next to preview in “operations” of the views list.
The answer is brief and simple: ow yeah you can.
To add stuff to views that seems rather custom, we can use the hook_view_data hook to join tables and expose fields. This adds new features to views and that’s exactly what we want. In views/modules you can peek at the code how the fields are built for modules we know (node, content, taxonomy, user, …).

Implementation of hook_views_data

The function hook_views_data has no parameters and returns a data array of database tables and their fields. The only thing you need to know about the database schema for presentations is that it is linked with node, has a start date and has a xml field where generated xml is cached (with product entries). Let’s build the body of presentations_views_data.
As you will see, the fields can have handlers as well as sort and filter handlers. The handlers are class extensions. In drupal , OOP? Indeed, views2 is an incredidable module that is written in OOP.  merlinofchaos is a leading figure in how to code OOP for drupal in my opinion.

I printed the hook_views_data with the defined handler classes underneath. The comment helps to understand what is going on.

  1. function presentations_views_data() {

  2.   $data = array();

  3.   // Presentations table

  4.   $data[‘presentations ‘][‘table’][‘group’]  = t(‘Presentations’);

  5.   $data[‘presentations ‘][‘table’][‘base’] = array(

  6.     ‘field’ => ‘presentation_id’,

  7.     ‘title’ => t(‘Presentations’),

  8.     ‘help’ => t("Presentations are groups of products."),

  9.   );

  10.   // Join node with presentations on node id

  11.   $data[‘presentations’][‘table’][‘join’] = array(

  12.     ‘node’ => array(

  13.       ‘left_field’ => ‘nid’,

  14.       ‘field’ => ‘nid’,

  15.     ),

  16.   );

  17.   // FIELDS

  18.   // start_date field

  19.   $data[‘presentations’][’start_date’] = array(

  20.     // The item it appears as on the UI

  21.     ‘title’ => t(‘presentation play date’),

  22.     // The help that appears on the UI

  23.     ‘help’ => t(‘The date the preentation will start playing.’),

  24.     ‘field’ => array(

  25.        // Default views handler for field dates

  26.       ‘handler’ => ‘views_handler_field_date’,

  27.       ‘click sortable’ => TRUE,

  28.     ),

  29.     ’sort’ => array(

  30.       // Default views handler for sorting

  31.       ‘handler’ => ‘views_handler_sort_date’,

  32.     ),

  33.     ‘filter’ => array(

  34.       // Default views date filter handler

  35.       ‘handler’ => ‘views_handler_filter_date’,

  36.     ),

  37.   );

  38.   // Clone a presentation

  39.   $data[‘presentations’][‘clone_node’] = array(

  40.     ‘field’ => array(

  41.       ‘title’ => t(‘Clone’),

  42.       ‘help’ => t(‘Provide a link to clone a presentation.’),

  43.       ‘handler’ => ‘views_handler_field_presentations_link_clone’,

  44.     ),

  45.   );

  46.   // Link to peek/preview a presentation

  47.   $data[‘presentations’][‘preview_node’] = array(

  48.     ‘field’ => array(

  49.       ‘title’ => t(‘Preview’),

  50.       ‘help’ => t(‘Provide a simple link to open the presentation on javascript onclick event.’),

  51.       ‘handler’ => ‘views_handler_field_presentations_link_preview’,

  52.     ),

  53.   );

  54.   return $data;

  55. }

You can see that the array of start_date is composed with predefined handlers and there is nothing to it. There is a handler class for each database field type known in drupal. In my case, i wanted to add a simple link to a custom menu callback function that I wrote that cloned a existing presentation. And it would be nice to pop-up a javascript overlay box with a flash animation showing the presentation.
In the last two field arrays, I defined my own handlers : views_handler_field_presentations_link_clone and views_handler_field_presentations_link_preview.
Let’s take a look at the code for the class that handles the link to clone a presentation:

  1. /**

  2.  * Field handler to peek/preview a presentation

  3.  */

  4. class views_handler_field_presentations_link_preview extends views_handler_field_node_link {

  5.   function render($values) {

  6.     global $base_url;

  7.     // Load extra javascript

  8.     $site_url = $base_url.‘/sites/’.SITENAME.‘/files’;

  9.     drupal_add_js(‘var files_url = "’.$site_url.‘";var base_url = "’.$base_url.‘";’ , ‘inline’);

  10.     drupal_add_js(drupal_get_path(‘module’, ‘presentations’) . ‘/swfobject.js’);

  11.     drupal_add_js(drupal_get_path(‘module’, ‘presentations’) . ‘/simplemodal/js/jquery.simplemodal.js’);

  12.     drupal_add_css(drupal_get_path(‘module’, ‘presentations’) . ‘/simplemodal/css/basic.css’);

  13.     drupal_add_js(drupal_get_path(‘module’, ‘presentations’) . ‘/presentations.js’);

  14.     // ensure user has access to edit this node.

  15.     $node = new stdClass();

  16.     $node->nid = $values->{$this->aliases[‘nid’]};

  17.     $node->status = 1; // unpublished nodes ignore access control

  18.     $text = !empty($this->options[‘text’]) ? $this->options[‘text’] : t(‘Preview’);

  19.     $attribs = array(

  20.       ‘attributes’ => array(

  21.         ‘onclick’ => ‘javascript:presentations_peek($node->nid,"$base_url/presentations/peek/$node->nid");return false;’

  22.       ),

  23.     );

  24.     return l($text, "node/$node->nid/edit", $attribs);

  25.   }

  26. }

The code to add a javascript event will need a little more work. To be more specific, we have to include the javascript files that we need. I am not showing the javascript files because it is rather simple because I use basicModal for the overlay (a jquery plugin I came across) and swfobject to render the presentation movie.

  1. /**

  2.  * Field handler to clone a presentation

  3.  */

  4. class views_handler_field_presentations_link_clone extends views_handler_field_node_link {

  5.   function render($values) {

  6.     // ensure user has access to edit this node.

  7.     $node = new stdClass();

  8.     $node->nid = $values->{$this->aliases[‘nid’]};

  9.     $node->status = 1;

  10.     $text = !empty($this->options[‘text’]) ? $this->options[‘text’] : t(‘clone’);

  11.     return l($text, "presentations/$node->nid/clone", array(‘query’ => drupal_get_destination()));

  12.   }

  13. }

I am not sure if the extension on views_handler_field_node_link is really neccessary, and I will look into this later on. The important thing is that we override the render method of our class and make the field link look as we want it to. If you want to use extra fields from your database table, you have can add these fields in the constructor. If you override the constructor, you always have to call the parents constructor as well:

  1. function __construct() {

  2.   parent::__construct();

  3. }

;

To use extra fields in you render method, than you can set them in the constructor like this :

  1. function construct() {

  2.   parent::construct();

  3.   $this->additional_fields[‘uid’] = ‘uid’;

  4. }

Later you can place this fields and sort them how you please. If you did not look into all features of views, I can assure you that you can do the most marvelous things with that module. Add image cache presets to show thumbnails with in your custom views.
I hope this was interesting for anyone. Please comment on this article if it was one of the reasons why you decided to digg views. Playtime!

This entry was posted on Wednesday, October 22nd, 2008 at 1:27 pm and is filed under Drupal. 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.

Author: 
RSS Tags: 
Original Post: 

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