function it_provides_formatted_batch_config_for_the_job(GroupInterface $oroTshirt)
 {
     $oroTshirt->getCode()->willReturn('oro_tshirt');
     $this->setGroup($oroTshirt);
     $this->setFilters([['id', 'IN', ['22', '7']]]);
     $this->getBatchConfig()->shouldReturn('{\\"filters\\":[[\\"id\\",\\"IN\\",[\\"22\\",\\"7\\"]]],\\"actions\\":{\\"field\\":\\"variant_group\\",\\"value\\":\\"oro_tshirt\\"}}');
 }
 function it_provides_formatted_batch_config_for_the_job(GroupInterface $oroTshirt)
 {
     $oroTshirt->getCode()->willReturn('oro_tshirt');
     $this->setGroup($oroTshirt);
     $this->setFilters([['id', 'IN', ['22', '7']]]);
     $this->getBatchConfig()->shouldReturn(['filters' => [['id', 'IN', ['22', '7']]], 'actions' => ['field' => 'variant_group', 'value' => 'oro_tshirt']]);
 }
 /**
  * @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_exception_if_media_of_variant_group_is_not_found($normalizer, $denormalizer, ArrayCollection $productValuesCollection, ArrayCollection $mediaCollection, ProductMediaInterface $media, GroupInterface $variantGroup, ProductTemplateInterface $productTemplate, ProductValueInterface $productValue)
 {
     $variantGroup->getProductTemplate()->willReturn($productTemplate);
     $variantGroup->getCode()->willReturn('my_variant_group');
     $productTemplate->getValuesData()->willReturn([$productValue]);
     $denormalizer->denormalize([$productValue], 'ProductValue[]', 'json')->willReturn($productValuesCollection);
     $productValuesCollection->filter(Argument::cetera())->willReturn($mediaCollection);
     $mediaCollection->toArray()->willReturn([$media]);
     $normalizer->normalize([$media], 'csv', ['field_name' => 'media', 'prepare_copy' => true, 'identifier' => 'my_variant_group'])->willThrow(new FileNotFoundException('upload/path/img.jpg'));
     $this->shouldThrow(new InvalidItemException('The file "upload/path/img.jpg" does not exist', ['item' => 'my_variant_group', 'uploadDirectory' => 'upload/path/']))->duringProcess($variantGroup);
 }
 /**
  * Fetch medias in local filesystem
  *
  * @param GroupInterface $variantGroup
  * @param string         $directory
  */
 protected function fetchMedia(GroupInterface $variantGroup, $directory)
 {
     if (null === ($productTemplate = $variantGroup->getProductTemplate())) {
         return;
     }
     $identifier = $variantGroup->getCode();
     $this->variantGroupUpdater->update($variantGroup, ['values' => $productTemplate->getValuesData()]);
     $this->mediaFetcher->fetchAll($productTemplate->getValues(), $directory, $identifier);
     foreach ($this->mediaFetcher->getErrors() as $error) {
         $this->stepExecution->addWarning($error['message'], [], new DataInvalidItem($error['media']));
     }
 }
 function it_provides_formatted_batch_config_for_the_job(GroupInterface $officeGroup, GroupInterface $bedroomGroup, ArrayCollection $groupCollection)
 {
     $officeGroup->getCode()->willReturn('office_room');
     $bedroomGroup->getCode()->willReturn('bedroom');
     $groupCollection->add($officeGroup);
     $groupCollection->add($bedroomGroup);
     $this->setGroups($groupCollection);
     $groupCollection->map(Argument::type('closure'))->willReturn($groupCollection);
     $groupCollection->toArray()->willReturn(['office_room', 'bedroom']);
     $this->setFilters([['id', 'IN', ['22', '7']]]);
     $this->getBatchConfig()->shouldReturn(['filters' => [['id', 'IN', ['22', '7']]], 'actions' => [['field' => 'groups', 'value' => ['office_room', 'bedroom']]]]);
 }
 function it_provides_formatted_batch_config_for_the_job(GroupInterface $officeGroup, GroupInterface $bedroomGroup, ArrayCollection $groupCollection)
 {
     $officeGroup->getCode()->willReturn('office_room');
     $bedroomGroup->getCode()->willReturn('bedroom');
     $groupCollection->add($officeGroup);
     $groupCollection->add($bedroomGroup);
     $this->setGroups($groupCollection);
     $groupCollection->map(Argument::type('closure'))->willReturn($groupCollection);
     $groupCollection->toArray()->willReturn(['office_room', 'bedroom']);
     $this->setFilters([['id', 'IN', ['22', '7']]]);
     $this->getBatchConfig()->shouldReturn('{\\"filters\\":[[\\"id\\",\\"IN\\",[\\"22\\",\\"7\\"]]],\\"actions\\":[{\\"field\\":\\"groups\\",\\"value\\":[\\"office_room\\",\\"bedroom\\"]}]}');
 }
 /**
  * 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->buildViolation($constraint->message, ['%group%' => $variantGroup->getCode(), '%attributes%' => $this->formatValues($invalidAttrCodes)])->addViolation();
     }
 }
 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);
 }
 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_normalizes_a_product_associations_in_standard_format_only(ProductInterface $product, AssociationInterface $association1, AssociationInterface $association2, AssociationTypeInterface $associationType1, AssociationTypeInterface $associationType2, GroupInterface $group1, ProductInterface $productAssociated)
 {
     $group1->getCode()->willReturn('group_code');
     $associationType1->getCode()->willReturn('XSELL');
     $association1->getAssociationType()->willReturn($associationType1);
     $association1->getGroups()->willReturn([$group1]);
     $association1->getProducts()->willReturn([]);
     $productAssociated->getReference()->willReturn('product_code');
     $associationType2->getCode()->willReturn('PACK');
     $association2->getAssociationType()->willReturn($associationType2);
     $association2->getGroups()->willReturn([]);
     $association2->getProducts()->willReturn([$productAssociated]);
     $product->getAssociations()->willReturn([$association1, $association2]);
     $this->normalize($product, 'standard')->shouldReturn(['PACK' => ['groups' => [], 'products' => ['product_code']], 'XSELL' => ['groups' => ['group_code'], 'products' => []]]);
 }
 /**
  * {@inheritdoc}
  *
  * @param GroupInterface $object
  */
 public function normalize($object, $format = null, array $context = [])
 {
     $results = ['code' => $object->getCode(), 'type' => $object->getType()->getCode()];
     $axisAttributes = $this->normalizeAxisAttributes($object);
     if (!empty($axisAttributes)) {
         $results += ['axis' => $axisAttributes];
     }
     $results += $this->transNormalizer->normalize($object, $format, $context);
     if (isset($context['versioning']) && true === $context['versioning']) {
         $context['with_variant_group_values'] = true;
     }
     if (isset($context['with_variant_group_values']) && true === $context['with_variant_group_values']) {
         $results['values'] = $this->normalizeVariantGroupValues($object, $format, $context);
     }
     return $results;
 }
 function it_saves_a_variant_group_and_copies_values_to_products($optionsResolver, $objectManager, $templateApplier, $eventDispatcher, GroupInterface $group, GroupType $type, ProductInterface $product, ProductTemplateInterface $template, ArrayCollection $products)
 {
     $optionsResolver->resolveSaveOptions(['copy_values_to_products' => true])->willReturn(['flush' => true, 'copy_values_to_products' => true, 'add_products' => [], 'remove_products' => []]);
     $group->getType()->willReturn($type);
     $group->getCode()->willReturn('my_code');
     $objectManager->persist($group)->shouldBeCalled();
     $objectManager->flush()->shouldBeCalled();
     $type->isVariant()->willReturn(true);
     $group->getProductTemplate()->willReturn($template);
     $group->getProducts()->willReturn($products);
     $products->toArray()->willReturn([$product]);
     $templateApplier->apply($template, [$product])->shouldBeCalled();
     $eventDispatcher->dispatch(StorageEvents::PRE_SAVE, Argument::cetera())->shouldBeCalled();
     $eventDispatcher->dispatch(StorageEvents::POST_SAVE, Argument::cetera())->shouldBeCalled();
     $this->save($group, ['copy_values_to_products' => true]);
 }
 function it_adds_a_violation_if_variant_group_template_contains_a_unique_attribute(GroupInterface $variantGroup, GroupType $type, ProductTemplateInterface $template, VariantGroupValues $constraint, $attributeRepository, $context, ConstraintViolationBuilderInterface $violation)
 {
     $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->buildViolation($constraint->message, $violationData)->shouldBeCalled()->willReturn($violation);
     $this->validate($variantGroup, $constraint);
     $template->getValuesData()->willReturn(['sku' => 'SKU-001', 'barcode' => 01122334455]);
     $violationData = ['%group%' => 'tshirt', '%attributes%' => '"sku", "barcode"'];
     $context->buildViolation($constraint->message, $violationData)->shouldBeCalled()->willReturn($violation);
     $this->validate($variantGroup, $constraint);
 }
 function it_normalizes_a_variant_group_with_its_values($transNormalizer, $valuesDenormalizer, $valuesNormalizer, GroupInterface $group, GroupTypeInterface $groupType, AttributeInterface $attr, ProductTemplateInterface $productTemplate)
 {
     $groupType->getCode()->willReturn('VARIANT');
     $groupType->isVariant()->willReturn(true);
     $group->getCode()->willReturn('laser_sabers');
     $valuesData = ['name' => 'Light saber model', 'size' => '120'];
     $context = ['with_variant_group_values' => true];
     $format = 'csv';
     $productTemplate->getValuesData()->willReturn($valuesData);
     $valuesDenormalizer->denormalize($valuesData, Argument::any(), Argument::any())->willReturn('denormalized_values');
     $valuesNormalizer->normalize('denormalized_values', Argument::any(), Argument::any())->willReturn('normalized_values');
     $group->getProductTemplate()->willReturn($productTemplate);
     $group->getType()->willReturn($groupType);
     $attr->getCode()->willReturn('light_color');
     $group->getAxisAttributes()->willReturn([$attr]);
     $transNormalizer->normalize($group, $format, $context)->willReturn([]);
     $this->normalize($group, $format, $context)->shouldReturn(['code' => 'laser_sabers', 'type' => 'VARIANT', 'axis' => ['light_color'], 'values' => 'normalized_values']);
 }
 function it_normalizes_the_associations_of_the_product(ProductInterface $product, AssociationInterface $association1, AssociationInterface $association2, AssociationTypeInterface $type1, AssociationTypeInterface $type2, ProductInterface $productAssociated1, ProductInterface $productAssociated2, ProductInterface $productAssociated3, GroupInterface $groupAssociated1, GroupInterface $groupAssociated2)
 {
     $type1->getCode()->willReturn('wahou the type');
     $type2->getCode()->willReturn('such a type');
     $groupAssociated1->getCode()->willReturn('group 1');
     $groupAssociated2->getCode()->willReturn('group 2');
     $productAssociated1->getReference()->willReturn('product 1');
     $productAssociated2->getReference()->willReturn('product 2');
     $productAssociated3->getReference()->willReturn('product 3');
     $association1->getAssociationType()->willReturn($type1);
     $association2->getAssociationType()->willReturn($type2);
     $association1->getGroups()->willReturn([$groupAssociated1]);
     $association2->getGroups()->willReturn([$groupAssociated1, $groupAssociated2]);
     $association1->getProducts()->willReturn([]);
     $association2->getProducts()->willReturn([$productAssociated1, $productAssociated2, $productAssociated3]);
     $product->getAssociations()->willReturn([$association1, $association2]);
     $this->normalize($product, 'json')->shouldReturn(['such a type' => ['groups' => ['group 1', 'group 2'], 'products' => ['product 1', 'product 2', 'product 3']], 'wahou the type' => ['groups' => ['group 1'], 'products' => []]]);
 }
 function it_normalizes_product_with_associations($filter, ProductInterface $product, AttributeInterface $skuAttribute, ProductValueInterface $sku, Association $myCrossSell, AssociationTypeInterface $crossSell, Association $myUpSell, AssociationTypeInterface $upSell, GroupInterface $associatedGroup1, GroupInterface $associatedGroup2, ProductInterface $associatedProduct1, ProductInterface $associatedProduct2, ProductValueInterface $skuAssocProduct1, ProductValueInterface $skuAssocProduct2, Collection $values, FamilyInterface $family, $serializer)
 {
     $family->getCode()->willReturn('shoes');
     $skuAttribute->getCode()->willReturn('sku');
     $skuAttribute->getAttributeType()->willReturn('pim_catalog_identifier');
     $skuAttribute->isLocalizable()->willReturn(false);
     $skuAttribute->isScopable()->willReturn(false);
     $sku->getAttribute()->willReturn($skuAttribute);
     $sku->getData()->willReturn('sku-001');
     $crossSell->getCode()->willReturn('cross_sell');
     $myCrossSell->getAssociationType()->willReturn($crossSell);
     $myCrossSell->getGroups()->willReturn([]);
     $myCrossSell->getProducts()->willReturn([]);
     $upSell->getCode()->willReturn('up_sell');
     $myUpSell->getAssociationType()->willReturn($upSell);
     $associatedGroup1->getCode()->willReturn('associated_group1');
     $associatedGroup2->getCode()->willReturn('associated_group2');
     $myUpSell->getGroups()->willReturn([$associatedGroup1, $associatedGroup2]);
     $skuAssocProduct1->getAttribute()->willReturn($skuAttribute);
     $skuAssocProduct2->getAttribute()->willReturn($skuAttribute);
     $skuAssocProduct1->__toString()->willReturn('sku_assoc_product1');
     $skuAssocProduct2->__toString()->willReturn('sku_assoc_product2');
     $associatedProduct1->getIdentifier()->willReturn($skuAssocProduct1);
     $associatedProduct2->getIdentifier()->willReturn($skuAssocProduct2);
     $myUpSell->getProducts()->willReturn([$associatedProduct1, $associatedProduct2]);
     $product->getIdentifier()->willReturn($sku);
     $product->getFamily()->willReturn($family);
     $product->isEnabled()->willReturn(true);
     $product->getGroupCodes()->willReturn(['group1,group2', 'variant_group_1']);
     $product->getCategoryCodes()->willReturn(['nice shoes', 'converse']);
     $product->getAssociations()->willReturn([$myCrossSell, $myUpSell]);
     $product->getValues()->willReturn($values);
     $filter->filterCollection($values, 'pim.transform.product_value.flat', Argument::cetera())->willReturn([$sku]);
     $serializer->normalize($sku, 'flat', Argument::any())->willReturn(['sku' => 'sku-001']);
     $this->normalize($product, 'flat', [])->shouldReturn(['sku' => 'sku-001', 'family' => 'shoes', 'groups' => 'group1,group2,variant_group_1', 'categories' => 'nice shoes,converse', 'cross_sell-groups' => '', 'cross_sell-products' => '', 'up_sell-groups' => 'associated_group1,associated_group2', 'up_sell-products' => 'sku_assoc_product1,sku_assoc_product2', 'enabled' => 1]);
 }
 /**
  * Returns the attribute codes for a group
  *
  * @param GroupInterface $group
  *
  * @return array
  */
 protected function getGroupAttributeCodes(GroupInterface $group)
 {
     $code = $group->getCode();
     if (!isset($this->groupAttributeCodes[$code])) {
         $this->groupAttributeCodes[$code] = $this->getAttributeCodes($group);
     }
     return $this->groupAttributeCodes[$code];
 }
 /**
  * Prepares media files present in the product template of the variant group for export.
  * Returns an array of files to be copied from 'filePath' to 'exportPath'.
  *
  * @param GroupInterface $group
  *
  * @throws InvalidItemException If a media file is not found
  *
  * @return array
  */
 protected function prepareVariantGroupMedia(GroupInterface $group)
 {
     $mediaValues = $this->getProductTemplateMediaValues($group->getProductTemplate());
     if (count($mediaValues) < 1) {
         return [];
     }
     try {
         return $this->normalizer->normalize($mediaValues, $this->format, ['field_name' => 'media', 'prepare_copy' => true, 'identifier' => $group->getCode()]);
     } catch (FileNotFoundException $e) {
         throw new InvalidItemException($e->getMessage(), ['item' => $group->getCode(), 'uploadDirectory' => $this->uploadDirectory]);
     }
 }
 function it_normalizes_group($normalizer, GroupInterface $group)
 {
     $group->getCode()->willReturn('mongo');
     $normalizer->normalize($group, 'mongodb_json', [])->willReturn(['label' => 'translations']);
     $this->normalize($group, 'mongodb_json', [])->shouldReturn(['code' => 'mongo', 'label' => 'translations']);
 }
 /**
  * @param GroupInterface $group
  *
  * @Given /^I should be on the ("([^"]*)" variant group) page$/
  */
 public function iShouldBeOnTheVariantGroupPage(GroupInterface $group)
 {
     $expectedAddress = $this->getPage('VariantGroup edit')->getUrl(['code' => $group->getCode()]);
     $this->getNavigationContext()->assertAddress($expectedAddress);
 }
 function it_normalizes_a_variant_group_with_its_values_on_versioning_context($transNormalizer, $valuesDenormalizer, GroupInterface $group, CustomSerializer $serializer, GroupTypeInterface $groupType, AttributeInterface $attr, ProductTemplateInterface $productTemplate, ProductValueInterface $productValue1)
 {
     $groupType->getCode()->willReturn('VARIANT');
     $groupType->isVariant()->willReturn(true);
     $group->getCode()->willReturn('lego');
     $valuesData = ['name' => 'Light saber model', 'size' => '120'];
     $context = ['versioning' => true];
     $format = 'csv';
     $productTemplate->getValuesData()->willReturn($valuesData);
     $valuesDenormalizer->denormalize($valuesData, 'ProductValue[]', 'json')->willReturn([$productValue1]);
     $newContext = array_merge($context, ['with_variant_group_values' => true]);
     $serializer->normalize($productValue1, $format, ['entity' => 'product'] + $newContext)->willReturn(['age' => '6+']);
     $group->getProductTemplate()->willReturn($productTemplate);
     $group->getType()->willReturn($groupType);
     $attr->getCode()->willReturn('model');
     $group->getAxisAttributes()->willReturn([$attr]);
     $transNormalizer->normalize($group, $format, $context)->willReturn([]);
     $this->setSerializer($serializer);
     $this->normalize($group, $format, $context)->shouldReturn(['code' => 'lego', 'type' => 'VARIANT', 'axis' => 'model', 'age' => '6+']);
 }
示例#23
0
 /**
  * @param GroupInterface $group
  * @param string         $type
  *
  * @throws \InvalidArgumentException
  */
 protected function setType(GroupInterface $group, $type)
 {
     $groupType = $this->groupTypeRepository->findOneByIdentifier($type);
     if (null === $groupType) {
         throw new \InvalidArgumentException(sprintf('Type "%s" does not exist', $type));
     }
     if ($groupType->isVariant()) {
         throw new \InvalidArgumentException(sprintf('Cannot process variant group "%s", only groups are accepted', $group->getCode()));
     }
     $group->setType($groupType);
 }
 function it_throws_an_exception_if_media_of_variant_group_is_not_found($objectDetacher, $normalizer, $mediaFetcher, $stepExecution, $variantGroupUpdater, ArrayCollection $productValueCollection, FileInfoInterface $media1, FileInfoInterface $media2, GroupInterface $variantGroup, ProductTemplateInterface $productTemplate, ProductValueInterface $productValue1, ProductValueInterface $productValue2, JobParameters $jobParameters, JobExecution $jobExecution, JobInstance $jobInstance, ExecutionContext $executionContext)
 {
     $stepExecution->getJobParameters()->willReturn($jobParameters);
     $jobParameters->get('filePath')->willReturn('my/path/variant_group.csv');
     $jobParameters->has('with_media')->willReturn(true);
     $jobParameters->get('with_media')->willReturn(true);
     $variantGroup->getProductTemplate()->willReturn($productTemplate);
     $variantGroup->getCode()->willReturn('my_variant_group');
     $productValueCollection->toArray()->willReturn([$productValue1, $productValue2]);
     $productValue1->setMedia($media1);
     $productValue2->setMedia($media2);
     $stepExecution->getJobExecution()->willReturn($jobExecution);
     $jobExecution->getJobInstance()->willReturn($jobInstance);
     $jobExecution->getId()->willReturn(100);
     $jobInstance->getCode()->willReturn('csv_variant_group_export');
     $jobExecution->getExecutionContext()->willReturn($executionContext);
     $executionContext->get(JobInterface::WORKING_DIRECTORY_PARAMETER)->willReturn('/working/directory/');
     $values = ['picture' => ['locale' => null, 'scope' => null, 'data' => ['filePath' => 'path/not_found.jpg']]];
     $variantStandard = ['code' => 'my_variant_group', 'values' => $values];
     $normalizer->normalize($variantGroup, null, ['with_variant_group_values' => true, 'identifier' => 'my_variant_group'])->willReturn($variantStandard);
     $variantGroupUpdater->update($variantGroup, ['values' => $variantStandard['values']])->shouldBeCalled();
     $productTemplate->getValuesData()->willReturn($variantStandard['values']);
     $productTemplate->getValues()->willReturn($productValueCollection);
     $mediaFetcher->fetchAll($productValueCollection, '/working/directory/', 'my_variant_group')->shouldBeCalled();
     $mediaFetcher->getErrors()->willReturn([['message' => 'The media has not been found or is not currently available', 'media' => ['filePath' => 'path/not_found.jpg']]]);
     $stepExecution->addWarning('The media has not been found or is not currently available', [], new DataInvalidItem(['filePath' => 'path/not_found.jpg']))->shouldBeCalled();
     $this->process($variantGroup)->shouldReturn($variantStandard);
     $objectDetacher->detach($variantGroup)->shouldBeCalled();
 }