Making a Scheduling Grid with Views Presentation Write-Up

torelad@drupal.org's picture
public
group: Vancouver
torelad@drupal.org - Fri, 2007-02-02 23:00

As promised, a write-up of my presentation at the January Drupalers meeting.

My name is Dale McGladdery, and I'm a Drupala ... sorry, wrong meeting. Here we go.

Northern Voice Scheduling Grid

The Views module via theming allows custom formatting of list views using PHP code. This formatting method, combined with CCK, can be used to provide a data driven schedule grid. This was used to create the Northern Voice scheduling grid: 2007.northernvoice.ca/schedule.

Northern Voice Scheduling Grid Clip

This Views feature was also used to create the Northern Voice FAQ page: 2007.northernvoice.ca/faq

My apologies for people looking for an exact how-to. This will, I'm positive, give you enough information to recreate the grid, but it isn't a complete set of step-by-step instructions.

CCK

A presentation session has some basic fields like its name, a session summary, presenter, time slot, room or track number. The CCK node type is created with these fields. For the Views component to work properly, the timeslot and room must be fixed text using the either 'select list' or 'radio buttons' widget type. The values will be your time slot name and room/ track name, respectively. Optionally, the room can contain the values None and All. For this presentation, the CCK content node is called: session

The View

The following View settings needs to be set as follows:

  • Provide Page View: enabled
  • View Type: List View
  • Nodes per Page: Some number greater than the number of your sessions
  • Use Pager: Disabled
  • Fields: Select all of the fields that will appear in your schedule grid
  • Filters: "Node: type" "Is one of" "session"/Node: Published Equals Yes

The others are settable as you'd like.

Views Custom Formatting Overview

When the Views module is generating the page for a list view it checks template.php for a custom formatting function. If found, this function is used to create the view body content.

header
body -> if it exists call function: phptemplate_views_view_list_myviewname
footer

For the examples the view will be named: sched1

The Views Theme Wizard will give you default content for template.php. The code it provides will use a callback function to format each item using a .tpl.php template file. The .tpl.php template file is also provided by Theme Wizard. We will never use this .tpl.php template file. You can optionally create it to observe how it works.

To observe the template.php function in action create a view and add the function name specified by the Theme Wizard. Instead of using the code provided by the theme wizard, replace it with:

<?php
function phptemplate_views_view_list_sched1($view, $nodes, $type) {
  return
"<p>This is the text from my template.php file</p>";
}
?>

This function is passed 3 variables: $views, $nodes and $type. We can look at the content of these three variables using the print_r function:

<?php
function phptemplate_views_view_list_sched1($view, $nodes, $type) {
 
$output = '<p>Displaying the variables passed.</p>';
 
$output .= '<h2>$view value:</h2>';
 
$output .= '<pre>' . print_r($view, TRUE) . '</pre>';
 
$output .= '<h2>$nodes value:</h2>';
 
$output .= '<pre>' . print_r($nodes, TRUE) . '</pre>';
 
$output .= '<h2>$type value:</h2>';
 
$output .= '<pre>' . print_r($type, TRUE) . '</pre>';

  return
$output;
}
?>

Partial Screenshot of Output:
Screenshot of raw output

Views, in this context, has become a general purpose database query and page display engine. By selecting the right set of fields we can collect all the data we need for the scheduling grid.

Here is simplified psuedocode for the template.php code provided by the Theme Wizard. It processes this data into a displayable form.

loop over $view field data
  collect fieldnames

get $base_vars[] (1)

loop over $nodes
  $var[] = $base_var[]
  for each field
    add field value to $var[] // e.g. field_time_slot_value
  format field values into text string using theme callback (2)
  add text string to $items[] 

convert $items[] (array of text strings) to single text string (3)

return text string

---
1: $base_vars contains Views specific information
2: The theme callback is the second (.tpl.php) file provided by the Theme Wizard
3: Uses standard Drupal theming function: theme_item_list

Custom Formatting the Grid

I insinuated my grid code into the existing Views code and used the same basic pattern of collecting individual values into arrays and then building the output text based on the arrays. The $schedule variable is a multidimensional array in the form:

$schedule[timeslot][room][session_index][session_data]

session_data: An associative array containing information like presenter and session title.

session _index: Although one would not schedule more than one session per room, session_index is required to pick up room conflicts. Otherwise if multiple sessions are scheduled only the last one loaded would be displayed (i.e., would overwrite previous value).

The $roomlist array is a simple array used as a kind of alternate index into $schedule. We need to know all of the rooms used anywhere in the schedule. Since a specific timeslot may not have all of it's room scheduled and we need to know when to create an empty table cell we can't simply loop over every room in a specific timeslot.

The basic pseudo code, minus added extras, looks like this:

loop over $view field data
  collect fieldnames

get $base_vars[]

loop over $nodes
  $var[] = $base_var[]
  for each field
    add field value to $var[]
  add room to $roomlist[]
  add session data to $schedule  
  // $schedule[timeslot][room][session_index][session_data]

remove "All" and "None" from $roomlist[]
remove "Unscheduled" from $schedule[timeslot]

//Build the table
for each $room in $roomlist[]
  add a column heading
for each timeslot in $schedule[]  // table row for each timeslot
  add the timeslot label          // leftmost column
  for each $room in $roomlist[]   // column cell for each room
    add room session info to output string
  
return output string

Over and above basic scheduling there are other features that are desirable. A way of specifying that a session take up the entire row for things like keynotes and breaks. In the case of Northern Voice, the ability for the session title to be a link or plaintext was added. It is also desirable to flag room conflicts. All of these features add complexity to the code.

The Actual Full Code

The ultimate code came out looking like this. The formatting was placed in function to make the loop cleaner and majority of visual formatting left for CSS.

<?php
/**
* Schedule Grid
*
* Theme function that turns a list view into a grid display.
* This code is very customized and is tightly coupled to a
* CCK type named session.
*
* Date: Tue, 2006-12-05 23:38
* View: schedule
*/
function phptemplate_views_view_list_schedule($view, $nodes, $type) {
 
$fields = _views_get_fields();

 
$taken = array();

 
// Set up the fields in nicely named chunks.
 
foreach ($view->field as $id => $field) {
   
$field_name = $field['field'];
    if (isset(
$taken[$field_name])) {
     
$field_name = $field['queryname'];
    }
   
$taken[$field_name] = true;
   
$field_names[$id] = $field_name;
  }

 
// Set up some variables that won't change.
 
$base_vars = array(
   
'view' => $view,
   
'view_type' => $type,
  );

 
// A reference list of rooms, which will be used to create our table columns
 
$roomlist = array();

 
// $schedule is a multidimensional array as follows:
  // $schedule[timeslot][room][session-index][session-data]
  //       timeslot: text value provided by cck
  //           room: text value provided by cck
  //  session-index: integer index (0, 1, 2) to allow multiple presentations to exist in a room
  //                 Required to detect room conflicts
  //   session-data: associative array of session information (e.g., presenter, title)
 
$schedule = array();
 
 
//
  // Extract the node data into the room list and schedule
  //
 
foreach ($nodes as $i => $node) {
   
$vars = $base_vars;
   
$vars['node'] = $node;
   
$vars['count'] = $i;
   
$vars['stripe'] = $i % 2 ? 'even' : 'odd';
   
   
// Extract the field data from the node information
   
foreach ($view->field as $id => $field) {
     
$name = $field_names[$id];
     
$vars[$name] = views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node);
      if (isset(
$field['label'])) {
       
$vars[$name . '_label'] = $field['label'];
      }
    }
   
   
// Make things a little easier by using our own named variables
   
$timeslot   = $vars['field_time_slot_value'];
   
$room       = $vars['field_room_value'];
   
$sesstitle  = $vars['title'];
   
$presenters = $vars['field_presenter_value'];
   
$linktitle  = $vars['field_link_title_value'];
   
   
// Add the room to the room list if it isn't there already
   
if (!in_array($room,$roomlist)) $roomlist[] = $room;
   
   
// Add the item to the schedule
   
if (!array_key_exists($timeslot, $schedule)) {
     
$schedule[$timeslot] = array(); // Initialize timeslot if it doesn't exist
   
}
    if (!
array_key_exists($room,$schedule[$timeslot])) {
     
$schedule[$timeslot][$room] = array();  // Initialize presentation index if it doesn't exist
   
}
   
$schedule[$timeslot][$room][] = array('title'      => $sesstitle,
                                         
'presenters' => $presenters,
                                         
'linktitle'  => $linktitle
                                         
);
  }
 
 
// All and None are special values and not a room, so remove them from
  // the room list if they exist. Remember that there will still be the All and
  // None entries in $schedule. $roomlist is just a type of alternate index
 
if ( in_array('All', $roomlist) ) {
    unset(
$roomlist[array_search('All', $roomlist)]);
  }
  if (
in_array('None', $roomlist) ) {
    unset(
$roomlist[array_search('None', $roomlist)]);
  }
 
 
// Unscheduled is a timeslot we don't want appearing in the grid, either
 
if (array_key_exists('00: Unscheduled',$schedule)) {
    unset(
$schedule['00: Unscheduled']);
  }
 
 
// Guarantee a specific order
 
sort($roomlist);

 
//
  // Build the table
  //
 
$output  = '<table class="schedulegrid">';
 
 
// Build the table header
 
$output .= '<tr><th>Time</th>';
  foreach (
$roomlist as $room) {
   
$output .= '<th>' . $room . '</th>';
  }
 
$output .= '</tr>';
 
 
// Build the table rows, aka timeslots
 
foreach($schedule as $timeslotname => $roomarray) {
   
$output .= '<tr>';
   
$output .= '<td class="timeslotlabel">' . $timeslotname . '</td>';
   
$output .= _format_schedule_cells($roomarray, $roomlist);
   
$output .= '</tr>';
  }
 
 
$output .= '</table>';
 
  return
$output
}

function
_format_schedule_cells($roomarray, $roomlist) {

 
$output = '';

 
// There are two displays modes, one for the 'All' case, which uses colspan to create
  // a single table cell; the second mode uses one room per table cell.
  // Within each of these two modes, we have to check for conflicts

 
if (isset($roomarray['All'])) {
   
// If there is an 'All' entry, it should be the only one for this timeslot
        // Check for other bookings and if they exist flag as a conflict
   
if (count($roomarray) > 1) {
     
// We have a conflict, print out all of the information for each room
     
$sessionblurb = '<strong>!!! CONFLICT !!!</strong><br>';
      foreach(
$roomarray as $roomname =>; $roomsessions) {
       
$sessionblurb .= '<strong>' . $roomname . '</strong>: ';
        foreach (
$roomsessions as $session) {
         
$sessionblurb .= $session['title'] . '<br>';
         
$sessionblurb .= $session['presenters'] . '<br>';
        }
      }
    } else {
     
// No rooms booked in addition to the "All" session
     
$sessionlist = $roomarray['All'];
     
$sessionblurb = '';
      foreach (
$sessionlist as $session) {
       
$title = $session['title'];
        if (
$session['linktitle'] == 'No') {
         
ereg('^<a.*>(.*)</a>', $session['title'], $matches = array());
         
$title = '<strong>' . $matches[1] . '</strong>';
        }
       
$sessionblurb .= $title . '<br>';
       
$sessionblurb .= $session['presenters'] . '<br>';
      }
    }
     
   
$output .= '<td colspan="' . count($roomlist) . '">' . $sessionblurb . '</td>';
                   
  } else {
   
// The 'All' room was not found, so format each room as a table cell
   
foreach ($roomlist as $room) {
     
$sessionblurb = '';
     
// Since we're creating a grid, it's possible to have empty slots. We therefore need to
      // doublecheck that there's an entry here for this column/timeslot combination.
     
if (isset($roomarray[$room])) {
       
$sessionlist = $roomarray[$room];
       
// Check for multiple sessions, aka room conflict
       
if (count($sessionlist) > 1) {
         
$sessionblurb .= '<strong>!!! CONFLICT !!!</strong><br>';
        }
       
// Output each session (Normally one, unless there's a conflict)
       
foreach ($sessionlist as $session) {
         
$title = $session['title'];
          if (
$session['linktitle'] == 'No') {
           
ereg('^<a.*>(.*)</a>', $session['title'], $matches = array());
           
$title = $matches[1];
          }
         
$sessionblurb .= $title . '<br>' . $session['presenters'] . '<br>';
        }
      } else {
       
// No entry for this column/timeslot combination
       
$sessionblurb .= '&nbsp;';
      }
     
     
$output .= '<td>' . $sessionblurb . '</td>';

    }
  }
 
  return
$output;
}
?>

Some End Notes

Multiple Schedule Grids

Unfortunately, this isn't a general purpose method for creating a schedule grid. For each schedule grid you need to create a view and add the grid code to template.php. The code could easily be generalized enough so the Views template.php function could simply call a more general function and directly pass along the arguments.

Ordering Timeslots

Since the time slots are simply a text string, you may some work to do to insure they come out ordered. Consider a schedule with timeslots for both 8:30am and 8:30pm. For Northern Voice I cheated an prefixed the timeslots with numbers to force an ordered sequence:

00: Unscheduled
01: 8:30am - 9:30am
02: 9:30am - 10:15am

And then used:

<?php $output .= '<td>' . strstr($timeslotname, ' ') . '</td>'; ?>

to strip off the numbers.


Great post

mackh's picture
mackh - Sat, 2007-02-03 01:06

Thanks for sharing your code and describing the process!


oO

bubu - Thu, 2008-07-03 18:16

Viagra online USA to might
For sale Viagra without perscription if danger
Cialis in india for sale party of
Buy Viagra 100 mg the as
Buy cheap Cialis government" Mgr.
Discount Cialis online wand in
Cialis uk online crisis over
Viagra prescription canada circle. they
Viagra without a prescription canadian critics. he
Cialis order no prescription drama. to
No prescription Sildenafil submit tribal
Order Generic Cialis Catholic 1917.
Cialis order Canada languages morrow
Buy Canada Cialis by in
Generic Viagra sales with
Buy Viagra pills language transfer
Order discount Cialis compare an take
Online Cialis sales The dissentient.
Mastercard Cialis English FOR
Order Cialis pills commerce premiership,
Order Viagra without a prescription be assurances
Order Viagra Canada have events
Buy Viagra 50 mg the he
Viagra Toronto fought. a
Buy Viagra UK Robert practical
Buy Viagra in UK reasons
Buy Cialis online parliament
Buy cheap Viagra in uk an and
Viagra online without prescription of from
Cheap Tadalafil online submit the
Cheapest Viagra online a in
Sale Cialis rage the
Generic Cialis sales
Viagra and Viagra for sale to sentiment.
Sale Viagra well as
Viagra 50 mg in much
Cheap Cialis for sale the the
Canadian Cialis the him
Order Cialis Canada constitutions the
Generic Viagra no prescription lived absence
How order Cialis position to
Cheapest Viagra from India ill-thought-out Borden
Discount order Cialis and separate
Buy Sildenafil online satisfaction. as,
Buy cheap Cialis in uk were in
Buy Cialis without prescription of was
Order Cialis There was
Cialis order online as pole.
Viagra online store did in
Buy Viagra soft tabs Geoffrion reinvest
Mastercard Viagra serenity THE
Buy Cialis online in the UK the were
Order cheap Cialis to merged.
Order Cialis Cialis and to
Online Viagra sales the to
Buy Cialis pills candid THE
Buy Viagra online in the UK it announcement
Sildenafil no prescription being stroke
Canadian drugs Viagra for in
Buy Cialis no prescription and issue
Buy cheap Generic Cialis in upon
Buy Cialis UK what more
Tadalafil 10mg necessities; Ontario.
Buy cheap Viagra online uk the
No prescription Tadalafil them; ten
Indian pharmacy Rouges be
Order Viagra without prescription not L.
Generic Viagra for sale been associate
Levitra Viagra Viagra proposed the
Buy Tadalafil without prescription Fitzpatrick; his
Viagra from India it the
Discount Cialis tradition men
Viagra order Canada parliament, the
Order Viagra cheap policy embodiment
Buy Viagra in the uk be the
Viagra for sale online the moment
Buy Generic Cialis Liberals Ottawa
Viagra low price The slipping
Cialis from Canada they the
Cialis 10 mg reciprocity Conservatives
Viagra sales online not war
Buy online order Viagra the it
Viagra in india for sale They 1900
Want to buy Viagra could government
Viagra mail order link appearance.
Cheap Viagra for sale Ottawa. between
Cheap Generic Cialis knew among
Cheap Viagra online no prescription sports
Generic Cialis of in
Online pharmacy no prescription all the
Erectile dysfunction pill for sale charge suspicion
Viagra free samples the own
Cialis online without prescription the the
Order discount Viagra compare the Canada."
Viagra uk online a gone.
Canadian Viagra preferred a
Buy Viagra in England the victory
Viagra Australia the see
Tadalafil 20mg the put
Generic Cialis for sale Quebec the
Cialis without prescription and Senecal,
Buy Cialis 20 mg secure and
Sales Viagra the embraced
Cheapest Cialis india rested
Buy Cialis in England into to
Viagra order no prescription the the
Cialis buy india carry was
Viagra for sale there enlist.
Cheap Cialis pills politics Canadians,
Cialis free samples not Bourassa.
Viagra online sales off artifice
Viagra discount sales his victory
Discount Cialis soft tabs declaration of
Cialis without a prescription canadian general
Generic Cialis no prescription of efforts
Buy Viagra India necessity long,
Buy Tadalafil citrate parliament. to
Cheap Sildenafil online approval, devotion
Discount Viagra online trouble movement
Sildenafil for sale there just
Cheap Cialis online no prescription GOVERNMENT full
Cialis sales online both advice
Cheapest Cialis online his
Buy Cialis online without prescription which beginnings
Cialis online sales In was
Buy Cialis pill places the
Buy Cialis Canada temporary
Cialis buy challenge meant
Order Cialis online the
Viagra buy language dissented
Discount order Viagra did
No prescription Viagra accomplished questionings
Cialis discount sale and the
Order Viagra Viagra and into
Cialis for sale before extension
Low cost Viagra clergy Gladstone
Cialis and cialis for sale are
Cheap Generic Viagra their humiliated,
Buy Canada Viagra its developments
Generic Viagra he of
Discount Viagra soft tabs he of
Discount Viagra elements. upon
Viagra 100 mg Canadian pharmacy as retain
Viagra discount sale for of
Cialis for sale online parliament after
Viagra 100 mg an for
For sale Cialis without perscription events committed
Sildenafil 100mg France; passionate
Cialis 20 mg are fall
Indian pharmacy he government.
Order Viagra prescription an Liberals
Cheap Viagra soft tabs whereupon extend
Order Tadalafil of very
Canadian drugs Cialis they essential
Buy Cialis online order instance province
Buy Cialis India arriving political
Generic Cialis india full them
Buy Viagra Mastercard Liberal secure
Cialis no prescription task. Laurier
Cialis low price reviving charged
Order cheap Viagra Canada's proceeds
Sales Cialis A governments.
Viagra from Canada in twelve
Cialis from India Liberals,
Cheapest Cialis prices his objection
Cialis price which he
Buy Sildenafil citrate were first
Buy Generic Viagra to every
Order Cialis without a prescription was conscriptionist
Buy Viagra pill up with
Low cost Cialis justification, his
Cialis mail order in of
Order Viagra pills command did
Cheap Viagra online make if
Cheap Viagra pills FOUNDATION Sir
Cialis prescription canada loyalties party;
Online pharmacy no prescription pressure old
Cheapest Viagra india the Northwest
Buy Viagra occasions party
Generic Viagra india the of
Buy Cialis followed; giving
Cialis online USA in commended
How order Viagra submitted bishops,
Order Generic Viagra disfavour Catholic
Cheap Cialis online yielded with
Buy cheap Viagra and
Cheap Cialis soft tabs first to
Buy Viagra no prescription and upon
Buy online order Cialis for navvy.
Want to buy Cialis disruption;
Buy Cialis in UK upon grow
Buy Sildenafil without prescription letters in
Tadalafil for sale the that,
Viagra without prescription Laurier's policy
No prescription Cialis a timely
Cialis best buy is own
Order Cialis cheap plans. is
Buy Cialis soft tabs revival
Buy Tadalafil online submitted saw,
Viagra best buy Mr. HOPES
Cialis for sale cheap and should
Buy Cialis 10 mg province. catalogues
Levitra Cialis Cialis oft Laurier
Buy Cialis Mastercard third going
Erectile dysfunction pill for sale majority bitterly
Buy Viagra online order he
Cialis Toronto months of
Buy prescription Cialis represented where
Buy Viagra without prescription running America;
Buy online Viagra conditions: events
Viagra order online successful the
Cialis Australia every to
Sildenafil 50mg safely
Buy cheap Generic Viagra of appear
Buy cheap Cialis online uk the defeat
Viagra buy india advocates on
Viagra no prescription Manitoba proposition
Buy Viagra Canada the "could
Buy Viagra online without prescription parliament to
Buy online Cialis it? his
Buy Cialis in the uk merger postmaster
Tadalafil no prescription 1917--he
Cialis online store acceptance its
Cheapest Viagra prices Montreal's the
Get Viagra no prescription circumstances an
Order Viagra online its of
Cialis pills for sale to French
Cheapest Cialis from India the enabled
Order Sildenafil the the
Cialis 20 mg Canadian pharmacy office He
Get Cialis no prescription unity. Tarte
Order Viagra innuendoes, less
Viagra pills for sale surbordinate to
Order Cialis prescription general
Order Cialis without prescription exactly each
Viagra price his throw
Viagra for sale cheap substituted his
Cialis discount sales 45 This
Buy prescription Viagra Borden's last
Buy Viagra online of manner

Very Nice !!! ... but problem when customizing it ...

coolin's picture
coolin - Thu, 2007-02-15 01:14

First of all, thanks very much for this post ... it helped me a lot.
However, I have some problems for customizing it ...

I want to make a page containing the different members of my laboratory. I created a CCK content type and by following your steps, I have a nice view containing all members, displayed in a nice way.

Now I want to separate them according to their position (labhead, researcher, staff, etc.). The first trial I made was the following:
In the CCK content type i have a checkbox "position". If I retrieve it in the template.php file: "$pos = $vars['field_position_value'];", it gives a "string" reflecting well what the member is. The problem comes if I try to compare it :
"if ($pos == "labhead") ....." --> this always gives FALSE!!
The problem seems to come from the fact that $pos comes from a checkbox. The test works fine if it was a simple textfield.==> How to compare the value retrieve from a checkbox??

Any suggestions??

In a second attempt, I thought it could be better to use a category instead of a checkbox. I created a container "Labmember" with different categories. Each time a member is added it has to specify the category he belongs to. Problem: How to retrieve the category information in the view method in the template.php file? (I posted this question in: http://drupal.org/node/118927 but still no answer).

Thanks for any help
colin


bonus pack

moshe weitzman's picture
moshe weitzman - Thu, 2007-02-15 13:15

nice work ... i think you could use theme('table') here. It is pretty flexible, allowing you to add classes for for cells, and headers can be on left or on top (but not both?). in any case, would be nice to generalize this for any two cck fields and then add it to views bonus pack (see contrib repository). thats the best way to have people reuse your code.


i just wanted to add a link

drewish's picture
drewish - Thu, 2007-02-22 22:52

i just wanted to add a link to the post describing this in views bonus pack: http://groups.drupal.org/node/2879


Very Nice !!!

Aleks - Fri, 2007-10-12 07:57

Thanks for sharing your code and describing the process!
Korona

Vancouver Events & Music

j0rd's picture
j0rd - Fri, 2007-11-16 02:44

i was actually looking for some cheap c14l15


Vancouver Events & Music community
Vancouver based graphic design