From 829137ef7e7ec59187a7b721874280cbd00ee05e Mon Sep 17 00:00:00 2001 From: Piotr Lewandowski Date: Thu, 30 Sep 2021 10:19:03 +0200 Subject: [PATCH] #3 Select attribute throws error (#7) Resolve #3 --- .github/ISSUE_TEMPLATE/bug_report.md | 31 ++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++ README.md | 7 +++ .../Provider/AttributeOptionsProvider.php | 27 ++++++++- src/Matcher/SizeChartValidator.php | 36 +++++++++-- tests/Unit/Matcher/SizeChartValidatorTest.php | 60 ++++++++++++++++++- 6 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..308ed1f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Sylius and PHP version:** + - Sylius 1.9 + - PHP 7.4 + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..e0c0168 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FEATURE]" +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/README.md b/README.md index f5c8da6..21f15bf 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,11 @@ imports: madcoders_sylius_sizechart_plugin: resource: "@MadcodersSyliusSizechartPlugin/Resources/config/routing.yaml" ``` +5. Run migrations: +```bash +php bin/console doctrine:migrations:migrate +``` + ## Development * See [How to contribute](docs/CONTRIBUTING.md) @@ -55,3 +60,5 @@ Developed by [MADCODERS](https://madcoders.co) Architects of this package: - [Piotr Lewandowski](https://github.com/plewandowski) - [Leonid Moshko](https://github.com/LeoMoshko) + +Buy Me A Coffee diff --git a/src/Form/Provider/AttributeOptionsProvider.php b/src/Form/Provider/AttributeOptionsProvider.php index b45076f..bbbb8be 100644 --- a/src/Form/Provider/AttributeOptionsProvider.php +++ b/src/Form/Provider/AttributeOptionsProvider.php @@ -17,6 +17,9 @@ namespace Madcoders\SyliusSizechartPlugin\Form\Provider; use Sylius\Bundle\ProductBundle\Doctrine\ORM\ProductAttributeValueRepository; +use Sylius\Component\Attribute\AttributeType\IntegerAttributeType; +use Sylius\Component\Attribute\AttributeType\SelectAttributeType; +use Sylius\Component\Attribute\AttributeType\TextAttributeType; use Sylius\Component\Product\Model\ProductAttributeInterface; use Sylius\Component\Product\Model\ProductAttributeValueInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; @@ -59,8 +62,28 @@ public function provideOptionsByAttributeCode(string $code): array $choices = []; foreach($qb->getQuery()->getResult() as $value) { /** @var ProductAttributeValueInterface $value */ - $index = (string)$value->getValue(); - $choices[$index] = $value->getValue(); + switch($value->getType()) { + case SelectAttributeType::TYPE: + /** @var string[] $values */ + $values = $value->getValue(); + foreach($values as $index) { + if (!$value->getAttribute()) { + continue; + } + $config = $value->getAttribute()->getConfiguration(); + /** @var array $attributeChoices */ + $attributeChoices = $config['choices'] ?? []; + $label = (string)($attributeChoices[$index][$this->localeCode] ?? ''); + $choices[$label] = $index; + } + break; + case IntegerAttributeType::TYPE: + case TextAttributeType::TYPE: + default: + $textValue = (string)$value->getValue(); + $choices[$textValue] = $textValue; + break; + } } return $choices; diff --git a/src/Matcher/SizeChartValidator.php b/src/Matcher/SizeChartValidator.php index b7153ca..f378ef3 100644 --- a/src/Matcher/SizeChartValidator.php +++ b/src/Matcher/SizeChartValidator.php @@ -17,8 +17,10 @@ namespace Madcoders\SyliusSizechartPlugin\Matcher; use Madcoders\SyliusSizechartPlugin\Entity\SizeChartInterface; +use Sylius\Component\Attribute\AttributeType\IntegerAttributeType; +use Sylius\Component\Attribute\AttributeType\SelectAttributeType; +use Sylius\Component\Attribute\AttributeType\TextAttributeType; use Sylius\Component\Core\Model\ProductInterface; -use Sylius\Component\Product\Model\ProductAttributeInterface; final class SizeChartValidator implements SizeChartValidatorInterface { @@ -39,14 +41,40 @@ public function isValidForTheProduct(SizeChartInterface $sizeChart, ProductInter /** @var string[] $attributeCodes */ $attributeCodes = $criteria['attributes'] ?? []; - foreach($attributeCodes as $attributeCode) { + foreach ($attributeCodes as $attributeCode) { /** @var string $value */ - $value = $criteria['attribute' . $attributeCode ] ?? ''; + $value = $criteria['attribute' . $attributeCode] ?? ''; $productAttributeValue = $product->getAttributeByCodeAndLocale($attributeCode, $this->localeCode); - if (!$productAttributeValue || $productAttributeValue->getValue() !== $value) { + if (!$productAttributeValue) { return false; } + + if (!$productAttributeValue->getAttribute()) { + return false; + } + + switch ($productAttributeValue->getAttribute()->getType()) { + case SelectAttributeType::TYPE: + /** @var array|null $selectAttributeValue */ + $selectAttributeValue = $productAttributeValue->getValue(); + if (!is_array($selectAttributeValue)) { + return false; + } + + if (!in_array($value, $selectAttributeValue)) { + return false; + } + + break; + case IntegerAttributeType::TYPE: + case TextAttributeType::TYPE: + default: + if ($productAttributeValue->getValue() !== $value) { + return false; + } + break; + } } return true; diff --git a/tests/Unit/Matcher/SizeChartValidatorTest.php b/tests/Unit/Matcher/SizeChartValidatorTest.php index 5780960..1d8c706 100644 --- a/tests/Unit/Matcher/SizeChartValidatorTest.php +++ b/tests/Unit/Matcher/SizeChartValidatorTest.php @@ -19,6 +19,8 @@ use Madcoders\SyliusSizechartPlugin\Entity\SizeChartInterface; use Madcoders\SyliusSizechartPlugin\Matcher\SizeChartValidator; use Prophecy\Argument; +use Sylius\Component\Attribute\AttributeType\SelectAttributeType; +use Sylius\Component\Attribute\AttributeType\TextAttributeType; use Sylius\Component\Core\Model\ProductInterface; use Sylius\Component\Product\Model\ProductAttributeInterface; use Sylius\Component\Product\Model\ProductAttributeValueInterface; @@ -35,7 +37,7 @@ function it_returns_true_when_there_are_no_attributes_in_criteria_defined() $product = $this->prophesize(ProductInterface::class); $sizeChart = $this->prophesize(SizeChartInterface::class); $sizeChart->getCriteria()->willReturn([ 'attributes' => [] ]); - $validator = new SizeChartValidator(); + $validator = new SizeChartValidator('en_US'); // when $result = $validator->isValidForTheProduct($sizeChart->reveal(), $product->reveal()); @@ -50,10 +52,17 @@ function it_returns_true_when_there_are_no_attributes_in_criteria_defined() function it_returns_true_when_all_criteria_are_matched() { // given + $attributeA = $this->prophesize(ProductAttributeInterface::class); + $attributeA->getType()->willReturn(TextAttributeType::TYPE); + $attributeB = $this->prophesize(ProductAttributeInterface::class); + $attributeB->getType()->willReturn(TextAttributeType::TYPE); + $valueX = $this->prophesize(ProductAttributeValueInterface::class); $valueX->getValue()->willReturn('x'); + $valueX->getAttribute()->willReturn($attributeA->reveal()); $valueY = $this->prophesize(ProductAttributeValueInterface::class); $valueY->getValue()->willReturn('y'); + $valueY->getAttribute()->willReturn($attributeB->reveal()); $product = $this->prophesize(ProductInterface::class); $product->getAttributeByCodeAndLocale('A', Argument::any())->willReturn($valueX->reveal()); @@ -66,7 +75,7 @@ function it_returns_true_when_all_criteria_are_matched() 'attributeB' => 'y', ]); - $validator = new SizeChartValidator(); + $validator = new SizeChartValidator('en_US'); // when $result = $validator->isValidForTheProduct($sizeChart->reveal(), $product->reveal()); @@ -81,10 +90,17 @@ function it_returns_true_when_all_criteria_are_matched() function it_returns_false_when_a_criteria_fails() { // given + $attributeA = $this->prophesize(ProductAttributeInterface::class); + $attributeA->getType()->willReturn(TextAttributeType::TYPE); + $attributeB = $this->prophesize(ProductAttributeInterface::class); + $attributeB->getType()->willReturn(TextAttributeType::TYPE); + $valueX = $this->prophesize(ProductAttributeValueInterface::class); $valueX->getValue()->willReturn('x'); + $valueX->getAttribute()->willReturn($attributeA->reveal()); $valueY = $this->prophesize(ProductAttributeValueInterface::class); $valueY->getValue()->willReturn('VALUE_THAT_IS_NOT_SELECTED_IN_CRITERIA'); + $valueY->getAttribute()->willReturn($attributeB->reveal()); $product = $this->prophesize(ProductInterface::class); $product->getAttributeByCodeAndLocale('A', Argument::any())->willReturn($valueX->reveal()); @@ -97,7 +113,7 @@ function it_returns_false_when_a_criteria_fails() 'attributeB' => 'y', ]); - $validator = new SizeChartValidator(); + $validator = new SizeChartValidator('en_US'); // when $result = $validator->isValidForTheProduct($sizeChart->reveal(), $product->reveal()); @@ -105,4 +121,42 @@ function it_returns_false_when_a_criteria_fails() // then $this->assertFalse($result); } + + /** + * @test + */ + function it_supports_select_attributes() + { + // given + $attributeA = $this->prophesize(ProductAttributeInterface::class); + $attributeA->getType()->willReturn(SelectAttributeType::TYPE); + $attributeB = $this->prophesize(ProductAttributeInterface::class); + $attributeB->getType()->willReturn(SelectAttributeType::TYPE); + + $valueX = $this->prophesize(ProductAttributeValueInterface::class); + $valueX->getValue()->willReturn(['x']); + $valueX->getAttribute()->willReturn($attributeA->reveal()); + $valueY = $this->prophesize(ProductAttributeValueInterface::class); + $valueY->getValue()->willReturn(['y']); + $valueY->getAttribute()->willReturn($attributeB->reveal()); + + $product = $this->prophesize(ProductInterface::class); + $product->getAttributeByCodeAndLocale('A', Argument::any())->willReturn($valueX->reveal()); + $product->getAttributeByCodeAndLocale('B', Argument::any())->willReturn($valueY->reveal()); + + $sizeChart = $this->prophesize(SizeChartInterface::class); + $sizeChart->getCriteria()->willReturn([ + 'attributes' => [ 'A', 'B' ], + 'attributeA' => 'x', + 'attributeB' => 'y', + ]); + + $validator = new SizeChartValidator('en_US'); + + // when + $result = $validator->isValidForTheProduct($sizeChart->reveal(), $product->reveal()); + + // then + $this->assertTrue($result); + } }