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)
+
+
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);
+ }
}