function it_converts_metric_values_given_the_configured_base_unit_in_the_channel($converter, ProductValueInterface $weightValue, ProductValueInterface $surfaceValue, ProductValueInterface $nameValue, AttributeInterface $weight, AttributeInterface $surface, AttributeInterface $name, MetricInterface $weightMetric, MetricInterface $surfaceMetric, ProductInterface $product, ChannelInterface $channel) { $weightValue->getAttribute()->willReturn($weight); $weightValue->getData()->willReturn($weightMetric); $weight->getCode()->willReturn('weight'); $weightMetric->getFamily()->willReturn('Weight'); $weightMetric->getUnit()->willReturn('KILOGRAM'); $weightMetric->getData()->willReturn(1); $surfaceValue->getAttribute()->willReturn($surface); $surfaceValue->getData()->willReturn($surfaceMetric); $surface->getCode()->willReturn('surface'); $surfaceMetric->getFamily()->willReturn('Surface'); $surfaceMetric->getUnit()->willReturn('METER_SQUARE'); $surfaceMetric->getData()->willReturn(10); $nameValue->getAttribute()->willReturn($name); $nameValue->getData()->willReturn('foobar'); $product->getValues()->willReturn(array($weightValue, $surfaceValue, $nameValue)); $channel->getConversionUnits()->willReturn(array('weight' => 'GRAM')); $converter->setFamily('Weight')->shouldBeCalled(); $converter->convert('KILOGRAM', 'GRAM', 1)->willReturn(0.001); $converter->setFamily('Surface')->shouldNotBeCalled(); $weightMetric->setData(0.001)->shouldBeCalled(); $weightMetric->setUnit('GRAM')->shouldBeCalled(); $this->convert($product, $channel); }
function it_provide_product_completeness_if_a_family_is_defined($familyRepository, $productValueCompleteChecker, QueryBuilder $qb, AbstractQuery $query, AttributeRequirementInterface $requirement, ProductInterface $product, ChannelInterface $mobile, LocaleInterface $en, FamilyInterface $shirt, CompletenessInterface $completeness, ProductValueInterface $nameValue, AttributeInterface $name) { $product->getFamily()->willReturn($shirt); $product->getCompletenesses()->willReturn([$completeness]); $en->getCode()->willReturn('en_US'); $mobile->getCode()->willReturn('mobile'); $completeness->getLocale()->willReturn($en); $completeness->getChannel()->willReturn($mobile); $completeness->getMissingCount()->willReturn(1); $familyRepository->getFullRequirementsQB($shirt, 'en_US')->willReturn($qb); $qb->getQuery()->willReturn($query); $query->getResult()->willReturn([$requirement]); $requirement->getChannel()->willReturn($mobile); $requirement->getAttribute()->willReturn($name); $requirement->isRequired()->willReturn(true); $name->getCode()->willReturn('name'); $name->isLocalizable()->willreturn(true); $name->isScopable()->willReturn(false); $name->isLocaleSpecific()->willReturn(true); $name->hasLocaleSpecific($en)->willReturn(false); $product->getValues()->willReturn(new ArrayCollection()); $productValueCompleteChecker->supportsValue($nameValue); $productValueCompleteChecker->isComplete($nameValue, $mobile, $en); $this->getProductCompleteness($product, [$mobile], [$en], 'en_US')->shouldReturn(['en_US' => ['channels' => ['mobile' => ['completeness' => $completeness, 'missing' => []]], 'stats' => ['total' => 1, 'complete' => 0]]]); }
function it_normalizes_an_existing_product_into_mongodb_document($mongoFactory, $serializer, ProductInterface $product, \MongoId $mongoId, \MongoDate $mongoDate, Association $assoc1, Association $assoc2, CategoryInterface $category1, CategoryInterface $category2, GroupInterface $group1, GroupInterface $group2, ProductValueInterface $value1, ProductValueInterface $value2, FamilyInterface $family) { $mongoFactory->createMongoId('product1')->willReturn($mongoId); $mongoFactory->createMongoDate()->willReturn($mongoDate); $family->getId()->willReturn(36); $category1->getId()->willReturn(12); $category2->getId()->willReturn(34); $group1->getId()->willReturn(56); $group2->getId()->willReturn(78); $product->getId()->willReturn('product1'); $product->getCreated()->willReturn(null); $product->getFamily()->willReturn($family); $product->isEnabled()->willReturn(true); $product->getGroups()->willReturn([$group1, $group2]); $product->getCategories()->willReturn([$category1, $category2]); $product->getAssociations()->willReturn([$assoc1, $assoc2]); $product->getValues()->willReturn([$value1, $value2]); $context = ['_id' => $mongoId]; $serializer->normalize($product, 'mongodb_json')->willReturn(['data' => 'data', 'completenesses' => 'completenesses']); $serializer->normalize($value1, 'mongodb_document', $context)->willReturn('my_value_1'); $serializer->normalize($value2, 'mongodb_document', $context)->willReturn('my_value_2'); $serializer->normalize($assoc1, 'mongodb_document', $context)->willReturn('my_assoc_1'); $serializer->normalize($assoc2, 'mongodb_document', $context)->willReturn('my_assoc_2'); $this->normalize($product, 'mongodb_document')->shouldReturn(['_id' => $mongoId, 'created' => $mongoDate, 'updated' => $mongoDate, 'family' => 36, 'enabled' => true, 'groupIds' => [56, 78], 'categoryIds' => [12, 34], 'associations' => ['my_assoc_1', 'my_assoc_2'], 'values' => ['my_value_1', 'my_value_2'], 'normalizedData' => ['data' => 'data'], 'completenesses' => []]); }
function it_adds_missing_product_values_from_family_on_new_product($valuesResolver, FamilyInterface $family, ProductInterface $product, AttributeInterface $sku, AttributeInterface $name, AttributeInterface $desc, ProductValueInterface $skuValue) { $sku->getCode()->willReturn('sku'); $sku->getAttributeType()->willReturn('pim_catalog_identifier'); $sku->isLocalizable()->willReturn(false); $sku->isScopable()->willReturn(false); $name->getCode()->willReturn('name'); $name->getAttributeType()->willReturn('pim_catalog_text'); $name->isLocalizable()->willReturn(true); $name->isScopable()->willReturn(false); $desc->getCode()->willReturn('description'); $desc->getAttributeType()->willReturn('pim_catalog_text'); $desc->isLocalizable()->willReturn(true); $desc->isScopable()->willReturn(true); // get expected attributes $product->getAttributes()->willReturn([$sku]); $family->getAttributes()->willReturn([$sku, $name, $desc]); $product->getFamily()->willReturn($family); // get eligible values $valuesResolver->resolveEligibleValues(['sku' => $sku, 'name' => $name, 'description' => $desc])->willReturn([['attribute' => 'sku', 'type' => 'pim_catalog_identifier', 'locale' => null, 'scope' => null], ['attribute' => 'name', 'type' => 'pim_catalog_text', 'locale' => 'fr_FR', 'scope' => null], ['attribute' => 'name', 'type' => 'pim_catalog_text', 'locale' => 'en_US', 'scope' => null], ['attribute' => 'description', 'type' => 'pim_catalog_text', 'locale' => 'en_US', 'scope' => 'ecommerce'], ['attribute' => 'description', 'type' => 'pim_catalog_text', 'locale' => 'fr_FR', 'scope' => 'ecommerce'], ['attribute' => 'description', 'type' => 'pim_catalog_text', 'locale' => 'en_US', 'scope' => 'print'], ['attribute' => 'description', 'type' => 'pim_catalog_text', 'locale' => 'fr_FR', 'scope' => 'print']]); // get existing values $skuValue->getAttribute()->willReturn($sku); $skuValue->getLocale()->willReturn(null); $skuValue->getScope()->willReturn(null); $product->getValues()->willReturn([$skuValue]); // add 6 new values : 4 desc (locales x scopes) + 2 name (locales $product->addValue(Argument::any())->shouldBeCalledTimes(6); $this->addMissingProductValues($product); }
function it_returns_flat_data_without_media(ChannelInterface $channel, ChannelManager $channelManager, ProductInterface $product, Serializer $serializer) { $product->getValues()->willReturn([]); $serializer->normalize($product, 'flat', ['scopeCode' => 'foobar', 'localeCodes' => ''])->willReturn(['normalized_product']); $channelManager->getChannelByCode('foobar')->willReturn($channel); $this->setChannel('foobar'); $this->process($product)->shouldReturn(['media' => [], 'product' => ['normalized_product']]); }
function it_throws_an_exception_if_something_goes_wrong_with_media_normalization($serializer, ProductInterface $product, ProductMediaInterface $media, ProductValueInterface $value, ProductValueInterface $value2, AttributeInterface $attribute) { $product->getValues()->willReturn([$value]); $product->getIdentifier()->willReturn($value2); $value->getAttribute()->willReturn($attribute); $value->getData()->willReturn($media); $value2->getData()->willReturn(23); $attribute->getAttributeType()->willReturn('pim_catalog_image'); $serializer->normalize([$media], Argument::cetera())->willThrow(new FileNotFoundException('upload/path/img.jpg')); $this->shouldThrow(new InvalidItemException('The file "upload/path/img.jpg" does not exist', ['item' => 23, 'uploadDirectory' => 'upload/path/']))->duringProcess($product); }
function it_throws_an_exception_if_no_file_is_found(ChannelInterface $channel, ProductInterface $product, ChannelManager $channelManager, Serializer $serializer, ProductValueInterface $productValue, AttributeInterface $attribute) { $product->getValues()->willReturn([$productValue]); $productValue->getAttribute()->willReturn($attribute); $attribute->getAttributeType()->willReturn('pim_catalog_image'); $product->getIdentifier()->willReturn($productValue); $productValue->getData()->willReturn('data'); $this->setChannel('foobar'); $channelManager->getChannelByCode('foobar')->willReturn($channel); $serializer->normalize(['data'], 'flat', ['field_name' => 'media', 'prepare_copy' => true])->willThrow('Symfony\\Component\\HttpFoundation\\File\\Exception\\FileNotFoundException'); $this->shouldThrow('Akeneo\\Bundle\\BatchBundle\\Item\\InvalidItemException')->during('process', [$product]); }
/** * Converts metric values * * @param DocumentManager $dm * @param ProductInterface $product */ protected function convertMetricValues(DocumentManager $dm, ProductInterface $product) { foreach ($product->getValues() as $value) { $metric = $value->getData(); if ($metric instanceof MetricInterface && $metric->getUnit()) { $this->createMetricBaseValues($metric); if (null !== $metric->getId()) { $metadata = $dm->getClassMetadata(ClassUtils::getClass($metric)); $dm->getUnitOfWork()->recomputeSingleDocumentChangeSet($metadata, $metric); } } } }
/** * Convert all the products metric values into the channel configured conversion units * * @param ProductInterface $product * @param ChannelInterface $channel */ public function convert(ProductInterface $product, ChannelInterface $channel) { $channelUnits = $channel->getConversionUnits(); foreach ($product->getValues() as $value) { $data = $value->getData(); $attribute = $value->getAttribute(); if ($data instanceof MetricInterface && isset($channelUnits[$attribute->getCode()])) { $channelUnit = $channelUnits[$attribute->getCode()]; $this->converter->setFamily($data->getFamily()); $data->setData($this->converter->convert($data->getUnit(), $channelUnit, $data->getData())); $data->setUnit($channelUnit); } } }
function it_normalizes_product(SerializerInterface $serializer, ProductInterface $product, FamilyInterface $family, Completeness $completeness) { $serializer->implement('Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface'); $this->setSerializer($serializer); $product->getFamily()->willReturn($family); $product->getGroups()->willReturn([]); $product->getValues()->willReturn([]); $product->getCompletenesses()->willReturn([$completeness]); $product->getCreated()->willReturn(null); $product->getUpdated()->willReturn(null); $product->isEnabled()->willReturn(true); $serializer->normalize($family, 'mongodb_json', [])->willReturn('family normalization'); $serializer->normalize($completeness, 'mongodb_json', [])->willReturn(['completenessCode' => 'completeness normalization']); $this->normalize($product, 'mongodb_json', [])->shouldReturn([ProductNormalizer::FAMILY_FIELD => 'family normalization', ProductNormalizer::COMPLETENESSES_FIELD => array('completenessCode' => 'completeness normalization'), ProductNormalizer::ENABLED_FIELD => true]); }
/** * Returns the required attribute codes for a product * * @param ProductInterface $product * * @return array */ public function getRequiredAttributeCodes(ProductInterface $product) { $codes = array(); if ($product->getFamily()) { $codes = $this->getFamilyAttributeCodes($product->getFamily()); } foreach ($product->getGroups() as $group) { $codes = array_merge($codes, $this->getGroupAttributeCodes($group)); } if ($product->getId()) { foreach ($product->getValues() as $value) { $codes[] = $value->getAttribute()->getCode(); } } return array_unique($codes); }
function it_does_not_convert_null_metric_values_in_the_channel($converter, ProductValueInterface $weightValue, AttributeInterface $weight, MetricInterface $weightMetric, ProductInterface $product, ChannelInterface $channel) { $weightValue->getAttribute()->willReturn($weight); $weightValue->getData()->willReturn($weightMetric); $weight->getCode()->willReturn('weight'); $weightMetric->getFamily()->willReturn('Weight'); $weightMetric->getUnit()->willReturn(null); $weightMetric->getData()->willReturn(null); $product->getValues()->willReturn(array($weightValue)); $channel->getConversionUnits()->willReturn(array('weight' => 'GRAM')); $converter->setFamily('Weight')->shouldNotBeCalled(); $converter->convert('KILOGRAM', 'GRAM', 1)->shouldNotBeCalled(); $weightMetric->setData(null)->shouldNotBeCalled(); $weightMetric->setUnit('GRAM')->shouldNotBeCalled(); $this->convert($product, $channel); }
/** * Handle the medias of a product * * @param ProductInterface $product * * @throws MediaManagementException * @throws \Exception */ public function handleProductMedias(ProductInterface $product) { foreach ($product->getValues() as $value) { if ($media = $value->getMedia()) { if ($id = $media->getCopyFrom()) { $repository = $this->doctrine->getRepository('Pim\\Bundle\\CatalogBundle\\Model\\ProductMedia'); $source = $repository->find($id); if (!$source) { throw new \Exception(sprintf('Could not find media with id %d', $id)); } $this->duplicate($source, $media, $this->generateFilenamePrefix($product, $value)); } else { $filenamePrefix = $media->getFile() ? $this->generateFilenamePrefix($product, $value) : null; $this->handle($media, $filenamePrefix); } } } }
function it_normalizes_the_values_of_product(ProductInterface $product, AttributeInterface $attribute, ProductValueInterface $value, ArrayCollection $values, \ArrayIterator $iterator, $filter, $serializer) { $values->getIterator()->willReturn($iterator); $product->getAssociations()->willReturn([]); $product->getFamily()->willReturn(null); $product->getGroupCodes()->willReturn([]); $product->getCategoryCodes()->willReturn([]); $product->isEnabled()->willReturn(true); $value->getAttribute()->willReturn($attribute); $attribute->getCode()->willReturn('name'); $product->getValues()->willReturn($values); $filter->filter($values, Argument::any())->shouldBeCalled()->willReturn($values); $iterator->rewind()->willReturn(null); $valueCount = 1; $iterator->valid()->will(function () use(&$valueCount) { return $valueCount-- > 0; }); $iterator->current()->willReturn($value); $iterator->next()->willReturn(null); $serializer->normalize($value, 'json', Argument::any())->willReturn(['locale' => null, 'scope' => null, 'value' => 'foo']); $this->normalize($product, 'json')->shouldReturn(['family' => null, 'groups' => [], 'categories' => [], 'enabled' => true, 'associations' => [], 'values' => ['name' => [['locale' => null, 'scope' => null, 'value' => 'foo']]]]); }
function it_adds_missing_product_values_from_family_on_new_product(FamilyInterface $family, ProductInterface $product, AttributeInterface $sku, AttributeInterface $name, AttributeInterface $desc, $localeRepository, LocaleInterface $fr, LocaleInterface $en, $channelRepository, ChannelInterface $ecom, ChannelInterface $print, ProductValueInterface $skuValue) { // get expected attributes $product->getAttributes()->willReturn([$sku]); $product->getFamily()->willReturn($family); $family->getAttributes()->willReturn([$sku, $name, $desc]); // get expected values $sku->getCode()->willReturn('sku'); $sku->getAttributeType()->willReturn('pim_catalog_identifier'); $sku->isLocalizable()->willReturn(false); $sku->isScopable()->willReturn(false); $sku->isLocaleSpecific()->willReturn(false); $name->getCode()->willReturn('name'); $name->getAttributeType()->willReturn('pim_catalog_text'); $name->isLocalizable()->willReturn(true); $name->isScopable()->willReturn(false); $name->isLocaleSpecific()->willReturn(false); $desc->getCode()->willReturn('desc'); $desc->getAttributeType()->willReturn('pim_catalog_text'); $desc->isLocalizable()->willReturn(true); $desc->isScopable()->willReturn(true); $desc->isLocaleSpecific()->willReturn(false); $fr->getCode()->willReturn('fr_FR'); $en->getCode()->willReturn('fr_FR'); $localeRepository->getActivatedLocales()->willReturn([$fr, $en]); $ecom->getCode()->willReturn('ecom'); $ecom->getLocales()->willReturn([$en, $fr]); $print->getCode()->willReturn('print'); $print->getLocales()->willReturn([$en, $fr]); $channelRepository->findAll()->willReturn([$ecom, $print]); // get existing values $skuValue->getAttribute()->willReturn($sku); $skuValue->getLocale()->willReturn(null); $skuValue->getScope()->willReturn(null); $product->getValues()->willReturn([$skuValue]); // add 6 new values : 4 desc (locales x scopes) + 2 name (locales $product->addValue(Argument::any())->shouldBeCalledTimes(6); $this->addMissingProductValues($product); }
function it_updates_a_variant_group($attributeRepository, $groupTypeRepository, $productBuilder, GroupInterface $variantGroup, AttributeInterface $attribute, GroupTypeInterface $type, GroupTranslation $translatable, ProductInterface $product, ProductValueInterface $productValue, ProductTemplateInterface $productTemplate) { $groupTypeRepository->findOneByIdentifier('VARIANT')->willReturn($type); $attributeRepository->findOneByIdentifier('main_color')->willReturn($attribute); $attributeRepository->findOneByIdentifier('secondary_color')->willReturn($attribute); $variantGroup->getTranslation()->willReturn($translatable); $translatable->setLabel('T-shirt super beau')->shouldBeCalled(); $variantGroup->setCode('mycode')->shouldBeCalled(); $variantGroup->setLocale('fr_FR')->shouldBeCalled(); $variantGroup->setType($type)->shouldBeCalled(); $variantGroup->getId()->willReturn(null); $variantGroup->addAxisAttribute(Argument::any())->shouldBeCalled(); $productTemplate->getValuesData()->willReturn([]); $productTemplate->setValues(Argument::any())->shouldBeCalled(); $productTemplate->setValuesData(['main_color' => [['locale' => null, 'scope' => null, 'data' => 'white']]])->shouldBeCalled(); $variantGroup->getProductTemplate()->willReturn($productTemplate); $variantGroup->setProductTemplate($productTemplate)->shouldBeCalled(); $product->getValues()->willReturn(new ArrayCollection([$productValue])); $product->getIdentifier()->willReturn($productValue); $productBuilder->createProduct()->willReturn($product); $values = ['code' => 'mycode', 'axis' => ['main_color', 'secondary_color'], 'type' => 'VARIANT', 'labels' => ['fr_FR' => 'T-shirt super beau'], 'values' => ['main_color' => [['locale' => null, 'scope' => null, 'data' => 'white']]]]; $this->update($variantGroup, $values, []); }
/** * Get values array for a given product. * * @param ProductInterface $product The given product * @param array $prestashopAttributes Attribute list from Prestashop * @param array $prestashopAttributesOptions Attribute options list from Prestashop * @param string $localeCode The locale to apply * @param string $scopeCode The Akeneo scope * @param MappingCollection $categoryMapping Root category mapping * @param MappingCollection $attributeCodeMapping Attribute mapping * @param boolean $onlyLocalized If true, only get translatable attributes * @param string $pimGrouped Pim grouped association code * @param boolean $urlKey Product url key * @param boolean $skuFirst Is sku first in url key? * * @return array Computed data */ public function getValues(ProductInterface $product, $prestashopAttributes, $prestashopAttributesOptions, $localeCode, $scopeCode, MappingCollection $categoryMapping, MappingCollection $attributeCodeMapping, $onlyLocalized, $pimGrouped = null, $urlKey = false, $skuFirst = false) { $normalizedValues = []; $context = ['identifier' => $product->getIdentifier(), 'scopeCode' => $scopeCode, 'localeCode' => $localeCode, 'onlyLocalized' => $onlyLocalized, 'prestashopAttributes' => $prestashopAttributes, 'prestashopAttributesOptions' => $prestashopAttributesOptions, 'attributeCodeMapping' => $attributeCodeMapping, 'currencyCode' => $this->currencyCode]; foreach ($product->getValues() as $value) { $normalizedValue = $this->productValueNormalizer->normalize($value, 'PrestashopArray', $context); if ($normalizedValue !== null) { $normalizedValues = array_merge($normalizedValues, $normalizedValue); } } $normalizedValues = array_merge($normalizedValues, $this->getCustomValue($product, $attributeCodeMapping, ['categoryMapping' => $categoryMapping, 'scopeCode' => $scopeCode, 'localeCode' => $localeCode, 'pimGrouped' => $pimGrouped, 'urlKey' => $urlKey, 'skuFirst' => $skuFirst])); ksort($normalizedValues); return $normalizedValues; }
/** * Get filtered values * * @param ProductInterface $product * @param array $context * * @return ProductValueInterface[] */ protected function getFilteredValues(ProductInterface $product, array $context = []) { $values = $product->getValues(); $context = ['identifier' => $product->getIdentifier(), 'scopeCode' => $context['scopeCode'], 'localeCodes' => $context['localeCodes']]; foreach ($this->valuesFilters as $filter) { $values = $filter->filter($values, $context); } return $values; }
/** * Fetch product media * * @param ProductInterface $product * * @return ProductMediaInterface[] */ protected function getProductMedias(ProductInterface $product) { $media = []; foreach ($product->getValues() as $value) { if (in_array($value->getAttribute()->getAttributeType(), [AttributeTypes::IMAGE, AttributeTypes::FILE])) { $media[] = $value->getData(); } } return $media; }
/** * Returns an array containing all completeness info and missing attributes for a product * * @param ProductInterface $product * @param \Pim\Bundle\CatalogBundle\Entity\ChannelInterface[] $channels * @param \Pim\Bundle\CatalogBundle\Entity\LocaleInterface[] $locales * @param string $localeCode * * @return array */ public function getProductCompleteness(ProductInterface $product, array $channels, array $locales, $localeCode) { $family = $product->getFamily(); $getCodes = function ($entities) { return array_map(function ($entity) { return $entity->getCode(); }, $entities); }; $channelCodes = $getCodes($channels); $localeCodes = $getCodes($locales); $channelTemplate = ['channels' => array_fill_keys($channelCodes, ['completeness' => null, 'missing' => []]), 'stats' => ['total' => 0, 'complete' => 0]]; $completenesses = array_fill_keys($localeCodes, $channelTemplate); if (!$family) { return $completenesses; } $allCompletenesses = $product->getCompletenesses(); foreach ($allCompletenesses as $completeness) { $locale = $completeness->getLocale(); $channel = $completeness->getChannel(); $compLocaleCode = $locale->getCode(); if (isset($completenesses[$compLocaleCode])) { $completenesses[$compLocaleCode]['channels'][$channel->getCode()]['completeness'] = $completeness; $completenesses[$compLocaleCode]['stats']['total']++; if (0 === $completeness->getMissingCount()) { $completenesses[$compLocaleCode]['stats']['complete']++; } } } $requirements = $this->familyRepository->getFullRequirementsQB($family, $localeCode)->getQuery()->getResult(); $productValues = $product->getValues(); foreach ($requirements as $requirement) { if ($requirement->isRequired()) { $this->addRequirementToCompleteness($completenesses, $requirement, $productValues, $locales); } } return $completenesses; }
/** * Transforms product violations into an array * * @param ConstraintViolationListInterface $violations * @param ProductInterface $product * * @return array */ protected function transformViolations(ConstraintViolationListInterface $violations, ProductInterface $product) { $errors = []; foreach ($violations as $violation) { $path = $violation->getPropertyPath(); if (0 === strpos($path, 'values')) { $codeStart = strpos($path, '[') + 1; $codeLength = strpos($path, ']') - $codeStart; $valueIndex = substr($path, $codeStart, $codeLength); $value = $product->getValues()[$valueIndex]; $errors['values'][$value->getAttribute()->getCode()][] = ['attribute' => $value->getAttribute()->getCode(), 'locale' => $value->getLocale(), 'scope' => $value->getScope(), 'message' => $violation->getMessage(), 'invalid_value' => $violation->getInvalidValue()]; } else { $errors[$path] = ['message' => $violation->getMessage(), 'invalid_value' => $violation->getInvalidValue()]; } } return $errors; }
function it_normalizes_product_with_a_multiselect_value($filter, $serializer, ProductInterface $product, AbstractAttribute $skuAttribute, AbstractAttribute $colorsAttribute, AbstractProductValue $sku, AbstractProductValue $colors, AttributeOption $red, AttributeOption $blue, Collection $values, Family $family) { $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'); $colorsAttribute->getCode()->willReturn('colors'); $colorsAttribute->isLocalizable()->willReturn(false); $colorsAttribute->isScopable()->willReturn(false); $colors->getAttribute()->willReturn($colorsAttribute); $colors->getData()->willReturn([$red, $blue]); $product->getIdentifier()->willReturn($sku); $product->getFamily()->willReturn($family); $product->isEnabled()->willReturn(true); $product->getGroupCodes()->willReturn(''); $product->getCategoryCodes()->willReturn(''); $product->getAssociations()->willReturn([]); $product->getValues()->willReturn($values); $filter->filter($values, ['identifier' => $sku, 'scopeCode' => null, 'localeCodes' => []])->willReturn([$sku, $colors]); $serializer->normalize($sku, 'flat', Argument::any())->willReturn(['sku' => 'sku-001']); $serializer->normalize($colors, 'flat', Argument::any())->willReturn(['colors' => 'red, blue']); $this->normalize($product, 'flat', [])->shouldReturn(['sku' => 'sku-001', 'family' => 'shoes', 'groups' => '', 'categories' => '', 'colors' => 'red, blue', 'enabled' => 1]); }
function it_returns_flat_data_with_french_attribute($channelManager, $serializer, $dateformatProvider, $numberFormatProvider, ChannelInterface $channel, ProductInterface $product, ProductValueInterface $number, AttributeInterface $attribute, MetricInterface $metric, ProductValueInterface $metricValue, ProductPriceInterface $price, ProductValueInterface $priceValue) { $dateformatProvider->getFormat('fr_FR')->willReturn('d/m/Y'); $numberFormatProvider->getFormat('fr_FR')->willReturn(['decimal_separator' => ',']); $this->configureOptions('fr_FR'); $attribute->getAttributeType()->willReturn('pim_catalog_number'); $number->getDecimal('10.50'); $number->getAttribute()->willReturn($attribute); $attribute->getAttributeType()->willReturn('pim_catalog_metric'); $metric->getData()->willReturn('10.00'); $metric->getUnit()->willReturn('GRAM'); $metricValue->getAttribute()->willReturn($attribute); $metricValue->getData()->willReturn($metric); $attribute->getAttributeType()->willReturn('pim_catalog_price_collection'); $price->getData()->willReturn('10'); $price->getCurrency()->willReturn('EUR'); $priceValue->getAttribute()->willReturn($attribute); $priceValue->getData()->willReturn($price); $product->getValues()->willReturn([$number, $metricValue, $priceValue]); $serializer->normalize($product, 'flat', ['scopeCode' => 'mobile', 'localeCodes' => '', 'decimal_separator' => ',', 'date_format' => 'd/m/Y'])->willReturn(['10,50', '10,00 GRAM', '10,00 EUR', '25/10/2015']); $channelManager->getChannelByCode('mobile')->willReturn($channel); $this->setChannelCode('mobile'); $this->process($product)->shouldReturn(['media' => [], 'product' => ['10,50', '10,00 GRAM', '10,00 EUR', '25/10/2015']]); }
/** * Transforms product violations into an array * * @param ConstraintViolationListInterface $violations * @param ProductInterface $product * * @return array */ protected function transformViolations(ConstraintViolationListInterface $violations, ProductInterface $product) { $errors = []; foreach ($violations as $violation) { $path = $violation->getPropertyPath(); if (0 === strpos($path, 'values')) { $codeStart = strpos($path, '[') + 1; $codeLength = strpos($path, ']') - $codeStart; $valueIndex = substr($path, $codeStart, $codeLength); $value = $product->getValues()[$valueIndex]; $attributeCode = $value->getAttribute()->getCode(); $currentError = ['attribute' => $attributeCode, 'locale' => $value->getLocale(), 'scope' => $value->getScope(), 'message' => $violation->getMessage(), 'invalid_value' => $violation->getInvalidValue()]; $errors['values'][$attributeCode] = isset($errors['values'][$attributeCode]) ? $errors['values'][$attributeCode] : []; $identicalErrors = array_filter($errors['values'][$attributeCode], function ($error) use($currentError) { return isset($error['message']) && $error['message'] === $currentError['message']; }); if (empty($identicalErrors)) { $errors['values'][$attributeCode][] = $currentError; } } else { $errors[$path] = ['message' => $violation->getMessage(), 'invalid_value' => $violation->getInvalidValue()]; } } return $errors; }
/** * Get values array for a given product * * @param ProductInterface $product The given product * @param array $magentoAttributes Attribute list from Magento * @param array $magentoAttributesOptions Attribute options list from Magento * @param string $localeCode The locale to apply * @param string $scopeCode The akeneo scope * @param MappingCollection $categoryMapping Root category mapping * @param MappingCollection $attributeCodeMapping Attribute mapping * @param boolean $onlyLocalized If true, only get translatable attributes * * @return array Computed data */ public function getValues(ProductInterface $product, $magentoAttributes, $magentoAttributesOptions, $localeCode, $scopeCode, MappingCollection $categoryMapping, MappingCollection $attributeCodeMapping, $onlyLocalized) { $normalizedValues = []; $context = ['identifier' => $product->getIdentifier(), 'scopeCode' => $scopeCode, 'localeCode' => $localeCode, 'onlyLocalized' => $onlyLocalized, 'magentoAttributes' => $magentoAttributes, 'magentoAttributesOptions' => $magentoAttributesOptions, 'attributeCodeMapping' => $attributeCodeMapping, 'currencyCode' => $this->currencyCode]; foreach ($product->getValues() as $value) { $normalizedValue = $this->productValueNormalizer->normalize($value, 'MagentoArray', $context); if ($normalizedValue !== null) { $normalizedValues = array_merge($normalizedValues, $normalizedValue); } } $normalizedValues = array_merge($normalizedValues, $this->getCustomValue($product, $attributeCodeMapping, ['categoryMapping' => $categoryMapping, 'scopeCode' => $scopeCode])); ksort($normalizedValues); return $normalizedValues; }
/** * Deletes values that link an attribute to a product * * @param ProductInterface $product * @param AttributeInterface $attribute * @param array $savingOptions * * @deprecated Will be removed in 1.5, please use ProductBuilderInterface::removeAttributeFromProduct() and * ProductSaver::save() instead. */ public function removeAttributeFromProduct(ProductInterface $product, AttributeInterface $attribute, array $savingOptions = []) { foreach ($product->getValues() as $value) { if ($attribute === $value->getAttribute()) { $product->removeValue($value); } } $options = array_merge(['recalculate' => false, 'schedule' => false], $savingOptions); $this->productSaver->save($product, $options); }
/** * Denormalize product values * * @param string $data * @param string $format * @param array $context * @param ProductInterface $product */ protected function denormalizeValues($data, $format, array $context, ProductInterface $product) { foreach ($product->getValues() as $value) { $product->removeValue($value); } foreach ($data as $attFieldName => $dataValue) { $attributeInfos = $this->fieldNameBuilder->extractAttributeFieldNameInfos($attFieldName); $attribute = $attributeInfos['attribute']; unset($attributeInfos['attribute']); if (!$product->hasAttribute($attribute)) { $this->productBuilder->addAttributeToProduct($product, $attribute); } // Denormalize data value. // The value is already added to the product so automatically updated $productValue = $product->getValue($attribute->getCode(), $attributeInfos['locale_code'], $attributeInfos['scope_code']); $this->serializer->denormalize($dataValue, $this->productValueClass, $format, ['product' => $product, 'entity' => $productValue] + $attributeInfos + $context); } }
/** * @param ProductInterface $product * @param array $drupalProduct * @param Channel $channel * @param array $configuration * * @throws \Exception */ protected function computeProductValues(ProductInterface $product, array &$drupalProduct, Channel $channel, $configuration) { /** @var \Pim\Bundle\CatalogBundle\Model\ProductValue $value */ foreach ($product->getValues() as $value) { /* // Skip out of scope values or not global ones. if ($value->getScope() != $channel->getCode() && $value->getScope( ) !== null ) { continue; }*/ $field = $value->getAttribute()->getCode(); $type = $value->getAttribute()->getAttributeType(); $locale = $value->getLocale(); if (is_null($locale)) { $locale = LANGUAGE_NONE; } $labelAttribute = $value->getEntity()->getFamily()->getAttributeAsLabel()->getCode(); if ($type == 'pim_catalog_identifier') { continue; } // Setup default locale. $context = ['locale' => $locale, 'scope' => $value->getScope(), 'defaultLocale' => 'fr_FR', 'configuration' => $configuration]; if ($normalizer = $this->normalizerGuesser->guessNormalizer($type, 'product_value')) { $normalizer->normalize($drupalProduct, $value, $field, $context); } else { throw new NormalizeException('Type field not supported: "' . $type . '".', 'Normalizing error'); } } }
function it_normalizes_product_with_price($filter, ProductInterface $product, AttributeInterface $priceAttribute, ProductValueInterface $price, Collection $prices, Collection $values, ProductPriceInterface $productPrice, FamilyInterface $family, SerializerInterface $serializer) { $family->getCode()->willReturn('shoes'); $priceAttribute->getCode()->willReturn('price'); $priceAttribute->getAttributeType()->willReturn('pim_catalog_price_collection'); $priceAttribute->isLocalizable()->willReturn(false); $priceAttribute->isScopable()->willReturn(false); $price->getAttribute()->willReturn($priceAttribute); $price->getData()->willReturn(null); $productPrice->getData()->willReturn("356.00"); $productPrice->getCurrency()->willReturn("EUR"); $prices->add($productPrice); $price->getPrices()->willReturn($prices); $product->getIdentifier()->willReturn($price); $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([]); $values->add($price); $product->getValues()->willReturn($values); $filter->filterCollection($values, 'pim.transform.product_value.flat', Argument::cetera())->willReturn([$price]); $serializer->normalize($price, 'flat', Argument::any())->willReturn(['price-EUR' => '356.00']); $this->normalize($product, 'flat', ['price-EUR' => ''])->shouldReturn(['price-EUR' => '356.00', 'family' => 'shoes', 'groups' => 'group1, group2, variant_group_1', 'categories' => 'nice shoes, converse', 'enabled' => 1]); }
/** * Fetch product medias * * @param ProductInterface $product * * @return \Pim\Bundle\CatalogBundle\Model\ProductMediaInterface[] */ protected function getProductMedias(ProductInterface $product) { $media = array(); foreach ($product->getValues() as $value) { if (in_array($value->getAttribute()->getAttributeType(), array('pim_catalog_image', 'pim_catalog_file'))) { $media[] = $value->getData(); } } return $media; }