Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store metadata in objects instead of arrays #678

Draft
wants to merge 8 commits into
base: v9-upgrades
Choose a base branch
from
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ phpunit.xml.dist export-ignore
.github/ export-ignore
src/CountryCodeToRegionCodeMapForTesting.php export-ignore
phpstan.neon.dist export-ignore
infection.json5 export-ignore

* text=auto
12 changes: 4 additions & 8 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,9 @@
<arg value="BuildMetadataPHPFromXML"/>
<arg value="${git.path}/resources/PhoneNumberMetadataForTesting.xml"/>
<arg value="${data.testCoreData}"/>
<arg value="PhoneNumberMetadataForTesting"/>
<arg value="libphonenumber\\Tests\\core\\data\\PhoneNumberMetadataForTesting"/>
<arg value="CountryCodeToRegionCodeMapForTesting"/>
<arg value="src/"/>
<arg value="false"/>
</exec>
</target>

Expand All @@ -149,10 +148,9 @@
<arg value="BuildMetadataPHPFromXML"/>
<arg value="${git.path}/resources/PhoneNumberMetadata.xml"/>
<arg value="${data.coreData}"/>
<arg value="PhoneNumberMetadata"/>
<arg value="libphonenumber\\data\\PhoneNumberMetadata"/>
<arg value="CountryCodeToRegionCodeMap"/>
<arg value="src/"/>
<arg value="false"/>
</exec>
</target>

Expand All @@ -161,10 +159,9 @@
<arg value="BuildMetadataPHPFromXML"/>
<arg value="${git.path}/resources/ShortNumberMetadata.xml"/>
<arg value="${data.coreData}"/>
<arg value="ShortNumberMetadata"/>
<arg value="libphonenumber\\data\\ShortNumberMetadata"/>
<arg value="ShortNumbersRegionCodeSet"/>
<arg value="src/"/>
<arg value="false"/>
</exec>
</target>

Expand All @@ -173,10 +170,9 @@
<arg value="BuildMetadataPHPFromXML"/>
<arg value="${git.path}/resources/PhoneNumberAlternateFormats.xml"/>
<arg value="${data.coreData}"/>
<arg value="PhoneNumberAlternateFormats"/>
<arg value="libphonenumber\\data\\PhoneNumberAlternateFormats"/>
<arg value="AlternateFormatsCountryCodeSet"/>
<arg value="src/"/>
<arg value="false"/>
</exec>
</target>

Expand Down
44 changes: 11 additions & 33 deletions build/BuildMetadataFromXml.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace libphonenumber\buildtools;

use libphonenumber\buildtools\Builders\PhoneMetadataBuilder;
use libphonenumber\NumberFormat;
use libphonenumber\PhoneMetadata;
use libphonenumber\PhoneNumberDesc;
use DOMDocument;
use DOMElement;
Expand Down Expand Up @@ -102,9 +102,9 @@ public static function validateRE(string $regex, bool $removeWhitespace = false)
}

/**
* @return PhoneMetadata[]
* @return PhoneMetadataBuilder[]
*/
public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlFile, bool $liteBuild, bool $specialBuild, bool $isShortNumberMetadata = false, bool $isAlternateFormatsMetadata = false): array
public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlFile, bool $isShortNumberMetadata = false, bool $isAlternateFormatsMetadata = false): array
{
if ($inputXmlFile instanceof DOMElement) {
$document = $inputXmlFile;
Expand All @@ -120,8 +120,6 @@ public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlF
$territories = $document->getElementsByTagName('territory');
$metadataCollection = [];

$metadataFilter = self::getMetadataFilter($liteBuild, $specialBuild);

foreach ($territories as $territoryElement) {
/** @var DOMElement $territoryElement */
// For the main metadata file this should always be set, but for other supplementary data
Expand All @@ -132,13 +130,12 @@ public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlF
$regionCode = '';
}
$metadata = self::loadCountryMetadata($regionCode, $territoryElement, $isShortNumberMetadata, $isAlternateFormatsMetadata);
$metadataFilter->filterMetadata($metadata);
$metadataCollection[] = $metadata;
}
return $metadataCollection;
}

public static function loadCountryMetadata(string $regionCode, DOMElement $element, bool $isShortNumberMetadata, bool $isAlternateFormatsMetadata): PhoneMetadata
public static function loadCountryMetadata(string $regionCode, DOMElement $element, bool $isShortNumberMetadata, bool $isAlternateFormatsMetadata): PhoneMetadataBuilder
{
$nationalPrefix = self::getNationalPrefix($element);
$metadata = self::loadTerritoryTagMetadata($regionCode, $element, $nationalPrefix);
Expand All @@ -152,25 +149,6 @@ public static function loadCountryMetadata(string $regionCode, DOMElement $eleme
return $metadata;
}

/**
* Processes the custom build flags and gets a MetadataFilter which may be used to
* filter PhoneMetadata objects. Incompatible flag combinations throw RuntimeException.
*/
public static function getMetadataFilter(bool $liteBuild, bool $specialBuild): MetadataFilter
{
if ($specialBuild) {
if ($liteBuild) {
throw new RuntimeException('liteBuild and specialBuild may not both be set');
}
return MetadataFilter::forSpecialBuild();
}
if ($liteBuild) {
return MetadataFilter::forLiteBuild();
}

return MetadataFilter::emptyFilter();
}

/**
* Returns the national prefix of the provided country element.
*/
Expand All @@ -194,8 +172,8 @@ public static function loadTerritoryTagMetadata(
string $regionCode,
DOMElement $element,
string $nationalPrefix
): PhoneMetadata {
$metadata = new PhoneMetadata();
): PhoneMetadataBuilder {
$metadata = new PhoneMetadataBuilder();
$metadata->setId($regionCode);
$metadata->setCountryCode((int) $element->getAttribute(self::COUNTRY_CODE));
if ($element->hasAttribute(self::LEADING_DIGITS)) {
Expand Down Expand Up @@ -239,7 +217,7 @@ public static function loadTerritoryTagMetadata(
* nationalPrefixOptionalWhenFormatting values are provided from the parent (territory) element.
*/
public static function loadAvailableFormats(
PhoneMetadata $metadata,
PhoneMetadataBuilder $metadata,
DOMElement $element,
string $nationalPrefix,
string $nationalPrefixFormattingRule,
Expand Down Expand Up @@ -312,7 +290,7 @@ public static function getDomesticCarrierCodeFormattingRuleFromElement(DOMElemen
* @throws RuntimeException if multiple or no formats have been encountered.
*/
public static function loadNationalFormat(
PhoneMetadata $metadata,
PhoneMetadataBuilder $metadata,
DOMElement $numberFormatElement,
NumberFormat $format
): void {
Expand Down Expand Up @@ -347,7 +325,7 @@ public static function setLeadingDigitsPatterns(DOMElement $numberFormatElement,
* @return bool whether an international number format is defined.
*/
public static function loadInternationalFormat(
PhoneMetadata $metadata,
PhoneMetadataBuilder $metadata,
DOMElement $numberFormatElement,
NumberFormat $nationalFormat
): bool {
Expand Down Expand Up @@ -379,7 +357,7 @@ public static function loadInternationalFormat(
return $hasExplicitIntlFormatDefined;
}

public static function setRelevantDescPatterns(PhoneMetadata $metadata, DOMElement $element, bool $isShortNumberMetadata): void
public static function setRelevantDescPatterns(PhoneMetadataBuilder $metadata, DOMElement $element, bool $isShortNumberMetadata): void
{
$generalDesc = self::processPhoneNumberDescElement(null, $element, self::GENERAL_DESC);
$metadata->setGeneralDesc($generalDesc);
Expand Down Expand Up @@ -722,7 +700,7 @@ private static function arePossibleLengthsEqual(array $possibleLengths, PhoneNum
}

/**
* @param PhoneMetadata[] $metadataCollection
* @param PhoneMetadataBuilder[] $metadataCollection
* @return array<int|string,array<string>>
*/
public static function buildCountryCodeToRegionCodeMap(array $metadataCollection): array
Expand Down
116 changes: 60 additions & 56 deletions build/BuildMetadataPHPFromXml.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

namespace libphonenumber\buildtools;

use libphonenumber\PhoneMetadata;
use Symfony\Component\VarExporter\VarExporter;
use libphonenumber\buildtools\Builders\PhoneMetadataBuilder;
use Nette\PhpGenerator\PhpFile;
use Nette\PhpGenerator\PsrPrinter;
use RuntimeException;

use function array_keys;
use function count;
use function file_put_contents;
use function ksort;
use function lcfirst;

/**
* Tool to convert phone number metadata from the XML format to protocol buffer format.
Expand All @@ -22,43 +23,33 @@
class BuildMetadataPHPFromXml
{
public const GENERATION_COMMENT = <<<EOT
/**
* libphonenumber-for-php data file
* This file has been @generated from libphonenumber data
* Do not modify!
* @internal
*/
libphonenumber-for-php data file
This file has been @generated from libphonenumber data
Do not modify!
@internal

EOT;
public const MAP_COMMENT = <<<EOT
/**
* A mapping from a country code to the region codes which denote the
* country/region represented by that country code. In the case of multiple
* countries sharing a calling code, such as the NANPA countries, the one
* indicated with "isMainCountryForCode" in the metadata should be first.
* @var array<int,string[]>
*/
A mapping from a country code to the region codes which denote the
country/region represented by that country code. In the case of multiple
countries sharing a calling code, such as the NANPA countries, the one
indicated with "isMainCountryForCode" in the metadata should be first.
@var array<int,string[]>

EOT;
public const COUNTRY_CODE_SET_COMMENT = <<<php
/**
* A set of all country calling codes for which data is available.
* @var int[]
*/
php;
public const REGION_CODE_SET_COMMENT = <<<php
/**
* A set of all region codes for which data is available.
* @var string[]
*/
php;

public function start(string $inputFile, string $outputDir, string $filePrefix, string $mappingClass, string $mappingClassLocation, bool $liteBuild): void
{
$savePath = $outputDir . $filePrefix;
public const COUNTRY_CODE_SET_COMMENT = <<<EOT
A set of all country calling codes for which data is available.
@var int[]
EOT;
public const REGION_CODE_SET_COMMENT = <<<EOT
A set of all region codes for which data is available.
@var string[]
EOT;

$metadataCollection = BuildMetadataFromXml::buildPhoneMetadataCollection($inputFile, $liteBuild, false);
$this->writeMetadataToFile($metadataCollection, $savePath);
public function start(string $inputFile, string $outputDir, string $namespaceAndClassPrefix, string $mappingClass, string $mappingClassLocation): void
{
$metadataCollection = BuildMetadataFromXml::buildPhoneMetadataCollection($inputFile);
$this->writeMetadataToFile($metadataCollection, $outputDir, $namespaceAndClassPrefix);

$countryCodeToRegionCodeMap = BuildMetadataFromXml::buildCountryCodeToRegionCodeMap($metadataCollection);
// Sort $countryCodeToRegionCodeMap just to have the regions in order
Expand All @@ -67,9 +58,9 @@ public function start(string $inputFile, string $outputDir, string $filePrefix,
}

/**
* @param PhoneMetadata[] $metadataCollection
* @param PhoneMetadataBuilder[] $metadataCollection
*/
private function writeMetadataToFile(array $metadataCollection, string $filePrefix): void
private function writeMetadataToFile(array $metadataCollection, string $directory, string $namespaceAndClassPrefix): void
{
foreach ($metadataCollection as $metadata) {
$regionCode = $metadata->getId();
Expand All @@ -79,11 +70,21 @@ private function writeMetadataToFile(array $metadataCollection, string $filePref
$regionCode = $metadata->getCountryCode();
}

$data = '<?php' . PHP_EOL
. self::GENERATION_COMMENT . PHP_EOL
. 'return ' . VarExporter::export($metadata->toArray()) . ';' . PHP_EOL;
$pos = strrpos($namespaceAndClassPrefix, '\\');

if ($pos === false) {
throw new RuntimeException('Invalid namespaceAndClassPrefix: ' . $namespaceAndClassPrefix);
}

$namespace = substr($namespaceAndClassPrefix, 0, $pos);
$classPrefix = substr($namespaceAndClassPrefix, $pos + 1);

$data = $metadata->toFile($classPrefix . '_' . $regionCode, $namespace);
$data->addComment(self::GENERATION_COMMENT);

$printer = new PsrPrinter();

file_put_contents($filePrefix . '_' . $regionCode . '.php', $data);
file_put_contents($directory . DIRECTORY_SEPARATOR . $classPrefix . '_' . $regionCode . '.php', $printer->printFile($data));
}
}

Expand All @@ -104,29 +105,32 @@ private function writeCountryCallingCodeMappingToFile(array $countryCodeToRegion

$hasCountryCodes = count($countryCodeToRegionCodeMap) > 1;

$variableName = lcfirst($mappingClass);
$variableName = strtoupper(preg_replace('/(?<!^)[A-Z]/', '_$0', $mappingClass));

$data = '<?php' . PHP_EOL .
'declare(strict_types=1);' . PHP_EOL .
'namespace libphonenumber;' . PHP_EOL .
self::GENERATION_COMMENT . PHP_EOL .
"class {$mappingClass} {" . PHP_EOL .
PHP_EOL;
$file = new PhpFile();
$file->setStrictTypes();
$file->addComment(self::GENERATION_COMMENT);

$namespace = $file->addNamespace('libphonenumber');

$class = $namespace->addClass($mappingClass);
$class->addComment('@internal');

if ($hasRegionCodes && $hasCountryCodes) {
$data .= self::MAP_COMMENT . PHP_EOL;
$data .= " public static array \${$variableName} = " . VarExporter::export($countryCodeToRegionCodeMap) . ';' . PHP_EOL;
$constant = $class->addConstant($variableName, $countryCodeToRegionCodeMap);
$constant->setComment(self::MAP_COMMENT);
} elseif ($hasCountryCodes) {
$data .= self::COUNTRY_CODE_SET_COMMENT . PHP_EOL;
$data .= " public static array \${$variableName} = " . VarExporter::export(array_keys($countryCodeToRegionCodeMap)) . ';' . PHP_EOL;
$constant = $class->addConstant($variableName, array_keys($countryCodeToRegionCodeMap));
$constant->setComment(self::COUNTRY_CODE_SET_COMMENT);
} else {
$data .= self::REGION_CODE_SET_COMMENT . PHP_EOL;
$data .= " public static array \${$variableName} = " . VarExporter::export($countryCodeToRegionCodeMap[0]) . ';' . PHP_EOL;
$constant = $class->addConstant($variableName, $countryCodeToRegionCodeMap[0]);
$constant->setComment(self::REGION_CODE_SET_COMMENT);
}

$data .= PHP_EOL .
'}' . PHP_EOL;
$constant->setPublic();

$printer = new PsrPrinter();

file_put_contents($outputDir . $mappingClass . '.php', $data);
file_put_contents($outputDir . $mappingClass . '.php', $printer->printFile($file));
}
}
Loading