Skip to content

Commit

Permalink
Update attribute configuration ouytside of value converter (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
lruozzi9 committed Feb 15, 2024
1 parent 7e06bac commit e3dead8
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 61 deletions.
2 changes: 0 additions & 2 deletions config/services/converter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
$services->set('webgriffe_sylius_akeneo.converter.value', ValueConverter::class)
->args([
service('translator'),
service('webgriffe_sylius_akeneo.api_client'),
service('sylius.repository.product_attribute'),
])
;

Expand Down
53 changes: 3 additions & 50 deletions src/Converter/ValueConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,18 @@

namespace Webgriffe\SyliusAkeneoPlugin\Converter;

use Akeneo\Pim\ApiClient\AkeneoPimClientInterface;
use InvalidArgumentException;
use Sylius\Component\Attribute\AttributeType\SelectAttributeType;
use Sylius\Component\Attribute\AttributeType\TextAttributeType;
use Sylius\Component\Attribute\Model\AttributeInterface;
use Sylius\Component\Product\Model\ProductAttributeInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Webgriffe\SyliusAkeneoPlugin\ProductAttributeHelperTrait;
use Webmozart\Assert\Assert;

final class ValueConverter implements ValueConverterInterface
{
use ProductAttributeHelperTrait;

/**
* @param RepositoryInterface<ProductAttributeInterface>|null $attributeRepository
*/
public function __construct(
private TranslatorInterface $translator,
private ?AkeneoPimClientInterface $akeneoPimClient = null,
private ?RepositoryInterface $attributeRepository = null
) {
if ($this->akeneoPimClient === null) {
trigger_deprecation(
'webgriffe/sylius-akeneo-plugin',
'1.0',
'The $akeneoPimClient argument is required.'
);
}
}

public function convert(AttributeInterface $attribute, array|bool|int|string $value, string $localeCode): array|bool|int|string
Expand All @@ -56,28 +38,18 @@ public function convert(AttributeInterface $attribute, array|bool|int|string $va
return $value;
}
if (!is_bool($value) && $attribute->getType() === SelectAttributeType::TYPE) {
/** @var string[] $value */
$value = (array) $value;
if (!$this->isAttributeValueBetweenProductAttributeChoices($attribute, $value)) {
$attributeCode = $attribute->getCode();
Assert::string($attributeCode);
if ($attribute instanceof ProductAttributeInterface &&
$this->akeneoPimClient !== null &&
$this->attributeRepository !== null
) {
// Try to re-import attribute configuration
$this->importAttributeConfiguration($attributeCode, $attribute);

if ($this->isAttributeValueBetweenProductAttributeChoices($attribute, $value)) {
return $value;
}
}

throw new InvalidArgumentException(
sprintf(
'This select attribute can only save existing attribute options. ' .
'Attribute option codes [%s] for attribute "%s" does not exist.',
implode(', ', $value),
$attributeCode
$attributeCode,
),
);
}
Expand All @@ -92,31 +64,12 @@ private function isAttributeValueBetweenProductAttributeChoices(AttributeInterfa
if (!array_key_exists('choices', $attributeConfiguration)) {
return false;
}
/** @var array $choices */
/** @var array<string, array> $choices */
$choices = $attributeConfiguration['choices'];
$possibleAttributeOptionCodes = array_map('strval', array_keys($choices));
/** @var string[] $invalid */
$invalid = array_diff($value, $possibleAttributeOptionCodes);

return count($invalid) === 0;
}

private function getAkeneoPimClient(): AkeneoPimClientInterface
{
$akeneoPimClient = $this->akeneoPimClient;
Assert::notNull($akeneoPimClient);

return $akeneoPimClient;
}

/**
* @return RepositoryInterface<ProductAttributeInterface>
*/
private function getAttributeRepository(): RepositoryInterface
{
$attributeRepository = $this->attributeRepository;
Assert::notNull($attributeRepository);

return $attributeRepository;
}
}
1 change: 1 addition & 0 deletions src/DependencyInjection/WebgriffeSyliusAkeneoExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ final class WebgriffeSyliusAkeneoExtension extends AbstractResourceExtension imp
'$factory' => 'sylius.factory.product_attribute_value',
'$localeProvider' => 'sylius.translation_locale_provider.admin',
'$valueConverter' => 'webgriffe_sylius_akeneo.converter.value',
'$akeneoPimClient' => 'webgriffe_sylius_akeneo.api_client',
],
],
'file_attribute' => [
Expand Down
1 change: 0 additions & 1 deletion src/ProductAttributeHelperTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
*/
trait ProductAttributeHelperTrait
{

abstract private function getAkeneoPimClient(): AkeneoPimClientInterface;

/**
Expand Down
53 changes: 45 additions & 8 deletions src/ValueHandler/AttributeValueHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,51 @@

namespace Webgriffe\SyliusAkeneoPlugin\ValueHandler;

use Akeneo\Pim\ApiClient\AkeneoPimClientInterface;
use InvalidArgumentException;
use Sylius\Component\Attribute\AttributeType\CheckboxAttributeType;
use Sylius\Component\Attribute\AttributeType\IntegerAttributeType;
use Sylius\Component\Attribute\AttributeType\SelectAttributeType;
use Sylius\Component\Attribute\AttributeType\TextareaAttributeType;
use Sylius\Component\Attribute\AttributeType\TextAttributeType;
use Sylius\Component\Attribute\Model\AttributeInterface;
use Sylius\Component\Channel\Model\ChannelInterface;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Core\Model\ProductVariantInterface;
use Sylius\Component\Product\Model\ProductAttributeInterface;
use Sylius\Component\Product\Model\ProductAttributeValueInterface;
use Sylius\Component\Product\Model\ProductOptionInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface;
use Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface;
use Webgriffe\SyliusAkeneoPlugin\ProductAttributeHelperTrait;
use Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface;
use Webmozart\Assert\Assert;

final class AttributeValueHandler implements ValueHandlerInterface
{
use ProductAttributeHelperTrait;

/**
* @param RepositoryInterface<AttributeInterface> $attributeRepository
* @param RepositoryInterface<ProductAttributeInterface> $attributeRepository
* @param FactoryInterface<ProductAttributeValueInterface> $factory
*/
public function __construct(
private RepositoryInterface $attributeRepository,
private FactoryInterface $factory,
private TranslationLocaleProviderInterface $localeProvider,
private ValueConverterInterface $valueConverter,
private ?AkeneoPimClientInterface $akeneoPimClient = null,
) {
if ($this->akeneoPimClient === null) {
trigger_deprecation(
'webgriffe/sylius-akeneo-plugin',
'v2.6.0',
'Not passing a "%s" instance to "%s" constructor is deprecated and will not be possible anymore in the next major version.',
AkeneoPimClientInterface::class,
self::class,
);
}
}

public function supports($subject, string $attributeCode, array $value): bool
Expand All @@ -53,7 +68,7 @@ public function supports($subject, string $attributeCode, array $value): bool
public function handle($subject, string $attributeCode, array $value): void
{
if (!$subject instanceof ProductVariantInterface) {
throw new \InvalidArgumentException(
throw new InvalidArgumentException(
sprintf(
'This attribute value handler only supports instances of %s, %s given.',
ProductVariantInterface::class,
Expand All @@ -64,14 +79,20 @@ public function handle($subject, string $attributeCode, array $value): void

$attribute = $this->attributeRepository->findOneBy(['code' => $attributeCode]);
if ($attribute === null) {
throw new \InvalidArgumentException(
throw new InvalidArgumentException(
sprintf(
'This attribute value handler only supports existing attributes. ' .
'Attribute with the given %s code does not exist.',
$attributeCode,
),
);
}
// TODO: Find a way to update attribute options only when they change or when needed, not every time
if ($this->akeneoPimClient !== null &&
$attribute->getType() === SelectAttributeType::TYPE
) {
$this->importAttributeConfiguration($attributeCode, $attribute);
}

$availableLocalesCodes = $this->localeProvider->getDefinedLocalesCodes();

Expand All @@ -83,10 +104,10 @@ public function handle($subject, string $attributeCode, array $value): void

foreach ($value as $valueData) {
if (!is_array($valueData)) {
throw new \InvalidArgumentException(sprintf('Invalid Akeneo value data: expected an array, "%s" given.', gettype($valueData)));
throw new InvalidArgumentException(sprintf('Invalid Akeneo value data: expected an array, "%s" given.', gettype($valueData)));
}
if (!array_key_exists('scope', $valueData)) {
throw new \InvalidArgumentException('Invalid Akeneo value data: required "scope" information was not found.');
throw new InvalidArgumentException('Invalid Akeneo value data: required "scope" information was not found.');
}
if ($valueData['scope'] !== null && !in_array($valueData['scope'], $productChannelCodes, true)) {
continue;
Expand All @@ -109,7 +130,7 @@ public function handle($subject, string $attributeCode, array $value): void
* @param array|int|string|bool|null $value
*/
private function handleAttributeValue(
AttributeInterface $attribute,
ProductAttributeInterface $attribute,
$value,
string $localeCode,
ProductInterface $product,
Expand Down Expand Up @@ -137,7 +158,7 @@ private function handleAttributeValue(
$product->addAttribute($attributeValue);
}

private function hasSupportedType(AttributeInterface $attribute): bool
private function hasSupportedType(ProductAttributeInterface $attribute): bool
{
return $attribute->getType() === TextareaAttributeType::TYPE ||
$attribute->getType() === TextAttributeType::TYPE ||
Expand All @@ -156,4 +177,20 @@ private function isProductOption(ProductVariantInterface $subject, string $attri

return !$productOptions->isEmpty();
}

private function getAkeneoPimClient(): AkeneoPimClientInterface
{
$akeneoPimClient = $this->akeneoPimClient;
Assert::notNull($akeneoPimClient);

return $akeneoPimClient;
}

/**
* @return RepositoryInterface<ProductAttributeInterface>
*/
private function getAttributeRepository(): RepositoryInterface
{
return $this->attributeRepository;
}
}

0 comments on commit e3dead8

Please sign in to comment.