Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 89 additions & 99 deletions Service/Formatter/Address/PhoneFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,169 +23,159 @@

class PhoneFormatter
{
private $validMobile = [
private const VALID_MOBILE = [
'NL' => ['00316'],
'BE' => ['003246', '003247', '003248', '003249'],
'DE' => ['004915', '004916', '004917'],
'AT' => ['0049650', '0049660', '0049664','0049676', '0049680', '0049677','0049681', '0049688', '0049699'],
];

private $invalidNotation = [
private const INVALID_NOTATION = [
'NL' => ['00310', '0310', '310', '31'],
'BE' => ['00320', '0320', '320', '32'],
];

private $startingNotation = [
'NL' => ['0', '0', '3', '1'],
'BE' => ['0', '0', '3', '2'],
'DE' => ['0', '0', '4', '9'],
'AT' => ['0', '0', '4', '3'],
private const STARTING_NOTATION = [
'NL' => '0031',
'BE' => '0032',
'DE' => '0049',
'AT' => '0043',
];

private Log $logger;

public function __construct(
Log $logger
) {
public function __construct(Log $logger)
{
$this->logger = $logger;
}

/**
* @param $phoneNumber
* @param $country
* Formats a phone number for a given country.
*
* @param string|null $phoneNumber
* @param string $country
* @return array
*/
public function format($phoneNumber, $country)
public function format(?string $phoneNumber, string $country): array
{
$this->logger->addDebug(__METHOD__ . '|1|');
$this->logger->addDebug(var_export([$phoneNumber, $country], true));

$return = ["orginal" => $phoneNumber, "clean" => false, "mobile" => false, "valid" => false];
$this->logger->addDebug(__METHOD__ . ' - Starting format process', [
'phoneNumber' => $phoneNumber,
'country' => $country,
]);

$return = [
'original' => $phoneNumber,
'clean' => false,
'mobile' => false,
'valid' => false,
];

// If phone number is null or empty, return default
if (empty($phoneNumber)) {
return $return;
}

$match = preg_replace('/[^0-9]/Uis', '', $phoneNumber);
if ($match) {
$phoneNumber = $match;
// If country is unsupported, return the original phone number as clean
if (!isset(self::STARTING_NOTATION[$country])) {
$return['clean'] = $phoneNumber;
return $return;
}

$return['clean'] = $this->formatPhoneNumber($phoneNumber, $country);
$return['mobile'] = $this->isMobileNumber($return['clean'], $country);
// Clean and format the phone number
$cleanedNumber = $this->cleanPhoneNumber($phoneNumber);
$formattedNumber = $this->formatPhoneNumber($cleanedNumber, $country);

if (strlen((string)$return['clean']) == 13) {
$return['valid'] = true;
}
// Check if the phone number is mobile and valid
$return['clean'] = $formattedNumber;
$return['mobile'] = $this->isMobileNumber($formattedNumber, $country);
$return['valid'] = strlen($formattedNumber) === 13;

$this->logger->addDebug(__METHOD__ . '|2|');
$this->logger->addDebug(var_export($return, true));
$this->logger->addDebug(__METHOD__ . ' - Format process complete', $return);

return $return;
}

/**
* @param $phoneNumber
* @param $country
* Removes all non-numeric characters from the phone number.
*
* @param string $phoneNumber
* @return string
*/
private function cleanPhoneNumber(string $phoneNumber): string
{
return preg_replace('/\D+/', '', $phoneNumber) ?? '';
}

/**
* Formats the phone number based on the country rules.
*
* @param string $phoneNumber
* @param string $country
* @return string
*/
private function formatPhoneNumber($phoneNumber, $country)
private function formatPhoneNumber(string $phoneNumber, string $country): string
{
$phoneLength = strlen((string)$phoneNumber);
$startingNotation = self::STARTING_NOTATION[$country];
$phoneLength = strlen($phoneNumber);

if ($phoneLength > 10 && $phoneLength != 13) {
$phoneNumber = $this->isValidNotation($phoneNumber, $country);
// Apply invalid notation correction
if ($phoneLength > 10 && $phoneLength !== 13) {
$phoneNumber = $this->applyInvalidNotationCorrection($phoneNumber, $country);
}

if ((in_array($country, ['NL', 'BE']) && ($phoneLength == 10))
||
(in_array($country, ['AT', 'DE']))
) {
if (isset($this->startingNotation[$country])) {
$notationStart = implode($this->startingNotation[$country]);
$phoneNumber = $notationStart . substr($phoneNumber, 1);
}
// Prepend starting notation for supported local numbers
if ($phoneLength === 10 && strpos($phoneNumber, $startingNotation) !== 0) {
$phoneNumber = $startingNotation . substr($phoneNumber, 1);
}

return $phoneNumber;
}

/**
* @param $phoneNumber
* @param $country
* Checks if the phone number is mobile based on country rules.
*
* @param string $phoneNumber
* @param string $country
* @return bool
*/
private function isMobileNumber($phoneNumber, $country)
private function isMobileNumber(string $phoneNumber, string $country): bool
{
$isMobile = false;

if (isset($this->validMobile[$country])) {
array_walk(
$this->validMobile[$country],
function ($value) use (&$isMobile, $phoneNumber) {
$phoneNumberPart = substr($phoneNumber, 0, strlen($value));
$phoneNumberHasValue = strpos($phoneNumberPart, $value);

if ($phoneNumberHasValue !== false) {
$isMobile = true;
}
}
);
foreach (self::VALID_MOBILE[$country] ?? [] as $prefix) {
if (strpos($phoneNumber, $prefix) === 0) {
return true;
}
}

return $isMobile;
return false;
}

/**
* @param $phoneNumber
* @param $country
* Corrects invalid notations in the phone number.
*
* @param string $phoneNumber
* @param string $country
* @return string
*/
private function isValidNotation($phoneNumber, $country)
private function applyInvalidNotationCorrection(string $phoneNumber, string $country): string
{
if (isset($this->invalidNotation[$country])) {
array_walk(
$this->invalidNotation[$country],
function ($invalid) use (&$phoneNumber, $country) {
$phoneNumberPart = substr($phoneNumber, 0, strlen($invalid));

if (strpos($phoneNumberPart, $invalid) !== false) {
$phoneNumber = $this->formatNotation($phoneNumber, $invalid, $country);
}
}
);
foreach (self::INVALID_NOTATION[$country] ?? [] as $invalidPrefix) {
if (strpos($phoneNumber, $invalidPrefix) === 0) {
$phoneNumber = $this->replaceInvalidNotation($phoneNumber, $invalidPrefix, $country);
}
}

return $phoneNumber;
}

/**
* @param $phoneNumber
* @param $invalid
* @param $country
* Replaces invalid notation with a valid prefix.
*
* @param string $phoneNumber
* @param string $invalidPrefix
* @param string $country
* @return string
*/
private function formatNotation($phoneNumber, $invalid, $country)
private function replaceInvalidNotation(string $phoneNumber, string $invalidPrefix, string $country): string
{
if (isset($this->startingNotation[$country])) {
$valid = substr($invalid, 0, -1);
$countryNotation = $this->startingNotation[$country];

if (substr($valid, 0, 2) == $countryNotation[2] . $countryNotation[3]) {
$valid = $countryNotation[0] . $countryNotation[1] . $valid;
}

if (substr($valid, 0, 2) == $countryNotation[1] . $countryNotation[2]) {
$valid = $countryNotation[0] . $valid;
}

if ($valid == $countryNotation[2]) {
$valid = $countryNotation[1] . $valid . $countryNotation[3];
}

$phoneNumber = substr_replace($phoneNumber, $valid, 0, strlen($invalid));
}

return $phoneNumber;
$validPrefix = self::STARTING_NOTATION[$country];
return preg_replace('/^' . preg_quote($invalidPrefix, '/') . '/', $validPrefix, $phoneNumber) ?? $phoneNumber;
}
}
23 changes: 12 additions & 11 deletions Service/Formatter/AddressFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,38 @@ public function __construct(
}

/**
* @param OrderAddressInterface $address
* Formats the address into a structured array.
*
* @param OrderAddressInterface $address
* @return array
*/
public function format($address)
public function format(OrderAddressInterface $address): array
{
$formattedAddress = [
return [
'street' => $this->formatStreet($address->getStreet()),
'telephone' => $this->formatTelephone($address->getTelephone(), $address->getCountryId())
'telephone' => $this->formatTelephone($address->getTelephone(), $address->getCountryId()),
];

return $formattedAddress;
}

/**
* @param $street
* Formats the street address.
*
* @param array|string|null $street
* @return array
*/
public function formatStreet($street)
public function formatStreet($street): array
{
return $this->streetFormatter->format($street);
}

/**
* @param $phoneNumber
* @param $country
* Formats the phone number based on the country.
*
* @param string|null $phoneNumber
* @param string $country
* @return array
*/
public function formatTelephone($phoneNumber, $country)
public function formatTelephone(?string $phoneNumber, string $country): array
{
return $this->phoneFormatter->format($phoneNumber, $country);
}
Expand Down
Loading