Enhance drupal_attributes() for multiple valued values

moshe weitzman - June 17, 2009 - 02:57
Project:Drupal
Version:7.x-dev
Component:theme system
Category:feature request
Priority:normal
Assigned:Unassigned
Status:closed
Issue tags:d4d, Quick fix, studio
Description

Studio theme has an enhanced version of drupal_attributes which can take an array of values and turn that into a space delimited value. The usual use case is the class attribute which separates multiple values with a space. This mutliple valued value is a common pattern. See theme_item_list() which also accepts an array as value - for nested lists.

This is backwards compatible and has no performance implications so it should be pretty non controversial.

AttachmentSizeStatusTest resultOperations
attributes.patch1.26 KBIdleFailed: Failed to apply patch.View details

#1

Jacine - June 17, 2009 - 05:26

This probably goes without saying, but +1 ;)

#2

JohnAlbin - June 17, 2009 - 05:58

I'm not opposed to this patch, per se, since it just modified how drupal_attributes() functions. However, I am opposed to using this function in any of core's tpl files.

See #306358: Add $classes to templates with new theme_process_hook functions (comments #65-76) for the full discussion, but the short answer is… tpl files are a huge win for Drupal theming because they make it easy (once you find the damn thing) to modify a bunch of the markup. Hiding the class and id attributes inside a <div <?php print drupal_attributes($attributes); ?>> means we add an additional barrier for non-PHP-savvy themers when all they want to do is add a class to a div. -1

#3

laura s - June 17, 2009 - 15:13

Re #2, wouldn't the answer logically be providing improved access and usability to attributes handling rather than sticking with the kludgey solution of multiplying .tpl files just to add classes and/or IDs? Leave the .tpl files for structure?

#4

Zarabadoo - June 17, 2009 - 15:49

I think it goes without saying that I am in support of this patch. Being able to store classes in an array is beneficial.

I won't argue the theme implementation of this as it is most likely outside the scope of this specific patch. To even come close for this to be used for themes as I do in Studio, we will need a better, more consistent structure. We would need something similar to Jacine's Skinr module would also have to be a must to satisfy the "barrier to entry" argument.

What I am saying is that we will need a much more intensive patch and I am sure that the conversation will go on for miles to make it happen. It is not worth arguing for as simple and autonomous of a change as this.

#5

ultimateboy - June 17, 2009 - 17:32

Absolutely. This patch gives the opportunity for so much more. It is quite simple. While it does not change anything apart of core just yet, it starts the process of a more united attribute system. There are really no side effects of adding this functionality. I just adjusted the code comment spacing slightly to match coding standards of wrapping lines.

To address JohnAlbin in #2, how this added functionality is implemented into template files will obviously be discussed in great detail later, however even this simple addition makes drupal_attributes() just a bit more powerful. But that should be addressed at a later time. There are possibilities as discussed at D4D Boston this past weekend such as <div class="<?php print $attributes['class'] ?>"> which allows for non php savvy themers to still add classes to the theme without hindering those who want more control of attributes. That idea would expand upon #306358: Add $classes to templates with new theme_process_hook functions, adding a huge amount of potential without making it more difficult to simply add an attribute into the tpl itself. The other option of course is to add a UI for adding attributes to elements as Skinr does, but none of this discussion should stop this match from moving forward. This obviously provides for a lot of potential, without really changing how core is working presently. Huge +1.

AttachmentSizeStatusTest resultOperations
493746-5-drupal_attributes.patch1.26 KBIdleFailed: Failed to install HEAD.View details

#6

moshe weitzman - June 17, 2009 - 18:00
Status:needs review» reviewed & tested by the community

Thanks Ultimateboy. Since we've not heard any dissent on this, lets move to RTBC.

#7

moshe weitzman - June 17, 2009 - 18:00

Thanks Ultimateboy. Since we've not heard any dissent on this patch specifically, lets move to RTBC.

#8

Damien Tournoud - June 17, 2009 - 18:12

#9

JohnAlbin - June 17, 2009 - 19:30
Status:reviewed & tested by the community» needs review

In d7 there are 2 new variables, $classes and $classes_array. You can modify the $classes_array in THEME_preprocess_HOOK function. That array gets flattened during template_process, which runs after all preprocess functions, to a string in $classes. You can modify the $classes string in a THEME_preprocess_HOOK function.

@laura_s, so in D7 you already don't need to mulitply tpl files just to change classes. :-)

@ultimateboy, “adding a huge amount of potential”. How so? I've been working on #306358: Add $classes to templates with new theme_process_hook functions for so long, I don't see the potential with this patch that you think is obvious. Wouldn't adding an $id variable to all templates give the same results, but be simpler and more consistent with the existing $classes variable? [ note, my failure to see the "obvious" might be related to the fact that its 3:30am here. :-p ] Perhaps this potential is more related to forms then to tpls?

@Damien, “enabled by this patch”. Meaning those proposed drupal_render changes would require this change to drupal_attributes? That issue hasn't moved in 7 months, so I don't see that as a compelling reason unless someone gets that issue moving again. I do like the idea of that patch, though.

I would like to see just a touch more discussion before RTBC.

#10

moshe weitzman - June 17, 2009 - 20:01

OK, lets stop discussing future patches in this one.

@JohnAlbin - you downgraded this patch but didn't specify what we should discuss that actually pertains to the patch. Please specify what you mean, or move back to RTBC. You make some great points, but lets save them for the next issue. I'll be sure to invite you :).

#11

ultimateboy - June 17, 2009 - 20:19

Maybe an example is best. JohnAlbin in #9, you are not quite right in saying that "perhaps this potential is more related to forms then to tpls" is somewhat correct. The power comes almost anytime multiple classes are added and then passed to drupal_attributes(). The individual changes will obviously come later which is why they are not included in the initial patch, but as a quick example of how this improves the code, here is an example of an updated theme_links: http://drupalbin.com/9968. Notice how the string concatenation that was going on to add classes is now replaced with an array of classes which is then handed down to drupal_attributes().

#12

catch - June 17, 2009 - 20:28
Status:needs review» needs work

I see a check_plain() taken out but not put back in.

#13

ultimateboy - June 17, 2009 - 21:22
Status:needs work» needs review

After talking to catch in IRC, I am adding back in the check_plain. Ideally, attributes should be passed in sanitized so that we dont have to check_plain for every attribute output, but that should be done in another patch.

AttachmentSizeStatusTest resultOperations
493746-13-drupal_attributes.patch1.27 KBIdleFailed: Failed to apply patch.View details

#14

JohnAlbin - June 18, 2009 - 05:38
Status:needs review» reviewed & tested by the community

@Moshe I just wanted to make sure this patch’s potential wasn't just duplicating functionality that was already in D7. ultimateboy's example in #11 clears up my concern; this patch would be useful in theme functions, for example. I had "tpl blinders" on before. :-D

Patch looks good.

#15

webchick - July 10, 2009 - 05:40
Status:reviewed & tested by the community» needs work

There is some valuable discussion here that I do not see reflected in the PHPDoc of drupal_attributes. Let's expand that out to capture the "Ah-Ha" moment that helped John to realize the power of this, because I'm still sitting here kind of in the dark.

Additionally...

+ *   An associative array of HTML attributes. If an attribute value is itself
+ *   an array, then its values are imploded using a space as delimiter (e.g.
+ *   a multiple value <em>class</em> attribute).

We don't embed formatting HTML in Doxygen as far as I know, so let's ditch the em tags. Also, I think the additions here rightly belong in the @return section (describing what the output will be) or else inline comments in the function, since they're not (afaik) instructions to the calling function.

Basically, please re-work the docs a bit to help other themers to understand why this is so awesome, and make proper use of it in their themes.

Tests would also really help with documenting the usage of this function. There are tons of us in #drupal who can help you with this. It's not necessarily a requirement for committing this, but it would surely help make it easier. This way, the expected behaviour is written down in code, so we're not likely to break it again.

#16

JohnAlbin - July 10, 2009 - 14:12
Status:needs work» needs review

I re-did the docblock and added some simpletests.

I'm also taking this opportunity to streamline drupal_attributes a bit more. We don't need to check if $attributes is empty or not an array. If someone is calling drupal_attributes with a string, that's a bug. And if the param is an empty array, then the foreach loop will simply be skipped. Also, not returning _anything_ (void return) if the attributes param is empty seems ungood to me, so it now returns an empty string in that case (the @return documentation claimed we were always returning a string, btw.)

Oh, and I did find a bug in theme_image() as it was passing NULL to drupal_attributes(), so that is fixed too. Let's see if the bot picks up anymore bugs.

AttachmentSizeStatusTest resultOperations
drupal-attributes-493746-16.patch4.21 KBIdleFailed: 11608 passes, 0 fails, 4 exceptionsView details

#17

System Message - July 10, 2009 - 14:31
Status:needs review» needs work

The last submitted patch failed testing.

#18

JohnAlbin - July 12, 2009 - 23:34
Status:needs work» needs review

Fixed broken tests.

To make this easier on reviewers, this patch does 4 simple things:

  1. drupal_attributes() used to only accept attribute values that were simple strings. After this patch, any attribute value passed to drupal_attributes() that is an array, will now be imploded with spaces between. 'class' => array('first', 'last') will become class="first last"
  2. Adds simpletests to test all of drupal_attributes() functionality.
  3. Removes checking for a valid parameter. Before the patch, you could pass NULL or a string to drupal_attributes() instead of an array() and drupal_attributes() would ignore the invalid parameter. After the patch, passing an invalid parameter is a bug.
  4. Fixes theme_image() and theme_image_style() because they were buggy per #3 above.
AttachmentSizeStatusTest resultOperations
drupal-attributes-493746-18.patch7.61 KBIdleFailed: Failed to apply patch.View details

#19

ultimateboy - July 15, 2009 - 02:34
Status:needs review» reviewed & tested by the community

I like the additions added by JohnAlbin and the tests look good. I'd say this is good to go.

#20

Dries - July 15, 2009 - 17:40
Status:reviewed & tested by the community» fixed

Committed to CVS HEAD. Thanks.

#21

Dave Reid - July 15, 2009 - 18:23

Ooh let's expand this further. :)

- Adds typehinting to the function so it truly errors if NULL is passed.
- Refactors the function to just plain make it prettier.

AttachmentSizeStatusTest resultOperations
493746-followup-D7.patch959 bytesIdleFailed: 11640 passes, 50 fails, 32 exceptionsView details

#22

Dave Reid - July 15, 2009 - 18:23
Status:fixed» needs review

#23

moshe weitzman - July 15, 2009 - 18:27

why &$data instead of $data?

#24

Dave Reid - July 15, 2009 - 18:31

Because we alter that variable and existing array so we can just do implode(' ', $attributes) at the end instead of creating another variable. It's minor at best.

#25

System Message - July 15, 2009 - 18:41
Status:needs review» needs work

The last submitted patch failed testing.

#26

Dave Reid - July 15, 2009 - 19:05
Status:needs work» needs review

Suppose it would have been good to actually test the followup patch.

AttachmentSizeStatusTest resultOperations
493746-followup-D7.patch984 bytesIdlePassed: 11835 passes, 0 fails, 0 exceptionsView details

#27

joshmiller - July 19, 2009 - 14:59
Status:needs review» reviewed & tested by the community

Adds typehinting to the function so it truly errors if NULL is passed.

Excellent, minor change.

Refactors the function to just plain make it prettier.

The re-write is much more elegant.

I'd say this could be committed... minor changes...

#28

System Message - July 23, 2009 - 07:04
Status:reviewed & tested by the community» needs work

The last submitted patch failed testing.

#29

deekayen - July 23, 2009 - 07:05
Status:needs work» reviewed & tested by the community

bad trial run of new testing bot

#30

JohnAlbin - July 27, 2009 - 17:35
Assigned to:moshe weitzman» Anonymous
Issue tags:+Quick fix

RTBC + 1 on the current patch.

Also, regarding the already-committed patch, it isn't going to help much unless we actually go through all of Drupal’s code and make all 'class' implementations into arrays.

Otherwise, at any given point, we won't know if 'class' is an array or a string. And we will just end up changing this awkward code:

<?php
   
if (isset($options['attributes']['class'])) {
     
$options['attributes']['class'] .= ' active';
    }
    else {
     
$options['attributes']['class'] = 'active';
    }
?>

with this awkward code:

<?php
   
if (!isset($options['attributes']['class']) || is_array($options['attributes']['class'])) {
     
$options['attributes']['class'][] = 'active';
    }
    else {
     
$options['attributes']['class'] = array($options['attributes']['class'], 'active');
    }
?>

Which, you may notice, is actually longer then the previous awkward code.

I've got a half-implemented patch that starts on this conversion which I'll post after the one in #26 goes in.

#31

JohnAlbin - July 27, 2009 - 22:11

I just moved my follow-up for this issue to #326539: Convert 'class' attribute to use an array, not a string. The patch in #26 is still RTBC. :-)

#32

Dries - July 28, 2009 - 19:22
Status:reviewed & tested by the community» needs work

Committed #26 to CVS HEAD. Has this been documented yet in the upgrade instructions? If so, please mark this fixed. If not, document it before marking this fixed. Thanks!

#33

ultimateboy - July 29, 2009 - 18:34
Status:needs work» fixed

This particular issue does not require any upgrade instructions as it doesnt alter any functionality.. #326539: Convert 'class' attribute to use an array, not a string will simply be a change in coding standards. Marking as fixed. Docs change will be associated with the classes to array change.

#34

System Message - August 12, 2009 - 18:40
Status:fixed» closed

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

 
 

Drupal is a registered trademark of Dries Buytaert.