Skip to content

Commit 3ba8875

Browse files
committed
Merge remote-tracking branch 'origin/AC-13535' into spartans_pr_03092025
2 parents 0968118 + 5b3b234 commit 3ba8875

File tree

4 files changed

+649
-2
lines changed

4 files changed

+649
-2
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Customer\Plugin;
10+
11+
use Magento\Customer\Api\Data\CustomerInterface;
12+
use Magento\Customer\Api\CustomerRepositoryInterface;
13+
use Magento\Eav\Model\Config as EavConfig;
14+
use Magento\Framework\Exception\InputException;
15+
use Magento\Framework\Serialize\Serializer\Json as JsonSerializer;
16+
use Magento\Framework\Stdlib\DateTime;
17+
18+
class ValidateDobOnSave
19+
{
20+
/**
21+
* @var EavConfig
22+
*/
23+
private $eavConfig;
24+
25+
/**
26+
* @var JsonSerializer
27+
*/
28+
private $json;
29+
30+
/**
31+
* @param EavConfig $eavConfig
32+
* @param JsonSerializer $json
33+
*/
34+
public function __construct(
35+
EavConfig $eavConfig,
36+
JsonSerializer $json
37+
) {
38+
$this->eavConfig = $eavConfig;
39+
$this->json = $json;
40+
}
41+
42+
/**
43+
* Enforce DOB min/max from attribute validate_rules on every save.
44+
*
45+
* @param CustomerRepositoryInterface $subject
46+
* @param callable $proceed
47+
* @param CustomerInterface $customer
48+
* @param string|null $passwordHash
49+
* @return mixed
50+
* @throws InputException
51+
* @throws \Magento\Framework\Exception\LocalizedException
52+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
53+
* @SuppressWarnings(PHPMD.NPathComplexity)
54+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
55+
*/
56+
public function aroundSave(
57+
CustomerRepositoryInterface $subject,
58+
callable $proceed,
59+
CustomerInterface $customer,
60+
$passwordHash = null
61+
) {
62+
$dobRaw = $customer->getDob();
63+
64+
$dobDate = $this->parseDate($dobRaw);
65+
if ($dobRaw !== null && $dobRaw !== '' && !$dobDate) {
66+
throw new InputException(__('Date of Birth is invalid.'));
67+
}
68+
69+
if ($dobDate) {
70+
$attr = $this->eavConfig->getAttribute('customer', 'dob');
71+
72+
$rules = $attr->getData('validate_rules');
73+
if (is_string($rules) && $rules !== '') {
74+
try {
75+
$rules = $this->json->unserialize($rules);
76+
} catch (\InvalidArgumentException $e) {
77+
$rules = [];
78+
}
79+
}
80+
if (!is_array($rules)) {
81+
$rules = (array)$attr->getValidateRules();
82+
}
83+
84+
$min = $rules['date_range_min'] ?? $rules['min_date'] ?? null;
85+
$max = $rules['date_range_max'] ?? $rules['max_date'] ?? null;
86+
87+
$minDate = $this->parseDate($min);
88+
$maxDate = $this->parseDate($max);
89+
90+
$dobKey = $dobDate->format(DateTime::DATE_PHP_FORMAT);
91+
92+
if ($minDate && $dobKey < $minDate->format(DateTime::DATE_PHP_FORMAT)) {
93+
throw new InputException(__(
94+
'Date of Birth must be on or after %1.',
95+
$minDate->format(DateTime::DATE_PHP_FORMAT)
96+
));
97+
}
98+
if ($maxDate && $dobKey > $maxDate->format(DateTime::DATE_PHP_FORMAT)) {
99+
throw new InputException(__(
100+
'Date of Birth must be on or before %1.',
101+
$maxDate->format(DateTime::DATE_PHP_FORMAT)
102+
));
103+
}
104+
}
105+
106+
return $proceed($customer, $passwordHash);
107+
}
108+
109+
/**
110+
* Parse a date value into DateTimeImmutable.
111+
*
112+
* @param mixed $value
113+
* @return \DateTimeImmutable|null
114+
* @throws \Exception
115+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
116+
*/
117+
private function parseDate($value): ?\DateTimeImmutable
118+
{
119+
if ($value === null || $value === '' || $value === false) {
120+
return null;
121+
}
122+
if (is_int($value) || (is_string($value) && ctype_digit($value))) {
123+
$intVal = (int)$value;
124+
if ($intVal <= 0) {
125+
return null;
126+
}
127+
$seconds = ($intVal >= 10000000000) ? intdiv($intVal, 1000) : $intVal;
128+
return (new \DateTimeImmutable('@' . $seconds))->setTimezone(new \DateTimeZone('UTC'));
129+
}
130+
131+
try {
132+
return new \DateTimeImmutable((string)$value);
133+
} catch (\Exception $e) {
134+
return null;
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)