You are here

public function ProductVariationAttributeMapper::prepareAttributes in Commerce Core 8.2

Prepares the available attributes for the selected product variation.

The attribute and its values are retrieved in the language of the variation. Values not corresponding to any variation are removed.

Parameters

\Drupal\commerce_product\Entity\ProductVariationInterface $selected_variation: The selected product variation.

\Drupal\commerce_product\Entity\ProductVariationInterface[] $variations: The available product variations.

Return value

\Drupal\commerce_product\PreparedAttribute[] The prepared attributes, keyed by field name.

Overrides ProductVariationAttributeMapperInterface::prepareAttributes

File

modules/product/src/ProductVariationAttributeMapper.php, line 77

Class

ProductVariationAttributeMapper

Namespace

Drupal\commerce_product

Code

public function prepareAttributes(ProductVariationInterface $selected_variation, array $variations) {
  $attributes = [];
  $field_definitions = $this->attributeFieldManager
    ->getFieldDefinitions($selected_variation
    ->bundle());
  $field_map = $this->attributeFieldManager
    ->getFieldMap($selected_variation
    ->bundle());
  $field_names = array_column($field_map, 'field_name');
  $attribute_ids = array_column($field_map, 'attribute_id');
  $index = 0;
  foreach ($field_names as $field_name) {
    $field = $field_definitions[$field_name];

    /** @var \Drupal\commerce_product\Entity\ProductAttributeInterface $attribute */
    $attribute = $this->attributeStorage
      ->load($attribute_ids[$index]);

    // Make sure we have translation for attribute.
    $attribute = $this->entityRepository
      ->getTranslationFromContext($attribute, $selected_variation
      ->language()
      ->getId());
    $definition = [
      'id' => $attribute
        ->id(),
      'label' => $attribute
        ->label(),
      'element_type' => $attribute
        ->getElementType(),
      'required' => $field
        ->isRequired(),
    ];

    // The first attribute gets all values. Every next attribute gets only
    // the values from variations matching the previous attribute value.
    // For 'Color' and 'Size' attributes that means getting the colors of all
    // variations, but only the sizes of variations with the selected color.
    $callback = NULL;
    if ($index > 0) {
      $index_limit = $index - 1;

      // Get all previous field values.
      $previous_variation_field_values = [];
      for ($i = 0; $i <= $index_limit; $i++) {
        $previous_variation_field_values[$field_names[$i]] = $selected_variation
          ->getAttributeValueId($field_names[$i]);
      }
      $callback = function (ProductVariationInterface $variation) use ($previous_variation_field_values) {
        $results = [];
        foreach ($previous_variation_field_values as $previous_field_name => $previous_field_value) {
          $results[] = $variation
            ->getAttributeValueId($previous_field_name) == $previous_field_value;
        }
        return !in_array(FALSE, $results, TRUE);
      };
    }
    $definition['values'] = $this
      ->getAttributeValues($variations, $field_name, $callback);

    // Return the attribute only if it has at least one value.
    if (!empty($definition['values'])) {
      $attributes[$field_name] = new PreparedAttribute($definition);
    }
    $index++;
  }
  return $attributes;
}