Skip to content

Commit ebaeeb5

Browse files
committed
ACP2E-4223: Improved validation for rest api
1 parent e490559 commit ebaeeb5

File tree

2 files changed

+182
-3
lines changed

2 files changed

+182
-3
lines changed

app/code/Magento/Customer/Model/Attribute/Data/Postcode.php

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88

99
use Magento\Directory\Helper\Data as DirectoryHelper;
1010
use Magento\Eav\Model\AttributeDataFactory;
11+
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
12+
use Magento\Framework\App\ObjectManager;
1113
use Magento\Framework\App\RequestInterface;
1214
use Magento\Framework\Locale\ResolverInterface;
15+
use Magento\Framework\Stdlib\StringUtils;
1316
use Psr\Log\LoggerInterface as PsrLogger;
1417
use Magento\Framework\Stdlib\DateTime\TimezoneInterface as MagentoTimezone;
1518

@@ -25,19 +28,27 @@ class Postcode extends \Magento\Eav\Model\Attribute\Data\AbstractData
2528
*/
2629
protected $directoryHelper;
2730

31+
/**
32+
* @var StringUtils|null
33+
*/
34+
private $string;
35+
2836
/**
2937
* @param MagentoTimezone $localeDate
3038
* @param PsrLogger $logger
3139
* @param ResolverInterface $localeResolver
3240
* @param DirectoryHelper $directoryHelper
41+
* @param StringUtils|null $stringHelper
3342
*/
3443
public function __construct(
3544
MagentoTimezone $localeDate,
3645
PsrLogger $logger,
3746
ResolverInterface $localeResolver,
38-
DirectoryHelper $directoryHelper
47+
DirectoryHelper $directoryHelper,
48+
?StringUtils $stringHelper
3949
) {
4050
$this->directoryHelper = $directoryHelper;
51+
$this->string = $stringHelper ?? ObjectManager::getInstance()->get(StringUtils::class);
4152
parent::__construct($localeDate, $logger, $localeResolver);
4253
}
4354

@@ -63,6 +74,13 @@ public function validateValue($value)
6374
$label = __($attribute->getStoreLabel());
6475
$errors[] = __('"%1" is a required value.', $label);
6576
}
77+
78+
$validateLengthResult = $this->validateLength($attribute, $value);
79+
$errors = array_merge($errors, $validateLengthResult);
80+
81+
$validateInputRuleResult = $this->validateInputRule($value);
82+
$errors = array_merge($errors, $validateInputRuleResult);
83+
6684
if (count($errors) == 0) {
6785
return true;
6886
}
@@ -120,4 +138,45 @@ public function outputValue($format = AttributeDataFactory::OUTPUT_FORMAT_TEXT)
120138
$value = $this->_applyOutputFilter($value);
121139
return $value;
122140
}
141+
142+
/**
143+
* Validates value length by attribute rules
144+
*
145+
* @param AbstractAttribute $attribute
146+
* @param string $value
147+
* @return array errors
148+
*/
149+
private function validateLength(AbstractAttribute $attribute, string $value): array
150+
{
151+
$errors = [];
152+
$length = $this->string->strlen(trim($value));
153+
$validateRules = $attribute->getValidateRules();
154+
155+
if (!empty($validateRules['input_validation'])) {
156+
if (!empty($validateRules['min_text_length']) && $length < $validateRules['min_text_length']) {
157+
$label = __($attribute->getStoreLabel());
158+
$v = $validateRules['min_text_length'];
159+
$errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $v);
160+
}
161+
if (!empty($validateRules['max_text_length']) && $length > $validateRules['max_text_length']) {
162+
$label = __($attribute->getStoreLabel());
163+
$v = $validateRules['max_text_length'];
164+
$errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $v);
165+
}
166+
}
167+
168+
return $errors;
169+
}
170+
171+
/**
172+
* Validate value by attribute input validation rule.
173+
*
174+
* @param string $value
175+
* @return array
176+
*/
177+
private function validateInputRule(string $value): array
178+
{
179+
$result = $this->_validateInputRule($value);
180+
return \is_array($result) ? $result : [];
181+
}
123182
}

app/code/Magento/Customer/Test/Unit/Model/Attribute/Data/PostcodeTest.php

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
1313
use Magento\Framework\Locale\ResolverInterface;
1414
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
15+
use Magento\Framework\Stdlib\StringUtils;
1516
use PHPUnit\Framework\MockObject\MockObject;
1617
use PHPUnit\Framework\TestCase;
1718
use Psr\Log\LoggerInterface;
@@ -43,6 +44,11 @@ class PostcodeTest extends TestCase
4344
*/
4445
private $loggerMock;
4546

47+
/**
48+
* @var StringUtils|MockObject
49+
*/
50+
private $stringHelperMock;
51+
4652
protected function setUp(): void
4753
{
4854
$this->localeMock = $this->getMockBuilder(TimezoneInterface::class)
@@ -54,9 +60,12 @@ protected function setUp(): void
5460
$this->directoryHelperMock = $this->getMockBuilder(\Magento\Directory\Helper\Data::class)
5561
->disableOriginalConstructor()
5662
->getMock();
63+
$this->stringHelperMock = $this->getMockBuilder(StringUtils::class)
64+
->disableOriginalConstructor()
65+
->getMock();
5766
$this->attributeMock = $this->getMockBuilder(AbstractAttribute::class)
5867
->disableOriginalConstructor()
59-
->addMethods(['getStoreLabel'])
68+
->addMethods(['getStoreLabel', 'getValidateRules'])
6069
->getMock();
6170
}
6271

@@ -85,7 +94,8 @@ public function testValidateValue($value, $expected, $countryId, $isOptional)
8594
$this->localeMock,
8695
$this->loggerMock,
8796
$this->localeResolverMock,
88-
$this->directoryHelperMock
97+
$this->directoryHelperMock,
98+
$this->stringHelperMock
8999
);
90100
$object->setAttribute($this->attributeMock);
91101
$object->setExtractedData(['country_id' => $countryId]);
@@ -106,4 +116,114 @@ public static function validateValueDataProvider()
106116
['90034', true, 'IE', true],
107117
];
108118
}
119+
120+
/**
121+
* Test validation of length and input rules
122+
*
123+
* @param string $value
124+
* @param bool|array $expected
125+
* @param array $validateRules
126+
* @param string $countryId
127+
* @param bool $isOptional
128+
*
129+
* @dataProvider validateValueWithRulesDataProvider
130+
*/
131+
public function testValidateValueWithRules(
132+
string $value,
133+
bool|array $expected,
134+
array $validateRules,
135+
string $countryId,
136+
bool $isOptional
137+
) {
138+
$storeLabel = 'Zip/Postal Code';
139+
$this->attributeMock->expects($this->any())
140+
->method('getStoreLabel')
141+
->willReturn($storeLabel);
142+
143+
$this->attributeMock->expects($this->any())
144+
->method('getValidateRules')
145+
->willReturn($validateRules);
146+
147+
$this->directoryHelperMock->expects($this->once())
148+
->method('isZipCodeOptional')
149+
->willReturnMap([
150+
[$countryId, $isOptional],
151+
]);
152+
153+
if (!empty($validateRules['max_text_length'])) {
154+
$this->stringHelperMock->expects($this->any())
155+
->method('strlen')
156+
->willReturnCallback(function ($str) {
157+
return strlen(trim($str));
158+
});
159+
}
160+
161+
$object = new Postcode(
162+
$this->localeMock,
163+
$this->loggerMock,
164+
$this->localeResolverMock,
165+
$this->directoryHelperMock,
166+
$this->stringHelperMock
167+
);
168+
$object->setAttribute($this->attributeMock);
169+
$object->setExtractedData(['country_id' => $countryId]);
170+
171+
$actual = $object->validateValue($value);
172+
173+
if (is_array($expected)) {
174+
$this->assertIsArray($actual);
175+
$this->assertCount(count($expected), $actual);
176+
foreach ($expected as $key => $expectedMessage) {
177+
$actualMessage = $actual[$key];
178+
// Convert Phrase to string if needed
179+
if ($actualMessage instanceof \Magento\Framework\Phrase) {
180+
$actualMessage = $actualMessage->__toString();
181+
}
182+
$this->assertStringContainsString($expectedMessage, $actualMessage);
183+
}
184+
} else {
185+
$this->assertEquals($expected, $actual);
186+
}
187+
}
188+
189+
/**
190+
* @return array
191+
*/
192+
public static function validateValueWithRulesDataProvider()
193+
{
194+
return [
195+
// Test min length validation
196+
[
197+
'12',
198+
['"Zip/Postal Code" length must be equal or greater than 5 characters.'],
199+
['input_validation' => 'alphanumeric', 'min_text_length' => 5],
200+
'US',
201+
false
202+
],
203+
// Test max length validation
204+
[
205+
'1234567890',
206+
['"Zip/Postal Code" length must be equal or less than 6 characters.'],
207+
['input_validation' => 'alphanumeric', 'max_text_length' => 6],
208+
'US',
209+
false
210+
],
211+
// Test valid length
212+
[
213+
'12345',
214+
true,
215+
['input_validation' => 'alphanumeric', 'min_text_length' => 5, 'max_text_length' => 6],
216+
'US',
217+
false
218+
],
219+
// Test no validation rules
220+
[
221+
'90034',
222+
true,
223+
[],
224+
'US',
225+
false
226+
],
227+
];
228+
}
109229
}

0 commit comments

Comments
 (0)