You are here

function commerce_product_reference_entity_view in Commerce Core 7

Implements hook_entity_view().

This implementation adds product fields to the content array of an entity on display if the product contains a non-empty product reference field.

File

modules/product_reference/commerce_product_reference.module, line 318
Defines a field type for referencing products from other entities.

Code

function commerce_product_reference_entity_view($entity, $entity_type, $view_mode, $langcode) {
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  $instances = NULL;
  if ($entity_type == 'commerce_line_item' || $entity_type == 'commerce_product') {

    // We do not currently support the injection of product fields into the
    // display of line items or other products.
    return;
  }

  // Determine if the referencing bundle specifies custom settings
  // for the view mode currently displayed.
  $bundle_settings = field_bundle_settings($entity_type, $bundle);
  if (isset($bundle_settings['view_modes'][$view_mode]) && !empty($bundle_settings['view_modes'][$view_mode]['custom_settings'])) {
    $reference_view_mode = $view_mode;
  }
  else {
    $reference_view_mode = 'default';
  }

  // Don't try to perform the field injection by default.
  $perform_field_injection = FALSE;

  // Retrieve the real extra fields settings.
  $display = field_extra_fields_get_display($entity_type, $bundle, $reference_view_mode);
  if (!empty($display)) {

    // Loop over the extra fields and see if at least one of the injected field
    // is visible.
    foreach ($display as $key => $extra_field) {
      if (strpos($key, 'product:') !== 0) {
        continue;
      }
      if (!empty($extra_field['visible'])) {
        $perform_field_injection = TRUE;
        break;
      }
    }
  }

  // Stop here if we don't have any field to inject.
  if (!$perform_field_injection) {
    return;
  }

  // Resolve the product module path for use in the loop below.
  $product_module_path = drupal_get_path('module', 'commerce_product');

  // An entity metadata wrapper will be loaded on demand if it is determined
  // this entity has a product reference field instance attached to it.
  $wrapper = NULL;

  // Loop through product reference fields to see if any exist on this entity
  // bundle that is either hidden or displayed with the Add to Cart form display
  // formatter.
  foreach (commerce_info_fields('commerce_product_reference', $entity_type) as $field_name => $field) {

    // Load the instances array only if the entity has product reference fields.
    if (empty($instances)) {
      $instances = field_info_instances($entity_type, $bundle);
    }

    // If the reference field enables field injection.
    if (isset($instances[$field_name]) && !empty($instances[$field_name]['settings']['field_injection'])) {

      // If the field is missing a value, continue to next reference field.
      if (empty($entity->{$field_name})) {
        continue;
      }

      // Load a wrapper for the entity being viewed.
      if (empty($wrapper)) {
        $wrapper = entity_metadata_wrapper($entity_type, $entity)
          ->language($langcode);
      }

      // Fetch the product reference field value.
      $reference_field_value = $wrapper->{$field_name}
        ->value();

      // If this field doesn't reference any products, continue to the next one.
      if (empty($reference_field_value)) {
        continue;
      }

      // Find the default product based on the cardinality of the field.
      $product = NULL;
      if ($field['cardinality'] == 1) {

        // The value of single value reference fields is the product object.
        $product = $reference_field_value;
      }
      else {

        // Find the default from the array of all the referenced products.
        $product = commerce_product_reference_default_product($reference_field_value);

        // If the product is disabled, attempt to find one that is active and
        // use that as the default product instead.
        if (!empty($product) && $product->status == 0) {
          foreach ($reference_field_value as $reference_field_item) {
            if (!empty($reference_field_item) && $reference_field_item->status != 0) {
              $product = $reference_field_item;
              break;
            }
          }
        }
      }

      // If we found a product.
      if (!empty($product)) {

        // Add the display context for these field to the product.
        $product->display_context = array(
          'entity_type' => $entity_type,
          'entity_id' => $id,
          'entity' => $entity,
          'view_mode' => $view_mode,
          'language' => $langcode,
        );

        // Determine if the referenced product type specifies custom settings
        // for the reference view mode.
        $view_mode_settings = field_view_mode_settings('commerce_product', $product->type);
        if (!empty($view_mode_settings[$entity_type . '_' . $view_mode]['custom_settings'])) {
          $reference_view_mode = $entity_type . '_' . $view_mode;
        }
        else {
          $reference_view_mode = 'default';
        }

        // Loop through the fields on the referenced product's type.
        foreach (field_info_instances('commerce_product', $product->type) as $product_field_name => $product_field) {
          if (!isset($product_field['display'][$reference_view_mode])) {
            $reference_view_mode = 'default';
          }

          // Only prepare visible fields.
          if (!isset($product_field['display'][$reference_view_mode]['type']) || $product_field['display'][$reference_view_mode]['type'] != 'hidden') {

            // Add the product field to the entity's content array.
            $content_key = 'product:' . $product_field_name;
            $entity->content[$content_key] = field_view_field('commerce_product', $product, $product_field_name, $reference_view_mode, $langcode);

            // For multiple value references, add context information so the cart
            // form can do dynamic replacement of fields.
            if ($field['cardinality'] != 1) {

              // Construct an array of classes that will be used to theme and
              // target the rendered field for AJAX replacement.
              $classes = array(
                'commerce-product-field',
                drupal_html_class('commerce-product-field-' . $product_field_name),
                drupal_html_class('field-' . $product_field_name),
                drupal_html_class(implode('-', array(
                  $entity_type,
                  $id,
                  'product',
                  $product_field_name,
                ))),
              );

              // Add an extra class to distinguish empty product fields.
              if (empty($entity->content[$content_key])) {
                $classes[] = 'commerce-product-field-empty';
              }

              // Ensure the field's content array has a prefix and suffix key.
              $entity->content[$content_key] += array(
                '#prefix' => '',
                '#suffix' => '',
              );

              // Add the custom div before and after the prefix and suffix.
              $entity->content[$content_key]['#prefix'] = '<div class="' . implode(' ', $classes) . '">' . $entity->content[$content_key]['#prefix'];
              $entity->content[$content_key]['#suffix'] .= '</div>';
            }
          }
        }

        // Get the extra fields display settings for the current view mode.
        $display = field_extra_fields_get_display('commerce_product', $product->type, $reference_view_mode);

        // Attach "extra fields" to the bundle representing all the extra fields
        // currently attached to products.
        foreach (field_info_extra_fields('commerce_product', $product->type, 'display') as $product_extra_field_name => $product_extra_field) {

          // Only include extra fields that specify a theme function and that
          // are visible on the current view mode.
          if (!empty($product_extra_field['theme']) && !empty($display[$product_extra_field_name]['visible'])) {

            // Add the product extra field to the entity's content array.
            $content_key = 'product:' . $product_extra_field_name;
            $entity->content[$content_key] = array(
              '#theme' => $product_extra_field['theme'],
              '#' . $product_extra_field_name => $product->{$product_extra_field_name},
              '#label' => $product_extra_field['label'] . ':',
              '#product' => $product,
              '#attached' => array(
                'css' => array(
                  $product_module_path . '/theme/commerce_product.theme.css',
                ),
              ),
            );

            // For multiple value references, add context information so the cart
            // form can do dynamic replacement of fields.
            if ($field['cardinality'] != 1) {

              // Construct an array of classes that will be used to theme and
              // target the rendered field for AJAX replacement.
              $classes = array(
                'commerce-product-extra-field',
                drupal_html_class('commerce-product-extra-field-' . $product_extra_field_name),
                drupal_html_class(implode('-', array(
                  $entity_type,
                  $id,
                  'product',
                  $product_extra_field_name,
                ))),
              );

              // Add an extra class to distinguish empty fields.
              if (empty($entity->content[$content_key])) {
                $classes[] = 'commerce-product-extra-field-empty';
              }

              // Ensure the extra field's content array has a prefix and suffix key.
              $entity->content[$content_key] += array(
                '#prefix' => '',
                '#suffix' => '',
              );

              // Add the custom div before and after the prefix and suffix.
              $entity->content[$content_key]['#prefix'] = '<div class="' . implode(' ', $classes) . '">' . $entity->content[$content_key]['#prefix'];
              $entity->content[$content_key]['#suffix'] .= '</div>';
            }
          }
        }
      }
    }
  }
}