This is weird, and I hope I explain it right...

I have a filefield formatter I've written as part of the Flashy module. For various reasons it is a multi-value formatter. This has led me to an interesting discovery that is manifesting itself as a bug. Specifically, multi-value filefield formatters in views do not work, at least as far as I can tell.

To wit, when using a single-value formatter or multi-value formatter through the normal node page, the $element parameter to the formatter is passed in properly. When loaded through a view. it is not. As near as I can tell, the problem is traced to content_format() in content.module and the filefield_field_sanitize() function.

The $item passed into content_format, either way, looks like this:

array(4) {
  ["fid"]=>
  string(2) "59"
  ["list"]=>
  string(1) "1"
  ["data"]=>
  string(32) "a:1:{s:11:"description";s:0:"";}"
  ["#delta"]=>
  int(0)
}

content_format() then, in the case of a single-value formatter, does this:

$items = array($item);
$function = $field['module'] .'_field';
if (function_exists($function)) {
  $function('sanitize', $node, $field, $items, FALSE, FALSE);
}

while for a multi-value formatter it does this:

$items = $item;
$function = $field['module'] .'_field';
if (function_exists($function)) {
  $function('sanitize', $node, $field, $items, FALSE, FALSE);
}

Note that $items is therefore different when it's passed into $function('sanitize'), which in this case ends up with filefield_field_sanitize in filefield_field.inc. However, that function is hard-coded to only be able to handle $items as an array, as its first line is:

foreach ($items as $delta => $item) {

It then checks $item['fid'], which won't exist if content_format() passed in the multi-value form, and it will therefore do no sanitizing/loading of the actual data, and then the formatter won't have the necessary data, and there will be a sad trombone playing.

Whatever the code path is for the non-views version, something else is handling that logic so that filefield_field_sanitize() gets the data it's expecting. I didn't bother tracing through that, as those parts of CCK scare me.

So the net result is that filefield_field_sanitize() cannot handle multi-value formatters through views, because CCK is feeding it a different data structure that it is not expecting. Fixing that bug I leave as an exercise for the reader/maintainer. :-)

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

quicksketch’s picture

Priority: Critical » Normal

I answer your verbose (and excellent) report with equal verbosity. ;)

I don't think FileField's sanitize function is at fault for this problem, it looks like we're somehow not following the documentation for passing in parameters into content_format().

Like you said at first, with either a multivalue formatter or a single value formatter, the $item passed into content_format() is the same, a single file object. However, according to the PHP doc at the top of content_format() the $item variable should already be an array of items if the destination formatter is multivalue:

/**
 * @param $item
 *   The field item(s) to be formatted (such as $node->field_foo[0],
 *   or $node->field_foo if the formatter handles multiple values itself)
 */

So $item should already be an array of $file objects, not a single file, and filefield_field_sanitize() shouldn't need to be changed at all.

Now we get into the Views integration. We need to know why CCK isn't getting an array of items and instead is only getting a single item. CCK already has a Views handler "content_handler_field_multiple" which properly calls content_format() with an array of items. My guess is that FileField needs to tell CCK (to tell Views) that FileFields should use the content_handler_field_multiple handler instead of the normal content_handler_field.

That's as far as I can discover currently, I'll take a look at FileField's filefield_field_settings_views_data() function to see if any adjustment needs to be made there.

quicksketch’s picture

FileSize
160.44 KB

Well, upon further inspection I actually couldn't find anything wrong. In my installation (CCK 2.2, Views 2.3, FileField 3.x dev), everything does receive the proper parameters.

Setup:
- Create a new content type
- Add a multivalue FileField to the type
- Add some nodes with files attached
- Make a new view, add the "Content: [Label of Field] (field_[name_of_field])" field
- Ensure the "Group multiple values" checkbox is checked for this field. This option only shows up if the CCK field is multivalue. See screenshot.
- Select a multivalue formatter from the "Format" drop-down.

I didn't have any multivalue formatters around on my local, so I modified the default file formatter to be multivalue:

// In filefield.module:
function filefield_field_formatter_info() {
  return array(
    'default' => array(
      'label' => t('Generic files'),
      'field types' => array('filefield'),
      'multiple values' => CONTENT_HANDLE_MODULE,
      'description' => t('Displays all kinds of files with an icon and a linked file description.'),
    ),
  );

// In filefield_formatter.inc:
function theme_filefield_formatter_default($element) {
  $field = content_fields($element['#field_name']);

  $output = '';
  foreach (element_children($element) as $delta) {
    $file = $element[$delta]['#item'];
    $output .= theme('filefield_item', $file, $field);
  }
  return $output;
}

Then everything worked as expected. Multiple $file objects were passed into the $item parameter of content_format(), then filefield_field_sanitize(), then finally theme_filefield_formatter_default(). As far as I can tell, everything is working properly.

Crell’s picture

Title: Multi-value formatters + Views = Fail » Multi-value formatters + single-value record + Views = Fail
Project: FileField » Content Construction Kit (CCK)
Version: 6.x-3.0-beta3 » 6.x-2.2
Component: Code » Views Integration

So after some further investigation with quicksketch, we are now blaming CCK. :-)

Here's the situation as we now see it:

content_format() in fact expects different data depending on whether the field is single or multi-value. However, Views only feeds multiple values to content_format() iff:

1) The field in question is set to multi-value.
2) The field in question is set to "group multiple values" in the view.

If one of those is not the case, then the field is treated as single-value by Views and content_format() is fed incorrect data.

But it's not views per se that's the issue, it appears. In fact, our current working theory is that it's in content_handler_field_multiple::render():

    // If this is not a grouped field, use content_handler_field::render().
    if (!$this->defer_query) {
      return parent::render($values);
    }

Just because a field isn't grouped doesn't mean that its formatter isn't still expecting grouped data. A group of one is still a group! I don't know why this hasn't come up before, but that's our working theory.

I'm not sure what the proper solution is, other than it being related to enhancing that check above to be smarter about when it should delegate behavior to the single-value rendering handler. How exactly it should do that, I don't know yet.

yched’s picture

Status: Active » Needs review
FileSize
1.37 KB

Does the attached patch fix it for you ?

Crell’s picture

Status: Needs review » Reviewed & tested by the community

It does indeed! Thanks, yched!

yched’s picture

Status: Reviewed & tested by the community » Fixed

Cool, committed. Thanks for the detective work !

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

scottprive’s picture

Using Drupal Core 6.20 and CCK 6.x-2.9 I have repeatedly hit this problem: Only the first field of a Multi-value item is output.
The problem persists even if I disable Devel and Themer, and flush all caches.

More precisely I should say - my problem matches this description perfectly, but it may be some other cause. The missing multi-fields are truly missing, as verified by a print_r to disk.

Here's the catch though - this only seems to happen in one content type or one view, once in a while (actually, this is the only content which utilizes multi-value, so it's not clear if it could be systemwide or if there is something "special" about this content and view, which was originally created around March 2009 using older Drupal modules, and the system since upgraded of course).

I am not sure what triggers this bad state for this content, but guess what fixes it for me?

If I change the field label from "Widget Label (fieldname)" to any of the other 2 choices, then save that field, and finally save the view itself. That fixes a particular field's display. (To completely fix all affected fields, I need to repeat the field-label "bump" on all of the fields, then save the View.)

Again, after "bumping" the fields' labels in Views Fields, then Saving the field, the content view will show it is repaired. All instances of the fields display.

Post CCK 2.2 you can still get a problem that has a similar nature.
In any case, if someone else hits this, try my workaround, and if it fixes it for you, please file a new issue.
(I suspect it is just my content or View having become corrupt, and so I'm not sure there is a real issue to file).