There are a couple of issues with uc_attribute_order_product_alter()

for reference:

/**
 * Implemenation of hook_order_product_alter().
 */
function uc_attribute_order_product_alter(&$product, $order) {
  // Convert the attribute and option ids to their current names. This
  // preserves the important data in case the attributes or options are
  // changed later. 
  $key = key($product->data['attributes']);
  if (is_array($product->data['attributes']) && is_numeric(key($product->data['attributes']))) {
    $attributes = array();
    $options = _uc_cart_product_get_options($product);
    foreach ($options as $aid => $option) {
      $attributes[$option['attribute']][] = $option['name'];
    }
    $product->data['attributes'] = $attributes;
  }
}

Issue #1.

if (is_array($product->data['attributes']) && is_numeric(key($product->data['attributes']))) {

probably shouldnt use 'key' to determine whether or not these are numeric attributes, as key() relies on the array's internal pointer. If any other module has iterated over the product->data['attributes'] earlier on in any other hook or alter, the pointer is at the end of the array, and is_numeric() returns false, even though the numeric data is in the array, which ends up with numeric attributes and options stuck in the database, which then display to the user on the order forms.

Issue #2.
Probably a much bigger issue, and probably not that easy to address, is that saving over the attributes with user defined text severs any relationship the saved order has with its original attribute ID's. I understand why this is, so that if a customer orders a purple t-shirt, that when he looks at an order a year later, it still says purple t-shirt, even though the store admins changed the attribute to a more accurate and marketable "Grape" T-shirt.

The problem is that we no longer have attribute and option id's associated with the order once its saved, just the text that went with those orders. I suggest that we preserve these numeric aid/oid combos in addition to changing them to their text based counterparts by simply stuffing them in the data array.

i.e.

$product->data['numeric_attributes'] = $product->data['attributes'];
$product->data['attributes'] = $attributes;

Our particular use case is we are selling magazine subscriptions and need to pass the order data to our fulfillment house. An example attribute of "length of subscription" might have an option of "Two years at $24.95". In order to map the 'subscription' length to the field in our output data for the fulfillment house, I currently have to rely on the text "length of subscription" which is user facing, and likely to change as soon as somebody decides "subscription length" is how that attribute should read, and the option of "two years at 24.95" - I still need to translate into 'number of years * number of issues', which means I have to know that "Two years at $24.95" = 2, which isnt too bad considering the number of attributes that would require this sort of lookup table, however it means our users can never change the option labels to different text once this lookup table is in place. If we are at least keying off of the aid's and oid's the users would have the option to modify the text without affecting the underlying data export.

In an ideal world attributes and options would be entirely replaced with a paradigm like the way CCK or the Fieldsuc in D7 handles user configurable data, yet still makes it accessable and reusable.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

longwave’s picture

For #1, wouldn't reset() be a simpler replacement for key()? edit: no, reset() returns the value, which isn't useful here.

Keeping the numeric attributes for later reference would be useful. The changing structure of the $data['attributes'] array depending on whether the user is pre or post checkout is difficult to work with.

rbayliss’s picture

FileSize
600 bytes

For #2, Dealing with 2 different structures of attributes on order insert and order update is definitely a pain. Kind of reminds me of trying to use core taxonomy in hook_nodeapi(). Still, I'm sure there are modules that rely on this structure out there somewhere? If so, here is a minimally invasive fix that just stores the oid in place of the usual incrementing key.

TR’s picture

Status: Needs review » Needs work

Let's see what the testbot has to say ...

TR’s picture

Status: Needs work » Needs review
longwave’s picture

Status: Needs review » Needs work

Committed #2 to both branches. Back to needs work for #0.

longwave’s picture

Status: Needs work » Needs review
FileSize
811 bytes

#0 in git format

longwave’s picture

Status: Needs review » Fixed

#6 committed to both branches.

Status: Fixed » Closed (fixed)

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

mattcasey’s picture

Thanks! Just a caveat for anyone finding this that it is not included in 2.7.