Fomatting multiple CCK items

I've been doing some work on the SWF Tools project to enhance its support for CCK. Specifically, turning multiple filefield uploads in to a playlist.

In principle it seemed easy, create a theme function but rather than assign the multiple value formatter as CONTENT_HANDLE_CORE set it to CONTENT_HANDLE_MODULE.

When I did this I found that the theme function gets a large array of elements, but the difficulty was getting the elements I was interested in (the file uploads) out of everything else that got passed. I couldn't seem to find what I needed in the documentation, but after rummaging through some other contrib modules I discovered that the trick seems to be to use element_children($element) to filter out the "properties" and get just the keys for the bits I was interested in.

So hook_field_formatter_info() becomes

<?php
function swftools_field_formatter_info() {
  return array(
   
'swftools_no_file' => array('label' => t('SWF Tools - no download link'),
     
'field types' => array('filefield'),
     
'multiple values' => CONTENT_HANDLE_CORE,
    ),
   
'swftools_playlist' => array('label' => t('SWF Tools - playlist'),
     
'field types' => array('filefield'),
     
'multiple values' => CONTENT_HANDLE_MODULE,
    ),
   
'swftools' => array('label' => t('SWF Tools - with download link'),
     
'field types' => array('filefield'),
     
'multiple values' => CONTENT_HANDLE_CORE,
    ),   
  );
}
?>

hook_theme() becomes

<?php
function swftools_theme() {
  return array(
   
'swftools_formatter_swftools' => array(
     
'arguments' => array('element' => NULL),
     
'function' => 'theme_swftools_formatter_swftools',
    ),
   
'swftools_formatter_swftools_no_file' => array(
     
'arguments' => array('element' => NULL),
     
'function' => 'theme_swftools_formatter_swftools',
    ),
   
'swftools_formatter_swftools_playlist' => array(
     
'arguments' => array('element' => NULL),
     
'function' => 'theme_swftools_formatter_playlist',
    ),
  );
}
?>

and theme_swftools_formatter_playlist() which processes the multiple files becomes

<?php
function theme_swftools_formatter_playlist($element) {
 
 
// Initialise an array for results
 
$files = array();
 
 
// Cycle through the file elements
 
foreach (element_children($element) as $key) {

   
// If nothing has been uploaded then there are items, but they are empty, so check they are set
   
if (isset($element[$key]['#item']['filepath'])) {
     
$files[] = $element[$key]['#item']['filepath'];
    }
  }
 
 
// If files array is empty then there is nothing to be rendered
 
if (empty($files)) {
    return;
  }
  
 
// But if we got something then we can call swf() now to render it
 
return swf($files);
 
}
?>

Notice that the array is checked using isset as I found that when nothing is uploaded the theme function is still called, but with an empty array. Using isset suppresses notice errors that occur if the loop tries to process an empty array.

For reference, the formatters for single files with / without a download link are generated using the same theme function, but the function tests to see in what way it is being called by looking at $element['#formatter'] to see what is being requested.

So that function looks like this:

<?php
function theme_swftools_formatter_swftools($element) {

 
// If the element is empty return
 
if (empty($element['#item']['fid'])) {
    return
'';
  }
 
 
// Get the markup for the flash content from swf()
 
$return = swf($element['#item']['filepath']);
 
 
// Add the filefield download link if required
 
if ($element['#formatter'] == 'swftools') {
   
$return .= "\n" . theme('filefield_formatter_default', $element);
  }

 
// Return the resulting markup
 
return $return;
}
?>