File: BuildMetadataPHPFromXml.php

package info (click to toggle)
php-giggsey-libphonenumber 9.0.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 22,464 kB
  • sloc: php: 484,879; sh: 107; makefile: 37
file content (136 lines) | stat: -rw-r--r-- 5,266 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php

declare(strict_types=1);

namespace libphonenumber\buildtools;

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;

/**
 * Tool to convert phone number metadata from the XML format to protocol buffer format.
 *
 * @author Davide Mendolia
 * @internal
 */
class BuildMetadataPHPFromXml
{
    public const GENERATION_COMMENT = <<<EOT
        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[]>

        EOT;
    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;

    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
        ksort($countryCodeToRegionCodeMap);
        $this->writeCountryCallingCodeMappingToFile($countryCodeToRegionCodeMap, $mappingClassLocation, $mappingClass);
    }

    /**
     * @param PhoneMetadataBuilder[] $metadataCollection
     */
    private function writeMetadataToFile(array $metadataCollection, string $directory, string $namespaceAndClassPrefix): void
    {
        foreach ($metadataCollection as $metadata) {
            $regionCode = $metadata->getId();
            // For non-geographical country calling codes (e.g. +800), use the country calling codes
            // instead of the region code to form the file name.
            if ($regionCode === '001' || $regionCode === '') {
                $regionCode = $metadata->getCountryCode();
            }

            $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($directory . DIRECTORY_SEPARATOR . $classPrefix . '_' . $regionCode . '.php', $printer->printFile($data));
        }
    }

    /**
     * @param array<int|string,array<string>> $countryCodeToRegionCodeMap
     */
    private function writeCountryCallingCodeMappingToFile(array $countryCodeToRegionCodeMap, string $outputDir, string $mappingClass): void
    {
        // Find out whether the countryCodeToRegionCodeMap has any region codes or country
        // calling codes listed in it.
        $hasRegionCodes = false;
        foreach ($countryCodeToRegionCodeMap as $key => $listWithRegionCode) {
            if ((is_countable($listWithRegionCode) ? count($listWithRegionCode) : 0) > 0) {
                $hasRegionCodes = true;
                break;
            }
        }

        $hasCountryCodes = count($countryCodeToRegionCodeMap) > 1;

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

        $file = new PhpFile();
        $file->setStrictTypes();
        $file->addComment(self::GENERATION_COMMENT);

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

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

        if ($hasRegionCodes && $hasCountryCodes) {
            $constant = $class->addConstant($variableName, $countryCodeToRegionCodeMap);
            $constant->setComment(self::MAP_COMMENT);
        } elseif ($hasCountryCodes) {
            $constant = $class->addConstant($variableName, array_keys($countryCodeToRegionCodeMap));
            $constant->setComment(self::COUNTRY_CODE_SET_COMMENT);
        } else {
            $constant = $class->addConstant($variableName, $countryCodeToRegionCodeMap[0]);
            $constant->setComment(self::REGION_CODE_SET_COMMENT);
        }

        $constant->setPublic();

        $printer = new PsrPrinter();

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