/**
  * Normalize the attributes
  *
  * @param GroupInterface $group
  *
  * @return array
  */
 protected function normalizeAxisAttributes(GroupInterface $group)
 {
     $attributes = array();
     foreach ($group->getAxisAttributes() as $attribute) {
         $attributes[] = $attribute->getCode();
     }
     sort($attributes);
     return $attributes;
 }
 /**
  * @param VariantGroupAxis $constraint
  * @param GroupInterface   $variantGroup
  */
 protected function validateAttributeAxis(VariantGroupAxis $constraint, GroupInterface $variantGroup)
 {
     $allowedTypes = [AttributeTypes::OPTION_SIMPLE_SELECT, AttributeTypes::REFERENCE_DATA_SIMPLE_SELECT];
     foreach ($variantGroup->getAxisAttributes() as $attribute) {
         if (!in_array($attribute->getAttributeType(), $allowedTypes)) {
             $this->addInvalidAxisViolation($constraint, $variantGroup->getCode(), $attribute->getCode());
         }
     }
 }
 function it_throws_an_error_if_axis_is_updated(GroupInterface $variantGroup)
 {
     $variantGroup->setCode('mycode')->shouldBeCalled();
     $variantGroup->getId()->willReturn(42);
     $attribute = new Attribute();
     $attribute->setCode('other');
     $variantGroup->getAxisAttributes()->willReturn(new ArrayCollection([$attribute]));
     $values = ['code' => 'mycode', 'axis' => ['main_color']];
     $this->shouldThrow(new \InvalidArgumentException('Attributes: This property cannot be changed.'))->during('update', [$variantGroup, $values, []]);
 }
 /**
  * Get missing axis codes of a product given a variant group
  *
  * @param ProductInterface $product
  * @param GroupInterface   $variantGroup
  *
  * @return array
  */
 protected function getMissingAxisCodes(ProductInterface $product, GroupInterface $variantGroup)
 {
     $missingAxisCodes = [];
     foreach ($variantGroup->getAxisAttributes() as $attribute) {
         $value = $product->getValue($attribute->getCode());
         if (null === $value || null === $value->getData()) {
             $missingAxisCodes[] = $attribute->getCode();
         }
     }
     return $missingAxisCodes;
 }
 function it_adds_a_violation_if_a_group_contains_axis_attributes($context, GroupInterface $group, GroupType $type, VariantGroupAxis $constraint, AttributeInterface $axis)
 {
     $group->getId()->willReturn(null);
     $group->getType()->willReturn($type);
     $group->getCode()->willReturn('xsell');
     $type->isVariant()->willReturn(false);
     $group->getAxisAttributes()->willReturn([$axis]);
     $violationData = ['%group%' => 'xsell'];
     $context->addViolation($constraint->unexpectedAxisMessage, $violationData)->shouldBeCalled();
     $this->validate($group, $constraint);
 }
 function it_returns_non_eligible_attributes($attributeRepository, GroupInterface $group, ProductTemplateInterface $template, AttributeInterface $length, AttributeInterface $name, AttributeInterface $color, AttributeInterface $identifier, Collection $collection)
 {
     $group->getProductTemplate()->willReturn($template);
     $group->getAxisAttributes()->willReturn($collection);
     $collection->toArray()->willReturn([$length]);
     $template->getValuesData()->willReturn(['name' => 'foo', 'color' => 'bar']);
     $attributeRepository->findOneByIdentifier('name')->willReturn($name);
     $attributeRepository->findOneByIdentifier('color')->willReturn($color);
     $attributeRepository->findBy(['unique' => true])->willReturn([$name, $identifier]);
     $attributes = [$length, $name, $color, $identifier];
     $this->getNonEligibleAttributes($group)->shouldReturn($attributes);
 }
 function it_adds_a_violation_if_axis_attributes_are_invalid($context, GroupInterface $variantGroup, GroupType $type, VariantGroupAxis $constraint, ConstraintViolationBuilderInterface $violation, AttributeInterface $invalidAxis)
 {
     $variantGroup->getId()->willReturn(12);
     $variantGroup->getType()->willReturn($type);
     $variantGroup->getCode()->willReturn('tshirt');
     $type->isVariant()->willReturn(true);
     $variantGroup->getAxisAttributes()->willReturn([$invalidAxis]);
     $invalidAxis->getAttributeType()->willReturn(AttributeTypes::TEXT);
     $invalidAxis->getCode()->willReturn('name');
     $violationData = ['%group%' => 'tshirt', '%attribute%' => 'name'];
     $context->buildViolation($constraint->invalidAxisMessage, $violationData)->shouldBeCalled()->willReturn($violation);
     $this->validate($variantGroup, $constraint);
 }
 /**
  * Validate variant group product template values
  *
  * @param GroupInterface $variantGroup
  * @param Constraint     $constraint
  */
 protected function validateProductTemplateValues(GroupInterface $variantGroup, Constraint $constraint)
 {
     $template = $variantGroup->getProductTemplate();
     $valuesData = $template->getValuesData();
     $forbiddenAttrCodes = $this->attributeRepository->findUniqueAttributeCodes();
     foreach ($variantGroup->getAxisAttributes() as $axisAttribute) {
         $forbiddenAttrCodes[] = $axisAttribute->getCode();
     }
     $invalidAttrCodes = array_intersect($forbiddenAttrCodes, array_keys($valuesData));
     if (count($invalidAttrCodes) > 0) {
         $this->context->addViolation($constraint->message, array('%group%' => $variantGroup->getCode(), '%attributes%' => $this->formatValues($invalidAttrCodes)));
     }
 }
 function it_adds_a_violation_when_validates_a_product_with_missing_value_for_an_axe_of_its_variant_group($context, ProductInterface $product, GroupInterface $tShirtVariantGroup, AttributeInterface $sizeAttribute, AttributeInterface $colorAttribute, ProductValueInterface $sizeValue, ProductValueInterface $identifierValue, HasVariantAxes $constraint, ConstraintViolationBuilderInterface $violation)
 {
     $tShirtVariantGroup->getCode()->willReturn('tshirt');
     $tShirtVariantGroup->getAxisAttributes()->willReturn([$sizeAttribute, $colorAttribute]);
     $sizeAttribute->getCode()->willReturn('size');
     $colorAttribute->getCode()->willReturn('color');
     $product->getIdentifier()->willReturn($identifierValue);
     $product->getVariantGroup()->willReturn($tShirtVariantGroup);
     $product->getValue('size')->willReturn($sizeValue);
     $product->getValue('color')->willReturn(null);
     $sizeValue->getData()->willReturn('XL');
     $context->buildViolation('The product "%product%" is in the variant group "%variant%" but it misses the following axes: %axes%.', ['%product%' => $identifierValue, '%variant%' => 'tshirt', '%axes%' => 'color'])->shouldBeCalled()->willReturn($violation);
     $this->validate($product, $constraint);
 }
 function it_adds_a_violation_if_variant_group_template_contains_a_unique_attribute(GroupInterface $variantGroup, GroupType $type, ProductTemplateInterface $template, VariantGroupValues $constraint, $attributeRepository, $context)
 {
     $variantGroup->getType()->willReturn($type);
     $variantGroup->getCode()->willReturn('tshirt');
     $type->isVariant()->willReturn(true);
     $variantGroup->getProductTemplate()->willReturn($template);
     $variantGroup->getAxisAttributes()->willReturn([]);
     $attributeRepository->findUniqueAttributeCodes()->willReturn(['sku', 'barcode']);
     $template->getValuesData()->willReturn(['sku' => 'SKU-001']);
     $violationData = ['%group%' => 'tshirt', '%attributes%' => '"sku"'];
     $context->addViolation($constraint->message, $violationData)->shouldBeCalled();
     $this->validate($variantGroup, $constraint);
     $template->getValuesData()->willReturn(['sku' => 'SKU-001', 'barcode' => 01122334455]);
     $violationData = ['%group%' => 'tshirt', '%attributes%' => '"sku", "barcode"'];
     $context->addViolation($constraint->message, $violationData)->shouldBeCalled();
     $this->validate($variantGroup, $constraint);
 }
 /**
  * Get non eligible attributes to a product template
  *
  * @param GroupInterface $group
  *
  * @return AttributeInterface[]
  */
 public function getNonEligibleAttributes(GroupInterface $variantGroup)
 {
     $attributes = $variantGroup->getAxisAttributes()->toArray();
     $template = $variantGroup->getProductTemplate();
     if (null !== $template) {
         foreach (array_keys($template->getValuesData()) as $attributeCode) {
             $attributes[] = $this->attributeRepository->findOneByIdentifier($attributeCode);
         }
     }
     $uniqueAttributes = $this->attributeRepository->findBy(['unique' => true]);
     foreach ($uniqueAttributes as $attribute) {
         if (!in_array($attribute, $attributes)) {
             $attributes[] = $attribute;
         }
     }
     return $attributes;
 }
 /**
  * @param GroupInterface $variantGroup
  * @param array          $axes
  *
  * @throws \InvalidArgumentException
  */
 protected function setAxes(GroupInterface $variantGroup, array $axes)
 {
     if (null !== $variantGroup->getId()) {
         if (array_diff($this->getOriginalAxes($variantGroup->getAxisAttributes()), array_values($axes))) {
             throw new \InvalidArgumentException('Attributes: This property cannot be changed.');
         }
     }
     foreach ($axes as $axis) {
         $attribute = $this->attributeRepository->findOneByIdentifier($axis);
         if (null !== $attribute) {
             $variantGroup->addAxisAttribute($attribute);
         } else {
             throw new \InvalidArgumentException(sprintf('Attribute "%s" does not exist', $axis));
         }
     }
 }
 /**
  * @param GroupInterface $variantGroup
  *
  * @return array
  */
 protected function getAxisAttributeCodes($variantGroup)
 {
     $axisAttributes = $variantGroup->getAxisAttributes();
     $axisAttributeCodes = [];
     foreach ($axisAttributes as $axisAttribute) {
         $axisAttributeCodes[] = $axisAttribute->getCode();
     }
     return $axisAttributeCodes;
 }
 /**
  * Prepare query criteria for variant group
  *
  * @param GroupInterface   $variantGroup
  * @param ProductInterface $product
  * @param Constraint       $constraint
  *
  * @return array
  */
 protected function prepareQueryCriterias(GroupInterface $variantGroup, ProductInterface $product, Constraint $constraint)
 {
     $criteria = array();
     foreach ($variantGroup->getAxisAttributes() as $attribute) {
         $value = $product->getValue($attribute->getCode());
         // we don't add criteria when option is null, as this check is performed by HasVariantAxesValidator
         if (null !== $value && null !== $value->getOption()) {
             $criteria[] = ['attribute' => $attribute, 'option' => $value->getOption()];
         } else {
             $this->addEmptyAxisViolation($constraint, $variantGroup->getLabel(), $product->getIdentifier()->getVarchar(), $attribute->getCode());
         }
     }
     return $criteria;
 }
 function it_is_not_attribute_removable_with_group_containing_attribute(AttributeInterface $attribute, GroupInterface $group, GroupTypeInterface $groupType, ArrayCollection $groupAttributes)
 {
     $groupType->isVariant()->willReturn(true);
     $groupAttributes->contains($attribute)->willReturn(true);
     $group->getType()->willReturn($groupType);
     $group->getAxisAttributes()->willReturn($groupAttributes);
     $group->addProduct($this)->willReturn($this);
     $this->addGroup($group);
     $this->isAttributeRemovable($attribute)->shouldReturn(false);
 }
 function it_adds_a_violation_when_validating_product_in_groups_with_non_unique_combination_of_axis_attributes($context, $productRepository, GroupInterface $tShirtVariantGroup, GroupTypeInterface $tShirtGroupType, GroupInterface $clothesVariantGroup, GroupTypeInterface $clothesGroupType, ProductInterface $redTShirtProduct, AttributeInterface $sizeAttribute, AttributeInterface $colorAttribute, ProductValueInterface $sizeProductValue, ProductValueInterface $colorProductValue, ProductInterface $redTShirtProduct2, UniqueVariantAxis $uniqueVariantAxisConstraint)
 {
     $redTShirtProduct->getGroups()->willReturn([$tShirtVariantGroup, $clothesVariantGroup]);
     $tShirtVariantGroup->getId()->willReturn(1);
     $tShirtVariantGroup->getLabel()->willReturn('TShirts');
     $tShirtVariantGroup->getType()->willReturn($tShirtGroupType);
     $tShirtGroupType->isVariant()->willReturn(true);
     $tShirtVariantGroup->getAxisAttributes()->willReturn([$sizeAttribute, $colorAttribute]);
     $clothesVariantGroup->getId()->willReturn(2);
     $clothesVariantGroup->getLabel()->willReturn('Clothes');
     $clothesVariantGroup->getType()->willReturn($clothesGroupType);
     $clothesGroupType->isVariant()->willReturn(true);
     $clothesVariantGroup->getAxisAttributes()->willReturn([$sizeAttribute, $colorAttribute]);
     $sizeAttribute->getCode()->willReturn('size');
     $colorAttribute->getCode()->willReturn('color');
     $redTShirtProduct->getValue('size')->willReturn($sizeProductValue);
     $redTShirtProduct->getValue('color')->willReturn($colorProductValue);
     $redTShirtProduct->getId()->willReturn(1);
     $sizeProductValue->getOption()->willReturn('XL');
     $colorProductValue->getOption()->willReturn('Red');
     $redTShirtProduct2->getGroups()->willReturn([$clothesVariantGroup]);
     $redTShirtProduct2->getValue('size')->willReturn($sizeProductValue);
     $redTShirtProduct2->getValue('color')->willReturn($colorProductValue);
     $redTShirtProduct2->getId()->willReturn(2);
     $criteria = [['attribute' => $sizeAttribute, 'option' => 'XL'], ['attribute' => $colorAttribute, 'option' => 'Red']];
     $productRepository->findAllForVariantGroup($tShirtVariantGroup, $criteria)->willReturn([]);
     $productRepository->findAllForVariantGroup($clothesVariantGroup, $criteria)->willReturn([$redTShirtProduct2]);
     $context->addViolation('Group "%variant group%" already contains another product with values "%values%"', ['%variant group%' => 'Clothes', '%values%' => 'size: XL, color: Red'])->shouldBeCalled();
     $this->validate($redTShirtProduct, $uniqueVariantAxisConstraint);
 }
 /**
  * Prepare query criteria for variant group
  *
  * @param GroupInterface   $variantGroup
  * @param ProductInterface $product
  *
  * @return array
  */
 protected function prepareQueryCriterias(GroupInterface $variantGroup, ProductInterface $product)
 {
     $criteria = array();
     foreach ($variantGroup->getAxisAttributes() as $attribute) {
         $value = $product->getValue($attribute->getCode());
         // we don't add criteria when option is null, as this check is performed by HasVariantAxesValidator
         if (null !== $value && null !== $value->getOption()) {
             $criteria[] = ['attribute' => $attribute, 'option' => $value->getOption()];
         }
     }
     return $criteria;
 }
 /**
  * Prepare query criteria for variant group
  *
  * @param GroupInterface   $variantGroup
  * @param ProductInterface $product
  * @param Constraint       $constraint
  *
  * @return array
  */
 protected function prepareQueryCriterias(GroupInterface $variantGroup, ProductInterface $product, Constraint $constraint)
 {
     $criteria = [];
     foreach ($variantGroup->getAxisAttributes() as $attribute) {
         $value = $product->getValue($attribute->getCode());
         // we don't add criteria when option is null, as this check is performed by HasVariantAxesValidator
         if (null === $value || null === $value->getOption() && !$attribute->isBackendTypeReferenceData()) {
             $this->addEmptyAxisViolation($constraint, $variantGroup->getLabel(), $product->getIdentifier()->getVarchar(), $attribute->getCode());
             continue;
         }
         $current = ['attribute' => $attribute];
         if (null !== $value->getOption()) {
             $current['option'] = $value->getOption();
         } elseif ($attribute->isBackendTypeReferenceData()) {
             $current['referenceData'] = ['name' => $attribute->getReferenceDataName(), 'data' => $value->getData()];
         }
         $criteria[] = $current;
     }
     return $criteria;
 }
 function it_does_not_add_violation_when_validating_product_in_groups_with_unique_combination_of_axis_attributes($context, $productRepository, GroupInterface $tShirtVariantGroup, GroupTypeInterface $tShirtGroupType, ProductInterface $redTShirtProduct, AttributeInterface $sizeAttribute, AttributeInterface $colorAttribute, ProductValueInterface $sizeProductValue, ProductValueInterface $redColorProductValue, UniqueVariantAxis $uniqueVariantAxisConstraint)
 {
     $tShirtVariantGroup->getId()->willReturn(1);
     $tShirtVariantGroup->getLabel()->willReturn('TShirts');
     $tShirtVariantGroup->getType()->willReturn($tShirtGroupType);
     $tShirtGroupType->isVariant()->willReturn(true);
     $tShirtVariantGroup->getAxisAttributes()->willReturn([$sizeAttribute, $colorAttribute]);
     $sizeAttribute->getCode()->willReturn('size');
     $sizeAttribute->isBackendTypeReferenceData()->willReturn(false);
     $colorAttribute->getCode()->willReturn('color');
     $colorAttribute->isBackendTypeReferenceData()->willReturn(false);
     $redTShirtProduct->getVariantGroup()->willReturn($tShirtVariantGroup);
     $redTShirtProduct->getId()->willReturn(1);
     $redTShirtProduct->getValue('size')->willReturn($sizeProductValue);
     $redTShirtProduct->getValue('color')->willReturn($redColorProductValue);
     $sizeProductValue->getOption()->willReturn('XL');
     $redColorProductValue->getOption()->willReturn('Red');
     $criteria = [['attribute' => $sizeAttribute, 'option' => 'XL'], ['attribute' => $colorAttribute, 'option' => 'Red']];
     $productRepository->findAllForVariantGroup($tShirtVariantGroup, $criteria)->willReturn([]);
     $context->buildViolation()->shouldNotBeCalled(Argument::cetera());
     $this->validate($redTShirtProduct, $uniqueVariantAxisConstraint);
 }