Last active
July 8, 2020 12:43
-
-
Save igormukhingmailcom/31c5beae4c98aacead603bd827a1d3e4 to your computer and use it in GitHub Desktop.
Enable ability to specify Product's price/originalPrice at Sylius fixtures
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App\Fixture; | |
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; | |
trait PriceAwareProductFixtureTrait | |
{ | |
protected function configurePricesResourceNode(ArrayNodeDefinition $resourceNode): void | |
{ | |
$childrenNode = $resourceNode->children(); | |
$childrenNode->variableNode('prices'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App\Fixture\Factory; | |
use Sylius\Component\Core\Model\ChannelPricingInterface; | |
use Sylius\Component\Core\Model\ProductInterface; | |
use Sylius\Component\Core\Model\ProductVariantInterface; | |
use Symfony\Component\OptionsResolver\Options; | |
use Symfony\Component\OptionsResolver\OptionsResolver; | |
/** | |
* @see https://github.com/Sylius/Sylius/pull/10794/files | |
* | |
* sylius_fixtures: | |
* suites: | |
* default: | |
* fixtures: | |
* app_product: | |
* options: | |
* custom: | |
* - name: Common prices product | |
* prices: 10.00 | |
* | |
* - name: Random common prices product | |
* prices: [10.00, 11.00, 12.00] # Random one from this list will be applied | |
* | |
* - name: Common prices discounted product | |
* prices: | |
* price: 10.00 | |
* originalPrice: 15.00 | |
* | |
* - name: Common random prices discounted product | |
* prices: | |
* price: [10.00, 11.00, 12.00] # Random one from this list will be applied | |
* originalPrice: 15.00 | |
* | |
* - name: Different channel prices product | |
* prices: | |
* FASHION_WEB: 10.00 | |
* | |
* - name: Different channel prices discounted product | |
* prices: | |
* FASHION_WEB: | |
* price: 10.00 | |
* originalPrice: 15.00 | |
* | |
* - name: Random channel prices product | |
* prices: | |
* FASHION_WEB: | |
* price: [10.00, 11.00, 12.00] # Random one from this list will be applied | |
* originalPrice: 15.00 | |
* | |
*/ | |
trait PricesAwareProductExampleFactoryTrait | |
{ | |
public function updatePrices(ProductInterface $product, array $resolvedOptions = []): void | |
{ | |
if (!array_key_exists('prices', $resolvedOptions)) { | |
return; | |
} | |
$prices = $resolvedOptions['prices']; | |
if (null === $prices) { | |
return; | |
} | |
/** @var ProductVariantInterface $variant */ | |
foreach ($product->getVariants() as $variant) { | |
foreach ($variant->getChannelPricings() as $channelPricing) { | |
$pricesForChannel = $this->getPricesForChannel($channelPricing->getChannelCode(), $prices); | |
$this->setChannelPricingsPrices($channelPricing, $pricesForChannel); | |
} | |
} | |
} | |
protected function configurePricesOptions(OptionsResolver $resolver): void | |
{ | |
$resolver | |
->setDefault('prices', null) | |
->setAllowedTypes('prices', ['null', 'int', 'double', 'array']) | |
->setNormalizer('prices', \Closure::fromCallable([$this, 'normalizePrices'])) | |
; | |
} | |
/** | |
* @param array|int|float|null $value | |
* @return array|int|null | |
*/ | |
protected function normalizePrices(Options $options, $value) | |
{ | |
if (null === $value) { | |
return null; | |
} | |
if (is_array($value)) { | |
foreach ($value as $key => $v) { | |
$value[$key] = $this->normalizePrices($options, $v); | |
} | |
return $value; | |
} | |
return (int) (100 * $value); | |
} | |
/** | |
* Check whether prices is common for all channels | |
* | |
* @param array|int|null $prices | |
*/ | |
protected function isCommonPrices($prices): bool | |
{ | |
if (is_int($prices)) { | |
return true; | |
} | |
if (is_array($prices)) { | |
return $this->hasSubprices($prices); | |
} | |
return false; | |
} | |
/** | |
* @param array|int|null $prices | |
*/ | |
protected function hasSubprices($prices): bool | |
{ | |
return array_key_exists('price', $prices) || array_key_exists('originalPrice', $prices); | |
} | |
/** | |
* @param array|int|null $prices | |
* @return array|int|null | |
*/ | |
protected function getPricesForChannel(string $channelCode, $prices) | |
{ | |
if ($this->isCommonPrices($prices)) { | |
return $prices; | |
} | |
return $prices[$channelCode]; | |
} | |
/** | |
* @param array|int|null $prices | |
*/ | |
protected function setChannelPricingsPrices(ChannelPricingInterface $channelPricing, $prices): void | |
{ | |
if (null === $prices) { | |
return; | |
} | |
if (!is_array($prices)) { | |
$channelPricing->setPrice($prices); | |
return; | |
} | |
if (!$this->hasSubprices($prices)) { | |
// Random item from list | |
$channelPricing->setPrice($prices[random_int(0, count($prices) - 1)]); | |
} | |
if (array_key_exists('price', $prices)) { | |
if (is_array($prices['price'])) { | |
// Random item from list | |
$channelPricing->setPrice($prices['price'][random_int(0, count($prices['price']) - 1)]); | |
} else { | |
$channelPricing->setPrice($prices['price']); | |
} | |
} | |
if (array_key_exists('originalPrice', $prices)) { | |
if (is_array($prices['originalPrice'])) { | |
// Random item from list | |
$channelPricing->setPrice($prices['originalPrice'][random_int(0, count($prices['originalPrice']) - 1)]); | |
} else { | |
$channelPricing->setOriginalPrice($prices['originalPrice']); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App\Fixture\Factory; | |
use Sylius\Bundle\CoreBundle\Fixture\Factory\ProductExampleFactory as BaseProductExampleFactory; | |
use Sylius\Component\Core\Model\ProductInterface; | |
use Sylius\Component\Core\Uploader\ImageUploaderInterface; | |
use Sylius\Component\Product\Generator\ProductVariantGeneratorInterface; | |
use Sylius\Component\Product\Generator\SlugGeneratorInterface; | |
use Sylius\Component\Resource\Factory\FactoryInterface; | |
use Sylius\Component\Resource\Repository\RepositoryInterface; | |
use Symfony\Component\Config\FileLocatorInterface; | |
use Symfony\Component\OptionsResolver\OptionsResolver; | |
class ProductExampleFactory extends BaseProductExampleFactory | |
{ | |
use PricesAwareProductExampleFactoryTrait; | |
/** @var OptionsResolver */ | |
protected $optionsResolver; | |
public function __construct(FactoryInterface $productFactory, FactoryInterface $productVariantFactory, FactoryInterface $channelPricing, ProductVariantGeneratorInterface $variantGenerator, FactoryInterface $productAttributeValueFactory, FactoryInterface $productImageFactory, FactoryInterface $productProductFactory, ImageUploaderInterface $imageUploader, SlugGeneratorInterface $slugGenerator, RepositoryInterface $productRepository, RepositoryInterface $productAttributeRepository, RepositoryInterface $productOptionRepository, RepositoryInterface $channelRepository, RepositoryInterface $localeRepository, ?RepositoryInterface $taxCategoryRepository = null, ?FileLocatorInterface $fileLocator = null) | |
{ | |
parent::__construct($productFactory, $productVariantFactory, $channelPricing, $variantGenerator, $productAttributeValueFactory, $productImageFactory, $productProductFactory, $imageUploader, $slugGenerator, $productRepository, $productAttributeRepository, $productOptionRepository, $channelRepository, $localeRepository, $taxCategoryRepository, $fileLocator); | |
$this->optionsResolver = new OptionsResolver(); | |
$this->configureOptions($this->optionsResolver); | |
} | |
public function create(array $options = []): ProductInterface | |
{ | |
/** @var ProductInterface $product */ | |
$product = parent::create($options); | |
$options = $this->optionsResolver->resolve($options); | |
$this->updatePrices($product, $options); | |
return $product; | |
} | |
protected function configureOptions(OptionsResolver $resolver): void | |
{ | |
parent::configureOptions($resolver); | |
$this->configurePricesOptions($resolver); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App\Fixture; | |
use Sylius\Bundle\CoreBundle\Fixture\ProductFixture as BaseProductFixture; | |
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; | |
class ProductFixture extends BaseProductFixture | |
{ | |
use PriceAwareProductFixtureTrait; | |
public function getName(): string | |
{ | |
return 'app_product'; | |
} | |
protected function configureResourceNode(ArrayNodeDefinition $resourceNode): void | |
{ | |
parent::configureResourceNode($resourceNode); | |
$this->configurePricesResourceNode($resourceNode); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment