diff --git a/composer.json b/composer.json index 0c5539c..184f86e 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ "php": ">=7.4", "fakerphp/faker": "^1.21.0", "symfony/console": "^4.4", - "mbezhanov/faker-provider-collection": "^2.0" + "mbezhanov/faker-provider-collection": "^2.0", + "bluemmb/faker-picsum-photos-provider": "^2.0" }, "require-dev": { "prestashop/php-dev-tools": "^4.3" diff --git a/config/services.yml b/config/services.yml index 8ff9a80..7cc89a8 100644 --- a/config/services.yml +++ b/config/services.yml @@ -16,10 +16,16 @@ services: arguments: $faker: '@Faker\Generator' + PrestaShop\Module\PsFixturesCreator\Creator\ProductImageCreator: + arguments: + $faker: '@Faker\Generator' + $imageCopier : '@prestashop.adapter.import.image_copier' + PrestaShop\Module\PsFixturesCreator\Creator\ProductCreator: arguments: $langRepository: '@prestashop.core.admin.lang.repository' $featureCreator: '@PrestaShop\Module\PsFixturesCreator\Creator\FeatureCreator' + $productImageCreator: '@PrestaShop\Module\PsFixturesCreator\Creator\ProductImageCreator' $stockMovementCreator: '@PrestaShop\Module\PsFixturesCreator\Creator\StockMovementCreator' $connection: '@doctrine.dbal.default_connection' $dbPrefix: '%database_prefix%' @@ -48,6 +54,7 @@ services: $attributeCreator: '@PrestaShop\Module\PsFixturesCreator\Creator\AttributeCreator' $langRepository: '@prestashop.core.admin.lang.repository' $featureCreator: '@PrestaShop\Module\PsFixturesCreator\Creator\FeatureCreator' + $productImageCreator: '@PrestaShop\Module\PsFixturesCreator\Creator\ProductImageCreator' $stockMovementCreator: '@PrestaShop\Module\PsFixturesCreator\Creator\StockMovementCreator' $connection: '@doctrine.dbal.default_connection' $dbPrefix: '%database_prefix%' diff --git a/src/Command/ProductCreatorCommand.php b/src/Command/ProductCreatorCommand.php index ed1dcae..28601fe 100644 --- a/src/Command/ProductCreatorCommand.php +++ b/src/Command/ProductCreatorCommand.php @@ -68,6 +68,7 @@ protected function configure(): void ->addOption('features', null, InputOption::VALUE_OPTIONAL, 'Number of features per product', 2) ->addOption('featureValues', null, InputOption::VALUE_OPTIONAL, 'Number of values per feature', 5) ->addOption('stockMovements', null, InputOption::VALUE_OPTIONAL, 'Number of stock movements per product', 0) + ->addOption('images', null, InputOption::VALUE_OPTIONAL, 'Number of images per product', 0) ; } @@ -82,6 +83,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $numberOfFeatures = (int) $input->getOption('features'); $numberOfFeatureValues = (int) $input->getOption('featureValues'); $numberOfStockMovements = (int) $input->getOption('stockMovements'); + $numberOfImages = (int) $input->getOption('images'); $productsWithCombinations = (int) $input->getOption('productsWithCombinations'); // create products @@ -91,6 +93,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $numberOfFeatures, $numberOfFeatureValues, $numberOfStockMovements, + $numberOfImages, $shopId ); $output->writeln(sprintf('%s product(s) created', $numberOfProducts)); @@ -104,6 +107,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $numberOfAttributes, $numberOfFeatures, $numberOfFeatureValues, + $numberOfImages, $shopId ); $output->writeln(sprintf('%s product(s) with combinations created', $productsWithCombinations)); diff --git a/src/Creator/AbstractProductCreator.php b/src/Creator/AbstractProductCreator.php index 16dbce7..b5787c8 100644 --- a/src/Creator/AbstractProductCreator.php +++ b/src/Creator/AbstractProductCreator.php @@ -29,24 +29,31 @@ namespace PrestaShop\Module\PsFixturesCreator\Creator; use Doctrine\DBAL\Connection; +use Faker\Generator as Faker; abstract class AbstractProductCreator { protected FeatureCreator $featureCreator; + protected ProductImageCreator $productImageCreator; protected StockMovementCreator $stockMovementCreator; protected Connection $connection; protected string $dbPrefix; + protected Faker $faker; public function __construct( FeatureCreator $featureCreator, + ProductImageCreator $productImageCreator, StockMovementCreator $stockMovementCreator, Connection $connection, + Faker $faker, string $dbPrefix ) { $this->featureCreator = $featureCreator; + $this->productImageCreator = $productImageCreator; $this->stockMovementCreator = $stockMovementCreator; $this->connection = $connection; $this->dbPrefix = $dbPrefix; + $this->faker = $faker; } protected function associateFeatures(int $productId, int $numberOfFeatures, int $numberOfFeatureValues, int $shopId): void @@ -87,6 +94,15 @@ protected function associateStockMovements(int $productId, int $numberOfStockMov $this->stockMovementCreator->generate($numberOfStockMovements, $productId); } + protected function associateImages(int $productId, array $combinationsId, int $numberOfImages): void + { + if ($numberOfImages <= 0) { + return; + } + + $this->productImageCreator->generate($numberOfImages, $productId, $combinationsId); + } + protected function getRandomValues(int $featureId, int $numberOfFeatureValues): array { $featureValueIds = $this->connection->createQueryBuilder() diff --git a/src/Creator/ProductCombinationCreator.php b/src/Creator/ProductCombinationCreator.php index c7fdf2a..784bcfc 100644 --- a/src/Creator/ProductCombinationCreator.php +++ b/src/Creator/ProductCombinationCreator.php @@ -5,9 +5,10 @@ use Doctrine\DBAL\Connection; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; -use Faker\Generator; +use Faker\Generator as Faker; use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface; use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Command\GenerateProductCombinationsCommand; +use PrestaShop\PrestaShop\Core\Domain\Product\Combination\ValueObject\CombinationId; use PrestaShop\PrestaShop\Core\Domain\Product\Command\AddProductCommand; use PrestaShop\PrestaShop\Core\Domain\Product\ValueObject\ProductId; use PrestaShop\PrestaShop\Core\Domain\Product\ValueObject\ProductType; @@ -25,8 +26,6 @@ class ProductCombinationCreator extends AbstractProductCreator private AttributeCreator $attributeCreator; - private Generator $faker; - private LangRepository $langRepository; public function __construct( @@ -37,15 +36,15 @@ public function __construct( FeatureCreator $featureCreator, Connection $connection, string $dbPrefix, - Generator $faker, - StockMovementCreator $stockMovementCreator + Faker $faker, + StockMovementCreator $stockMovementCreator, + ProductImageCreator $productImageCreator ) { - parent::__construct($featureCreator, $stockMovementCreator, $connection, $dbPrefix); + parent::__construct($featureCreator, $productImageCreator, $stockMovementCreator, $connection, $faker, $dbPrefix); $this->entityManager = $entityManager; $this->commandBus = $commandBus; $this->attributeCreator = $attributeCreator; $this->langRepository = $langRepository; - $this->faker = $faker; } public function generate( @@ -54,6 +53,7 @@ public function generate( int $attributeValuePerGroupNumber, int $numberOfFeatures, int $numberOfFeatureValues, + int $numberOfImages, int $shopId ): void { $attributeGroups = $this->getAttributeGroupWithAtLeast($attributeValuePerGroupNumber); @@ -82,7 +82,7 @@ public function generate( $productNames )); - $this->commandBus->handle(new GenerateProductCombinationsCommand( + $combinationsIds = $this->commandBus->handle(new GenerateProductCombinationsCommand( $newProductId->getValue(), $combinationAttributes, $shopId ? ShopConstraint::shop($shopId) : ShopConstraint::allShops() @@ -94,7 +94,7 @@ public function generate( $productNames )); - $this->commandBus->handle(new GenerateProductCombinationsCommand( + $combinationsIds = $this->commandBus->handle(new GenerateProductCombinationsCommand( $newProductId->getValue(), $combinationAttributes, )); @@ -102,6 +102,11 @@ public function generate( throw new \RuntimeException(sprintf('Version %s not handled to generate combinations', _PS_VERSION_)); } + $combinationsIds = array_map(static function (CombinationId $combination) { + return $combination->getValue(); + }, $combinationsIds); + + $this->associateImages($newProductId->getValue(), $combinationsIds, $numberOfImages); $this->associateFeatures($newProductId->getValue(), $numberOfFeatures, $numberOfFeatureValues, $shopId); } } diff --git a/src/Creator/ProductCreator.php b/src/Creator/ProductCreator.php index 7cefa4d..fd4c7e1 100644 --- a/src/Creator/ProductCreator.php +++ b/src/Creator/ProductCreator.php @@ -11,7 +11,6 @@ class ProductCreator extends AbstractProductCreator { private LangRepository $langRepository; - private Faker $faker; public function __construct( LangRepository $langRepository, @@ -19,11 +18,11 @@ public function __construct( Connection $connection, string $dbPrefix, Faker $faker, - StockMovementCreator $stockMovementCreator + StockMovementCreator $stockMovementCreator, + ProductImageCreator $productImageCreator ) { - parent::__construct($featureCreator, $stockMovementCreator, $connection, $dbPrefix); + parent::__construct($featureCreator, $productImageCreator, $stockMovementCreator, $connection, $faker, $dbPrefix); $this->langRepository = $langRepository; - $this->faker = $faker; } public function generate( @@ -31,10 +30,12 @@ public function generate( int $numberOfFeatures, int $numberOfFeatureValues, int $numberOfStockMovements, + int $numberOfImages, int $shopId ): void { for ($i = 0; $i < $number; ++$i) { $productId = $this->createProduct($shopId); + $this->associateImages($productId, [], $numberOfImages); $this->associateStockMovements($productId, $numberOfStockMovements); $this->associateFeatures($productId, $numberOfFeatures, $numberOfFeatureValues, $shopId); } diff --git a/src/Creator/ProductImageCreator.php b/src/Creator/ProductImageCreator.php new file mode 100644 index 0000000..d46d975 --- /dev/null +++ b/src/Creator/ProductImageCreator.php @@ -0,0 +1,81 @@ +faker = $faker; + $this->faker->addProvider(new PicsumPhotosProvider($this->faker)); + $this->imageCopier = $imageCopier; + } + + public function generate(int $number, int $productId, array $combinationsId = []): void + { + if ($number <= 0) { + return; + } + + $imageIds = []; + for ($inc = 0; $inc < $number; ++$inc) { + $imageId = $this->createImage($productId, $inc === 0); + if ($imageId) { + $imageIds[] = $imageId; + } + } + + foreach ($combinationsId as $combinationId) { + $rndNumberOfImages = rand(1, $number); + $combinationImages = $rndNumberOfImages == 1 + ? $imageIds + : array_intersect_key($imageIds, array_flip(array_rand($imageIds, rand(2, $number)))); + + $this->associateCombinationImages($combinationId, $combinationImages); + } + } + + public function createImage(int $productId, bool $isCover): ?int + { + // Download the file + $url = $this->faker->imageUrl(); + $tmpFile = tempnam(sys_get_temp_dir(), 'data') . '.png'; + file_put_contents($tmpFile, file_get_contents($url)); + + // Create the object Image + $image = new Image(); + $image->id_product = $productId; + $image->position = Image::getHighestPosition($productId) + 1; + $image->cover = $isCover; + $image->add(); + + if (!$this->imageCopier->copyImg($productId, $image->id, $tmpFile, 'products', true)) { + $image->delete(); + + unlink($tmpFile); + + return null; + } + + unlink($tmpFile); + + return (int) $image->id; + } + + public function associateCombinationImages(int $combinationId, array $imageIds): void + { + $combination = new Combination($combinationId); + $combination->setImages($imageIds); + } +}