tddwizard/magento2-fixtures

View on GitHub
src/Catalog/OptionBuilder.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
declare(strict_types=1);

namespace TddWizard\Fixtures\Catalog;

use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
use Magento\Catalog\Model\Product;
use Magento\Eav\Api\AttributeOptionManagementInterface;
use Magento\Eav\Api\Data\AttributeOptionLabelInterface;
use Magento\Eav\Model\Entity\Attribute\Option as AttributeOption;
use Magento\TestFramework\Helper\Bootstrap;

/**
 * Create a source-model option for an attribute.
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class OptionBuilder
{

    /**
     * @var AttributeOptionManagementInterface
     */
    private $optionManagement;

    /**
     * @var AttributeOption
     */
    private $option;

    /**
     * @var AttributeOptionLabelInterface
     */
    private $optionLabel;

    /**
     * @var string
     */
    private $attributeCode;

    /**
     * OptionBuilder constructor.
     *
     * @param AttributeOptionManagementInterface $optionManagement
     * @param AttributeOption $option
     * @param AttributeOptionLabelInterface $optionLabel
     * @param string $attributeCode
     */
    public function __construct(
        AttributeOptionManagementInterface $optionManagement,
        AttributeOption $option,
        AttributeOptionLabelInterface $optionLabel,
        string $attributeCode
    ) {
        $this->optionManagement = $optionManagement;
        $this->option = $option;
        $this->optionLabel = $optionLabel;
        $this->attributeCode = $attributeCode;
    }

    /**
     * Clone the builder.
     */
    public function __clone()
    {
        $this->option = clone $this->option;
    }

    /**
     * Create an option.
     *
     * @param string $attributeCode
     * @return OptionBuilder
     * @throws \Magento\Framework\Exception\InputException
     * @throws \Magento\Framework\Exception\StateException
     */
    public static function anOptionFor(string $attributeCode): OptionBuilder
    {
        $objectManager = Bootstrap::getObjectManager();
        /** @var AttributeOptionManagementInterface $optionManagement */
        $optionManagement = $objectManager->create(AttributeOptionManagementInterface::class);
        $items = $optionManagement->getItems(Product::ENTITY, $attributeCode);

        /** @var AttributeOptionLabelInterface $optionLabel */
        $optionLabel = $objectManager->create(AttributeOptionLabelInterface::class);
        $label = uniqid('Name ', true);
        $optionLabel->setStoreId(0);
        $optionLabel->setLabel($label);

        /** @var AttributeOption $option */
        $option = $objectManager->create(AttributeOption::class);
        $option->setLabel($label);
        $option->setStoreLabels([$optionLabel]);
        $option->setSortOrder(count($items) + 1);
        $option->setIsDefault(false);

        return new static(
            $optionManagement,
            $option,
            $optionLabel,
            $attributeCode
        );
    }

    /**
     * Set label.
     *
     * @param string $label
     * @return OptionBuilder
     */
    public function withLabel(string $label): OptionBuilder
    {
        $builder = clone $this;
        $builder->optionLabel->setLabel($label);
        $builder->option->setStoreLabels([$builder->optionLabel]);
        $builder->option->setLabel($label);

        return $builder;
    }

    /**
     * Set sort order.
     *
     * @param int $sortOrder
     * @return OptionBuilder
     */
    public function withSortOrder(int $sortOrder): OptionBuilder
    {
        $builder = clone $this;
        $builder->option->setSortOrder($sortOrder);

        return $builder;
    }

    /**
     * Set default.
     *
     * @param bool $isDefault
     * @return OptionBuilder
     */
    public function withIsDefault(bool $isDefault): OptionBuilder
    {
        $builder = clone $this;
        $builder->option->setIsDefault($isDefault);

        return $builder;
    }

    /**
     * Set store ID.
     *
     * @param int $storeId
     * @return OptionBuilder
     */
    public function withStoreId(int $storeId): OptionBuilder
    {
        $builder = clone $this;
        $builder->optionLabel->setStoreId($storeId);

        return $builder;
    }

    /**
     * Build the option and apply it to the attribute.
     *
     * @return AttributeOption
     * @throws \Magento\Framework\Exception\InputException
     * @throws \Magento\Framework\Exception\StateException
     */
    public function build(): AttributeOption
    {
        $builder = clone $this;

        // add the option
        $this->optionManagement->add(
            \Magento\Catalog\Model\Product::ENTITY,
            $builder->attributeCode,
            $builder->option
        );

        $optionId = $this->getOptionId();
        $builder->option->setId($optionId);

        return $builder->option;
    }

    /**
     * Get the option ID.
     *
     * @return int
     */
    private function getOptionId(): int
    {
        $objectManager = Bootstrap::getObjectManager();
        // the add option above does not return the option, so we need to retrieve it
        $attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class);
        $attribute = $attributeRepository->get($this->attributeCode);
        $attributeValues[$attribute->getAttributeId()] = [];

        // We have to generate a new sourceModel instance each time through to prevent it from
        // referencing its _options cache. No other way to get it to pick up newly-added values.
        $tableFactory = $objectManager->get(\Magento\Eav\Model\Entity\Attribute\Source\TableFactory::class);
        $sourceModel = $tableFactory->create();
        $sourceModel->setAttribute($attribute);
        foreach ($sourceModel->getAllOptions() as $option) {
            $attributeValues[$attribute->getAttributeId()][$option['label']] = $option['value'];
        }
        if (isset($attributeValues[$attribute->getAttributeId()][$this->optionLabel->getLabel()])) {
            return (int)$attributeValues[$attribute->getAttributeId()][$this->optionLabel->getLabel()];
        }

        throw new \RuntimeException('Error building option');
    }
}