diff --git a/composer.json b/composer.json index b8ffced..68fb3dc 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "piotrmus/akeneo-product-translation", "type": "symfony-bundle", "description": "Translation extension for Akeneo", - "version": "0.1.9", + "version": "0.1.10", "license": "OSL-3.0", "authors": [ { diff --git a/src/Connector/Processor/MassEdit/TranslateAttributesProcessor.php b/src/Connector/Processor/MassEdit/TranslateAttributesProcessor.php index 09b5754..3bcc286 100644 --- a/src/Connector/Processor/MassEdit/TranslateAttributesProcessor.php +++ b/src/Connector/Processor/MassEdit/TranslateAttributesProcessor.php @@ -4,14 +4,17 @@ namespace Piotrmus\Translator\Connector\Processor\MassEdit; use Akeneo\Pim\Enrichment\Component\Product\Connector\Processor\MassEdit\AbstractProcessor; +use Akeneo\Pim\Enrichment\Component\Product\EntityWithFamilyVariant\CheckAttributeEditable; use Akeneo\Pim\Enrichment\Component\Product\Model\ProductInterface; use Akeneo\Pim\Enrichment\Component\Product\Model\ProductModelInterface; use Akeneo\Pim\Enrichment\Component\Product\Model\ValueInterface; +use Akeneo\Pim\Enrichment\Component\Product\Updater\Setter\AttributeSetterInterface; use Akeneo\Pim\Enrichment\Component\Product\Value\ScalarValue; use Akeneo\Pim\Structure\Component\Model\AttributeInterface; use Akeneo\Pim\Structure\Component\Repository\AttributeRepositoryInterface; use Akeneo\Tool\Component\Batch\Item\DataInvalidItem; use Akeneo\Tool\Component\Batch\Item\InvalidItemException; +use Akeneo\Tool\Component\StorageUtils\Updater\PropertySetterInterface; use InvalidArgumentException; use Piotrmus\Translator\Translator\Language; use Piotrmus\Translator\Translator\TranslatorInterface; @@ -26,13 +29,25 @@ class TranslateAttributesProcessor extends AbstractProcessor * @var AttributeRepositoryInterface */ private $attributeRepository; + /** + * @var CheckAttributeEditable + */ + private $checkAttributeEditable; + /** + * @var PropertySetterInterface + */ + private $propertySetter; public function __construct( TranslatorInterface $translator, - AttributeRepositoryInterface $attributeRepository + AttributeRepositoryInterface $attributeRepository, + CheckAttributeEditable $checkAttributeEditable, + PropertySetterInterface $propertySetter ) { $this->attributeRepository = $attributeRepository; $this->translator = $translator; + $this->checkAttributeEditable = $checkAttributeEditable; + $this->propertySetter = $propertySetter; } /** @@ -54,6 +69,16 @@ public function process($item) /** * @param ProductInterface|ProductModelInterface $product * @param array> $action + * $actions = [ + * 'sourceChannel' => 'ecommerce', + * 'targetChannel' => 'ecommerce', + * 'sourceLocale' => 'pl_PL', + * 'targetLocale' => 'en_US', + * 'translatedAttributes' => [ + * 'name', + * 'description', + * ] + * ]; * @return ProductInterface|ProductModelInterface */ private function translateAttributes($product, array $action) @@ -67,23 +92,10 @@ private function translateAttributes($product, array $action) $attributeCodes = $action['translatedAttributes']; foreach ($attributeCodes as $attributeCode) { + /** @var AttributeInterface|null $attribute */ $attribute = $this->attributeRepository->findOneByIdentifier($attributeCode); - if (!$this->canEditAttribute($product, $attribute)) { - throw new InvalidItemException( - sprintf( - "You can not edit attribute \"%s\" in this product \"%s\". Most common reason is that attribute is on another level.", - (string)$attributeCode, - $product->getIdentifier() - ), - new DataInvalidItem( - [ - 'identifier' => $product->getIdentifier(), - 'source_attribute' => $attributeCode, - 'source_language' => $sourceLocale->asString(), - 'source_channel' => $sourceScope, - ] - ) - ); + if (!$this->checkAttributeEditable->isEditable($product, $attribute)) { + continue; } if (!$attribute->isScopable()) { @@ -92,85 +104,24 @@ private function translateAttributes($product, array $action) } /** @var ValueInterface|null $attributeValue */ $attributeValue = $product->getValue($attributeCode, $sourceLocaleAkeneo, $sourceScope); - if ($attributeValue === null) { continue; } $sourceText = $attributeValue->getData(); - $translatedValue = $this->translator->translate( + $translatedText = $this->translator->translate( $sourceText, $sourceLocale, $targetLocale ); - $this->replaceProductValue($product, $attribute, $targetLocaleAkeneo, $targetScope, $translatedValue); - } - return $product; - } - - private function canEditAttribute($product, $attribute): bool - { - if ( - ( - ($product instanceof ProductInterface && $product->isVariant()) - || $product instanceof ProductModelInterface - ) - && $product->getFamilyVariant() !== null - && $product->getFamilyVariant()->getLevelForAttributeCode( - $attribute->getCode() - ) !== $product->getVariationLevel() - ) { - return false; - } - if ( - $product instanceof ProductInterface - && !$product->hasAttributeInFamily($attribute) - ) { - return false; - } - return true; - } - - /** - * @param ProductInterface $product - * @param AttributeInterface $attribute - * @param string $targetLocale - * @param string|null $targetScope - * @param string $newValue - */ - private function replaceProductValue( - ProductInterface $product, - AttributeInterface $attribute, - string $targetLocale, - ?string $targetScope, - string $newValue - ): void { - $targetAttributeValue = $product->getValue($attribute->getCode(), $targetLocale, $targetScope); - - $isScopable = $attribute->isScopable(); - $isLocalizable = $attribute->isLocalizable(); - - if ($isScopable && $isLocalizable) { - $value = ScalarValue::scopableLocalizableValue( - $attribute->getCode(), - $newValue, - $targetScope, - $targetLocale - ); - } elseif ($isScopable) { - $value = ScalarValue::scopableValue($attribute->getCode(), $newValue, $targetScope); - } elseif ($isLocalizable) { - $value = ScalarValue::localizableValue($attribute->getCode(), $newValue, $targetLocale); - } else { - $value = ScalarValue::value($attribute->getCode(), $newValue); - } - - if ($targetAttributeValue !== null) { - $product->removeValue($targetAttributeValue); + $this->propertySetter->setData($product, $attribute->getCode(), $translatedText, [ + 'locale' => $targetLocaleAkeneo, + 'scope' => $targetScope, + ]); } - $product->addValue($value); + return $product; } } diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index cb01848..0777c65 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -7,6 +7,8 @@ services: arguments: - '@Piotrmus\Translator\Translator\GoogleTranslator' - '@pim_catalog.repository.attribute' + - '@pim_catalog.entity_with_family_variant.check_attribute_editable' + - '@pim_catalog.updater.entity_with_values_property_setter_without_permission' Google\Cloud\Translate\V2\TranslateClient: arguments: @@ -37,12 +39,13 @@ services: - { name: akeneo_batch.job.job_parameters.constraint_collection_provider } piotrmus.step.update_product_translations.mass_edit: - class: Akeneo\Tool\Component\Batch\Step\ItemStep + class: '%pim_connector.step.item_step.class%' arguments: - 'perform' - '@event_dispatcher' - '@akeneo_batch.job_repository' - - '@pim_enrich.reader.database.products_and_variant_products_of_product_models' + - '@pim_enrich.reader.database.product_and_product_model' - '@Piotrmus\Translator\Connector\Processor\MassEdit\TranslateAttributesProcessor' - - '@pim_connector.writer.database.product' - - 10 \ No newline at end of file + - '@pim_enrich.writer.database.product_and_product_model_writer' + - '%pim_job_product_batch_size%' + - '@akeneo_batch.job.job_stopper' \ No newline at end of file