diff --git a/README.md b/README.md index 70d6fcd6..ffb49b52 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,36 @@ $ php bin/console doctrine:schema:update --force or use [Doctrine Migrations](https://symfony.com/doc/master/bundles/DoctrineMigrationsBundle/index.html). +## Fixtures + + 1. Add a new yaml file to the folder `config/packages` and name it as you wish, e.g. `my_own_fixtures.yaml`. + + 2. Fill this yaml with your own brand fixtures and don't forget to declare the definition of + your product(s) before this brand definition or use existing product(s) code. + ``` + # config/packages/my_own_fixtures.yaml + + sylius_fixtures: + suites: + my_own_brand_fixtures: + fixtures: + loevgaard_sylius_brand_plugin_brand: + options: + custom: + flux: + name: 'My brand' + slug: 'my-brand' + products: + - product_code_1 + - product_code_2 + - product_code_3 + ``` + + 3. Load your fixtures + + ```bash + php bin/console sylius:fixture:load my_own_brand_fixtures + ``` ## Installation and usage for plugin development [Find more information here](install-dev.md) diff --git a/composer.json b/composer.json index 52d9a37c..5b23367b 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,7 @@ "friends-of-behat/symfony-extension": "^1.2.1", "friends-of-behat/variadic-extension": "^1.1", "lakion/mink-debug-extension": "^1.2.3", + "matthiasnoback/symfony-config-test": "^3.0", "phpspec/phpspec": "^5.0", "phpstan/phpstan-doctrine": "^0.10", "phpstan/phpstan-shim": "^0.10", diff --git a/phpstan.neon b/phpstan.neon index 98566716..10967053 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -9,3 +9,4 @@ parameters: ignoreErrors: - '/Parameter #1 $configuration of method Symfony\Component\DependencyInjection\Extension\Extension::processConfiguration() expects Symfony\Component\Config\Definition\ConfigurationInterface, Symfony\Component\Config\Definition\ConfigurationInterface|null given./' + - '/Cannot call method scalarNode\(\) on Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface\|null/' diff --git a/src/Assigner/ProductsAssigner.php b/src/Assigner/ProductsAssigner.php new file mode 100644 index 00000000..2920b81a --- /dev/null +++ b/src/Assigner/ProductsAssigner.php @@ -0,0 +1,22 @@ +addProduct($product); + } + } + } +} diff --git a/src/Assigner/ProductsAssignerInterface.php b/src/Assigner/ProductsAssignerInterface.php new file mode 100644 index 00000000..dc450cf0 --- /dev/null +++ b/src/Assigner/ProductsAssignerInterface.php @@ -0,0 +1,17 @@ +images = new ArrayCollection(); + $this->initializeImagesCollection(); + $this->initializeProductsCollection(); } /** @@ -83,62 +77,4 @@ public function setName(string $name): void { $this->name = $name; } - - /******************************** - * ImagesAwareInterface methods * - *******************************/ - - /** - * {@inheritdoc} - */ - public function getImages(): Collection - { - return $this->images; - } - - /** - * {@inheritdoc} - */ - public function getImagesByType(string $type): Collection - { - return $this->images->filter(function (ImageInterface $image) use ($type) { - return $type === $image->getType(); - }); - } - - /** - * {@inheritdoc} - */ - public function hasImages(): bool - { - return !$this->images->isEmpty(); - } - - /** - * {@inheritdoc} - */ - public function hasImage(ImageInterface $image): bool - { - return $this->images->contains($image); - } - - /** - * {@inheritdoc} - */ - public function addImage(ImageInterface $image): void - { - $image->setOwner($this); - $this->images->add($image); - } - - /** - * {@inheritdoc} - */ - public function removeImage(ImageInterface $image): void - { - if ($this->hasImage($image)) { - $image->setOwner(null); - $this->images->removeElement($image); - } - } } diff --git a/src/Entity/BrandInterface.php b/src/Entity/BrandInterface.php index b1761360..d5870a7a 100644 --- a/src/Entity/BrandInterface.php +++ b/src/Entity/BrandInterface.php @@ -6,7 +6,7 @@ use Sylius\Component\Resource\Model\ResourceInterface; -interface BrandInterface extends ResourceInterface +interface BrandInterface extends ResourceInterface, ProductsAwareInterface, ImagesAwareInterface { /** * Returns the name of the brand diff --git a/src/Entity/ImagesAwareInterface.php b/src/Entity/ImagesAwareInterface.php new file mode 100644 index 00000000..7cf7e461 --- /dev/null +++ b/src/Entity/ImagesAwareInterface.php @@ -0,0 +1,12 @@ +images = new ArrayCollection(); + } + + /** + * {@inheritdoc} + */ + public function getImages(): Collection + { + return $this->images; + } + + /** + * {@inheritdoc} + */ + public function getImagesByType(string $type): Collection + { + return $this->images->filter(function (ImageInterface $image) use ($type) { + return $type === $image->getType(); + }); + } + + /** + * {@inheritdoc} + */ + public function hasImages(): bool + { + return !$this->images->isEmpty(); + } + + /** + * {@inheritdoc} + */ + public function hasImage(ImageInterface $image): bool + { + return $this->images->contains($image); + } + + /** + * {@inheritdoc} + */ + public function addImage(ImageInterface $image): void + { + if (false === $this->hasImage($image)) { + $image->setOwner($this); + $this->images->add($image); + } + } + + /** + * {@inheritdoc} + */ + public function removeImage(ImageInterface $image): void + { + if ($this->hasImage($image)) { + $image->setOwner(null); + $this->images->removeElement($image); + } + } +} diff --git a/src/Entity/ProductTrait.php b/src/Entity/ProductTrait.php index 4fe9edf3..902cceed 100644 --- a/src/Entity/ProductTrait.php +++ b/src/Entity/ProductTrait.php @@ -10,13 +10,13 @@ trait ProductTrait { /** * @var BrandInterface|null - * @ORM\ManyToOne(targetEntity="Loevgaard\SyliusBrandPlugin\Entity\Brand") + * @ORM\ManyToOne(targetEntity="Loevgaard\SyliusBrandPlugin\Entity\Brand", inversedBy="products") * @ORM\JoinColumn(name="brand_id", referencedColumnName="id") */ protected $brand; /** - * @return BrandInterface|null + * {@inheritdoc} */ public function getBrand(): ?BrandInterface { @@ -24,7 +24,7 @@ public function getBrand(): ?BrandInterface } /** - * @param BrandInterface|null $brand + * {@inheritdoc} */ public function setBrand(?BrandInterface $brand): void { diff --git a/src/Entity/ProductsAwareInterface.php b/src/Entity/ProductsAwareInterface.php new file mode 100644 index 00000000..502d1004 --- /dev/null +++ b/src/Entity/ProductsAwareInterface.php @@ -0,0 +1,34 @@ +products = new ArrayCollection(); + } + + /** + * {@inheritdoc} + */ + public function getProducts(): Collection + { + return $this->products; + } + + /** + * {@inheritdoc} + */ + public function hasProduct(BrandAwareInterface $product): bool + { + return $this->products->contains($product); + } + + /** + * {@inheritdoc} + */ + public function addProduct(BrandAwareInterface $product): void + { + if (false === $this->hasProduct($product)) { + /** @var ProductsAwareInterface $this */ + $product->setBrand($this); + $this->products->add($product); + } + } + + /** + * {@inheritdoc} + */ + public function removeProduct(BrandAwareInterface $product): void + { + if (true === $this->hasProduct($product)) { + $product->setBrand(null); + $this->products->removeElement($product); + } + } +} diff --git a/src/Fixture/BrandFixture.php b/src/Fixture/BrandFixture.php new file mode 100644 index 00000000..fee0957b --- /dev/null +++ b/src/Fixture/BrandFixture.php @@ -0,0 +1,33 @@ +children() + ->scalarNode('name')->cannotBeEmpty()->end() + ->scalarNode('slug')->cannotBeEmpty()->end() + ->arrayNode('products') + ->scalarPrototype()->end() + ->end(); + } +} diff --git a/src/Fixture/Factory/BrandExampleFactory.php b/src/Fixture/Factory/BrandExampleFactory.php new file mode 100644 index 00000000..77e48bd7 --- /dev/null +++ b/src/Fixture/Factory/BrandExampleFactory.php @@ -0,0 +1,82 @@ +productRepository = $productRepository; + $this->productAssigner = $productAssigner; + $this->brandFactory = $brandFactory; + + $this->optionsResolver = new OptionsResolver(); + + $this->configureOptions($this->optionsResolver); + } + + + /** + * {@inheritdoc} + */ + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver + ->setRequired('name') + ->setAllowedTypes('name', 'string') + ->setRequired('slug') + ->setAllowedTypes('slug', 'string') + ->setDefault('products', []) + ->setAllowedTypes('products', 'array') + ->setNormalizer('products', LazyOption::findBy($this->productRepository, 'code')) + ; + } + + /** + * {@inheritdoc} + */ + public function create(array $options = []): BrandInterface + { + $options = $this->optionsResolver->resolve($options); + + /** @var BrandInterface $brand */ + $brand = $this->brandFactory->createNew(); + $brand->setName($options['name']); + $brand->setSlug($options['slug']); + + $this->productAssigner->assign($brand, $options['products']); + + return $brand; + } +} diff --git a/src/Resources/config/doctrine/Brand.orm.xml b/src/Resources/config/doctrine/Brand.orm.xml index 1989b7b3..da8ae664 100644 --- a/src/Resources/config/doctrine/Brand.orm.xml +++ b/src/Resources/config/doctrine/Brand.orm.xml @@ -14,8 +14,9 @@ + - \ No newline at end of file + diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 20527b6f..6206a2ca 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -44,3 +44,23 @@ services: class: Loevgaard\SyliusBrandPlugin\Menu\AdminProductFormMenuListener tags: - { name: kernel.event_listener, event: sylius.menu.admin.product.form, method: addItems } + + loevgaard_sylius_brand.assigner.products: + class: Loevgaard\SyliusBrandPlugin\Assigner\ProductsAssigner + + loevgaard_sylius_brand.fixture.brand: + public: true + class: Loevgaard\SyliusBrandPlugin\Fixture\BrandFixture + arguments: + - '@loevgaard_sylius_brand.manager.brand' + - '@loevgaard_sylius_brand.fixture.example_factory.brand' + tags: + - { name: sylius_fixtures.fixture } + + loevgaard_sylius_brand.fixture.example_factory.brand: + public: true + class: Loevgaard\SyliusBrandPlugin\Fixture\Factory\BrandExampleFactory + arguments: + - '@sylius.repository.product' + - '@loevgaard_sylius_brand.assigner.products' + - '@loevgaard_sylius_brand.factory.brand' diff --git a/tests/Fixture/BrandFixtureTest.php b/tests/Fixture/BrandFixtureTest.php new file mode 100644 index 00000000..4aa282c9 --- /dev/null +++ b/tests/Fixture/BrandFixtureTest.php @@ -0,0 +1,46 @@ +assertConfigurationIsValid([[]], 'custom'); + } + + /** @test */ + public function brand_can_be_generated_randomly(): void + { + $this->assertConfigurationIsValid([['random' => 4]], 'random'); + $this->assertPartialConfigurationIsInvalid([['random' => -1]], 'random'); + } + + /** @test */ + public function brand_products_is_optional(): void + { + $this->assertConfigurationIsValid([['custom' => [['products' => []]]]], 'custom.*.products'); + } + + /** + * {@inheritdoc} + */ + protected function getConfiguration(): BrandFixture + { + return new BrandFixture( + $this->getMockBuilder(ObjectManager::class)->getMock(), + $this->getMockBuilder(ExampleFactoryInterface::class)->getMock() + ); + } +}