Problem

The implementation of the theme_textfield hook throws a fatal PHP error when the field is an autocomplete field. The issue exists in the stable version and in the dev version also.

You can reproduce the error submitting a form that contains an autocomplete field. It does not matter if the field is optional or required or if it has been leaved blank o has been filled.

When the function drupal_attributes is called the first time inside the bootstrap_textfield function, it converts de ['#attributes']['class'] array into a string, overwritting its original value (See the &$data below).


function drupal_attributes(array $attributes = array()) {
  foreach ($attributes as $attribute => &$data) {
    $data = implode(' ', (array) $data);
    $data = $attribute . '="' . check_plain($data) . '"';
  }
  return $attributes ? ' ' . implode(' ', $attributes) : '';
}

This function is called on the line 22 of the /themes/system/textfield.func.php file (Or /templates/system/textfield.php of the dev version).

After this, if the field is an autocomplete field, bootstrap_textfield tries to add a new class to the field on line 27, and the fatal error is thrown, because the ['#attributes']['class'] value is now a string.

Proposed resolution

Assigning the value of $element['#attributes'] to a variable before passing it as a parameter when calling drupal_attributes should fix the issue.

Comments

tucho created an issue. See original summary.

markhalliwell’s picture

Status: Active » Closed (duplicate)
Related issues: +#2566541: Update theme_textfield to be in line with core 7.39

The entire function needs to be refactored. Closing in favor of this related issue.

markhalliwell’s picture

Also, I'm not sure why you're getting a "fatal", but it's not because of drupal_attributes(). It doesn't alter the existing attributes array (i.e. it's not a referenced variable). So, it must be a string to begin with (e.g. what you or some module is providing).

tucho’s picture

Status: Closed (duplicate) » Active

The problem arraise when drupal_attributes is called.

I just modified the code inside bootstrap_textfield and added some print_r (Yes, that's awful but it works for this ;) ) before and after the call to drupal_attributes on line 22:


echo '<pre>' . print_r($element['#attributes'], true) . '</pre>';
$output = '<input' . drupal_attributes($element['#attributes']) . ' />';
echo '<pre>' . print_r($element['#attributes'], true) . '</pre>';

And the output before the call is:

Array
(
    [class] => Array
        (
            [0] => location_auto_province
            [1] => form-control
            [2] => form-text
        )

    [type] => text
    [id] => edit-locations-0-province
    [name] => locations[0][province]
    [value] => Chaco
    [size] => 64
    [maxlength] => 64
)

And after:

Array
(
    [class] => class="location_auto_province form-control form-text"
    [type] => text
    [id] => edit-locations-0-province
    [name] => locations[0][province]
    [value] => Chaco
    [size] => 64
    [maxlength] => 64
)

I also remove the function bootstrap_textfield, so the original theme_textfield is executed and the issue is not present.

May be, because on that function drupal_attributes is the last thing to get called?

Finally, I change my PHP version from PHP5.4 to PHP5.2 and the problem is still there.

tucho’s picture

I tried assigning $element['#attributes'] to another variable, but the problem persists.

Finally, I create a new array and copy the values from $element['#attributes'] with a foreach loop. Then I call drupal_attributes with the new array.


$attributes = array();
foreach ($element['#attributes'] as $attribute => $values) {
  $attributes[$attribute] = $values;
}
$output = '<input' . drupal_attributes($attributes) . ' />';

I attach two patches:

Version 7.x-3.0: bootstrap-textfield_class_fatal_error-2566595-5.patch
Version 7.x-3.x (dev): bootstrap_dev-textfield_class_fatal_error-2566595-5.patch

markhalliwell’s picture

Priority: Major » Normal
Status: Active » Closed (works as designed)

#4 shouldn't be possible, like at all... drupal_attributes() does not use $attributes as a reference (source). For example:

The actual function signature:
function drupal_attributes(array $attributes = array())

Is not:
function drupal_attributes(array &$attributes = array())
(notice the & at the beginning of $attributes).

The only thing I can think of is that you've somehow modified drupal_attributes() directly to include this (or there's something else going on here), because core doesn't behave like that out-of-the-box.

http://php.net/manual/en/language.references.pass.php

tucho’s picture

I know what you mean, but I'm working on a clean core and the output that I have posted on #4 is the one I'm getting.

My drupal_attributes function is the one of my initial post.

markhalliwell’s picture

&$data isn't the culprit as $attributes is never passed by reference in the first place. &$data only modifies the $attributes copy only, not $element['#attributes'] in the calling function.

Furthermore, looking at your "after" output, you'll see that only class is modified, not any of the other attributes. It should have returned for instance:

    [type] => type="text"

I imagine that whatever is going on is just a local occurrence as I have never encountered this issue.

tucho’s picture

Yes, I have seen that too.

I'm making a new deploy to check again why is this happening.

Thank you for your time. I will see #2566541: Update theme_textfield to be in line with core 7.39 now and make a patch for the update, to help a little and pay back for it ;)