My first commit of codes
This commit is contained in:
406
vendor/giggsey/libphonenumber-for-php/build/libphonenumber/buildtools/GeneratePhonePrefixData.php
vendored
Normal file
406
vendor/giggsey/libphonenumber-for-php/build/libphonenumber/buildtools/GeneratePhonePrefixData.php
vendored
Normal file
@@ -0,0 +1,406 @@
|
||||
<?php
|
||||
|
||||
namespace libphonenumber\buildtools;
|
||||
|
||||
use Symfony\Component\Console\Helper\ProgressHelper;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class GeneratePhonePrefixData
|
||||
{
|
||||
const NANPA_COUNTRY_CODE = 1;
|
||||
const DATA_FILE_EXTENSION = '.txt';
|
||||
const GENERATION_COMMENT = <<<'EOT'
|
||||
/**
|
||||
* This file is automatically @generated by {@link GeneratePhonePrefixData}.
|
||||
* Please don't modify it directly.
|
||||
*/
|
||||
|
||||
|
||||
EOT;
|
||||
|
||||
public $inputDir;
|
||||
private $filesToIgnore = array('.', '..', '.svn', '.git');
|
||||
private $outputDir;
|
||||
private $englishMaps = array();
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
private static $consoleOutput;
|
||||
|
||||
public function start($inputDir, $outputDir, OutputInterface $consoleOutput, ProgressHelper $progress)
|
||||
{
|
||||
$this->inputDir = $inputDir;
|
||||
$this->outputDir = $outputDir;
|
||||
self::$consoleOutput = $consoleOutput;
|
||||
|
||||
$inputOutputMappings = $this->createInputOutputMappings();
|
||||
$availableDataFiles = array();
|
||||
|
||||
$progress->start($consoleOutput, count($inputOutputMappings));
|
||||
foreach ($inputOutputMappings as $textFile => $outputFiles) {
|
||||
$mappings = $this->readMappingsFromFile($textFile);
|
||||
|
||||
$language = $this->getLanguageFromTextFile($textFile);
|
||||
|
||||
$this->removeEmptyEnglishMappings($mappings, $language);
|
||||
$this->makeDataFallbackToEnglish($textFile, $mappings);
|
||||
$mappingForFiles = $this->splitMap($mappings, $outputFiles);
|
||||
|
||||
foreach ($mappingForFiles as $outputFile => $value) {
|
||||
$this->writeMappingFile($language, $outputFile, $value);
|
||||
$this->addConfigurationMapping($availableDataFiles, $language, $outputFile);
|
||||
}
|
||||
$progress->advance();
|
||||
}
|
||||
|
||||
$this->writeConfigMap($availableDataFiles);
|
||||
$progress->finish();
|
||||
}
|
||||
|
||||
private function createInputOutputMappings()
|
||||
{
|
||||
$topLevel = scandir($this->inputDir);
|
||||
|
||||
$mappings = array();
|
||||
|
||||
foreach ($topLevel as $languageDirectory) {
|
||||
if (in_array($languageDirectory, $this->filesToIgnore)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fileLocation = $this->inputDir . DIRECTORY_SEPARATOR . $languageDirectory;
|
||||
|
||||
if (is_dir($fileLocation)) {
|
||||
// Will contain files
|
||||
|
||||
$countryCodeFiles = scandir($fileLocation);
|
||||
|
||||
foreach ($countryCodeFiles as $countryCodeFileName) {
|
||||
if (in_array($countryCodeFileName, $this->filesToIgnore)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$outputFiles = $this->createOutputFileNames(
|
||||
$countryCodeFileName,
|
||||
$this->getCountryCodeFromTextFileName($countryCodeFileName),
|
||||
$languageDirectory
|
||||
);
|
||||
|
||||
$mappings[$languageDirectory . DIRECTORY_SEPARATOR . $countryCodeFileName] = $outputFiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used by {@code #createInputOutputMappings()} to generate the list of output binary files
|
||||
* from the provided input text file. For the data files expected to be large (currently only
|
||||
* NANPA is supported), this method generates a list containing one output file for each area
|
||||
* code. Otherwise, a single file is added to the list.
|
||||
*/
|
||||
|
||||
private function createOutputFileNames($file, $countryCode, $language)
|
||||
{
|
||||
$outputFiles = array();
|
||||
|
||||
if ($countryCode == self::NANPA_COUNTRY_CODE) {
|
||||
// Fetch the 4-digit prefixes stored in the file.
|
||||
$phonePrefixes = array();
|
||||
|
||||
$this->parseTextFile(
|
||||
$this->getFilePathFromLanguageAndCountryCode($language, $countryCode),
|
||||
function ($prefix, $location) use (&$phonePrefixes) {
|
||||
$shortPrefix = substr($prefix, 0, 4);
|
||||
if (!in_array($shortPrefix, $phonePrefixes)) {
|
||||
$phonePrefixes[] = $shortPrefix;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
foreach ($phonePrefixes as $prefix) {
|
||||
$outputFiles[] = $this->generateFilename($prefix, $language);
|
||||
}
|
||||
} elseif ($countryCode == 86) {
|
||||
|
||||
/*
|
||||
* Reduce memory usage for China numbers
|
||||
* @see https://github.com/giggsey/libphonenumber-for-php/issues/44
|
||||
*/
|
||||
|
||||
// Fetch the 5-digit prefixes stored in the file.
|
||||
$phonePrefixes = array();
|
||||
|
||||
$this->parseTextFile(
|
||||
$this->getFilePathFromLanguageAndCountryCode($language, $countryCode),
|
||||
function ($prefix, $location) use (&$phonePrefixes) {
|
||||
$shortPrefix = substr($prefix, 0, 5);
|
||||
if (!in_array($shortPrefix, $phonePrefixes)) {
|
||||
$phonePrefixes[] = $shortPrefix;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
foreach ($phonePrefixes as $prefix) {
|
||||
$outputFiles[] = $this->generateFilename($prefix, $language);
|
||||
}
|
||||
} else {
|
||||
$outputFiles[] = $this->generateFilename($countryCode, $language);
|
||||
}
|
||||
|
||||
return $outputFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads phone prefix data from the provides file path and invokes the given handler for each
|
||||
* mapping read.
|
||||
*
|
||||
* @param $filePath
|
||||
* @param $handler
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function parseTextFile($filePath, \Closure $handler)
|
||||
{
|
||||
|
||||
if (!file_exists($filePath) || !is_readable($filePath)) {
|
||||
throw new \InvalidArgumentException("File '{$filePath}' does not exist");
|
||||
}
|
||||
|
||||
$data = file($filePath);
|
||||
|
||||
$countryData = array();
|
||||
|
||||
foreach ($data as $line) {
|
||||
// Remove \n
|
||||
$line = str_replace("\n", "", $line);
|
||||
$line = str_replace("\r", "", $line);
|
||||
$line = trim($line);
|
||||
|
||||
if (strlen($line) == 0 || substr($line, 0, 1) == '#') {
|
||||
continue;
|
||||
}
|
||||
if (strpos($line, '|')) {
|
||||
// Valid line
|
||||
$parts = explode('|', $line);
|
||||
|
||||
|
||||
$prefix = $parts[0];
|
||||
$location = $parts[1];
|
||||
|
||||
$handler($prefix, $location);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $countryData;
|
||||
|
||||
}
|
||||
|
||||
private function getFilePathFromLanguageAndCountryCode($language, $code)
|
||||
{
|
||||
return $this->getFilePath($language . DIRECTORY_SEPARATOR . $code . self::DATA_FILE_EXTENSION);
|
||||
}
|
||||
|
||||
private function getFilePath($fileName)
|
||||
{
|
||||
$path = $this->inputDir . $fileName;
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
private function generateFilename($prefix, $language)
|
||||
{
|
||||
return $language . DIRECTORY_SEPARATOR . $prefix . self::DATA_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
private function getCountryCodeFromTextFileName($countryCodeFileName)
|
||||
{
|
||||
return str_replace(self::DATA_FILE_EXTENSION, '', $countryCodeFileName);
|
||||
}
|
||||
|
||||
private function readMappingsFromFile($inputFile)
|
||||
{
|
||||
$areaCodeMap = array();
|
||||
|
||||
$this->parseTextFile(
|
||||
$this->inputDir . $inputFile,
|
||||
function ($prefix, $location) use (&$areaCodeMap) {
|
||||
$areaCodeMap[$prefix] = $location;
|
||||
}
|
||||
);
|
||||
|
||||
return $areaCodeMap;
|
||||
}
|
||||
|
||||
private function getLanguageFromTextFile($textFile)
|
||||
{
|
||||
$parts = explode(DIRECTORY_SEPARATOR, $textFile);
|
||||
|
||||
return $parts[0];
|
||||
}
|
||||
|
||||
private function removeEmptyEnglishMappings(&$mappings, $language)
|
||||
{
|
||||
if ($language != "en") {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($mappings as $k => $v) {
|
||||
if ($v == "") {
|
||||
unset($mappings[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress the provided mappings according to the English data file if any.
|
||||
* @param string $textFile
|
||||
* @param array $mappings
|
||||
*/
|
||||
private function makeDataFallbackToEnglish($textFile, &$mappings)
|
||||
{
|
||||
$englishPath = $this->getEnglishDataPath($textFile);
|
||||
|
||||
if ($textFile == $englishPath || !file_exists($this->getFilePath($englishPath))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$countryCode = substr($textFile, 3, 2);
|
||||
|
||||
if (!array_key_exists($countryCode, $this->englishMaps)) {
|
||||
$englishMap = $this->readMappingsFromFile($englishPath);
|
||||
|
||||
$this->englishMaps[$countryCode] = $englishMap;
|
||||
}
|
||||
|
||||
$this->compressAccordingToEnglishData($this->englishMaps[$countryCode], $mappings);
|
||||
}
|
||||
|
||||
private function getEnglishDataPath($textFile)
|
||||
{
|
||||
return "en" . DIRECTORY_SEPARATOR . substr($textFile, 3, 2) . self::DATA_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
private function compressAccordingToEnglishData($englishMap, &$nonEnglishMap)
|
||||
{
|
||||
foreach ($nonEnglishMap as $prefix => $value) {
|
||||
|
||||
if (array_key_exists($prefix, $englishMap)) {
|
||||
$englishDescription = $englishMap[$prefix];
|
||||
if ($englishDescription == $value) {
|
||||
if (!$this->hasOverlappingPrefix($prefix, $nonEnglishMap)) {
|
||||
unset($nonEnglishMap[$prefix]);
|
||||
} else {
|
||||
$nonEnglishMap[$prefix] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function hasOverlappingPrefix($number, $mappings)
|
||||
{
|
||||
while (strlen($number) > 0) {
|
||||
$number = substr($number, 0, -1);
|
||||
|
||||
if (array_key_exists($number, $mappings)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function splitMap($mappings, $outputFiles)
|
||||
{
|
||||
$mappingForFiles = array();
|
||||
|
||||
foreach ($mappings as $prefix => $location) {
|
||||
$targetFile = null;
|
||||
|
||||
foreach ($outputFiles as $k => $outputFile) {
|
||||
$outputFilePrefix = $this->getPhonePrefixLanguagePairFromFilename($outputFile)->prefix;
|
||||
if (self::startsWith($prefix, $outputFilePrefix)) {
|
||||
$targetFile = $outputFilePrefix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!array_key_exists($targetFile, $mappingForFiles)) {
|
||||
$mappingForFiles[$targetFile] = array();
|
||||
}
|
||||
$mappingForFiles[$targetFile][$prefix] = $location;
|
||||
}
|
||||
|
||||
return $mappingForFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the phone prefix and the language code contained in the provided file name.
|
||||
*/
|
||||
private function getPhonePrefixLanguagePairFromFilename($outputFile)
|
||||
{
|
||||
$parts = explode(DIRECTORY_SEPARATOR, $outputFile);
|
||||
|
||||
$returnObj = new \stdClass();
|
||||
$returnObj->language = $parts[0];
|
||||
|
||||
$returnObj->prefix = $this->getCountryCodeFromTextFileName($parts[1]);
|
||||
|
||||
return $returnObj;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @link http://stackoverflow.com/a/834355/403165
|
||||
* @param $haystack
|
||||
* @param $needle
|
||||
* @return bool
|
||||
*/
|
||||
private static function startsWith($haystack, $needle)
|
||||
{
|
||||
return !strncmp($haystack, $needle, strlen($needle));
|
||||
}
|
||||
|
||||
private function writeMappingFile($language, $outputFile, $data)
|
||||
{
|
||||
|
||||
if (!file_exists($this->outputDir . $language)) {
|
||||
mkdir($this->outputDir . $language);
|
||||
}
|
||||
|
||||
$phpSource = '<?php' . PHP_EOL
|
||||
. self::GENERATION_COMMENT
|
||||
. 'return ' . var_export($data, true) . ';'
|
||||
. PHP_EOL;
|
||||
|
||||
$outputPath = $this->outputDir . $language . DIRECTORY_SEPARATOR . $outputFile . '.php';
|
||||
|
||||
file_put_contents($outputPath, $phpSource);
|
||||
}
|
||||
|
||||
public function addConfigurationMapping(&$availableDataFiles, $language, $prefix)
|
||||
{
|
||||
if (!array_key_exists($language, $availableDataFiles)) {
|
||||
$availableDataFiles[$language] = array();
|
||||
}
|
||||
|
||||
$availableDataFiles[$language][] = $prefix;
|
||||
}
|
||||
|
||||
private function writeConfigMap($availableDataFiles)
|
||||
{
|
||||
$phpSource = '<?php' . PHP_EOL
|
||||
. self::GENERATION_COMMENT
|
||||
. 'return ' . var_export($availableDataFiles, true) . ';'
|
||||
. PHP_EOL;
|
||||
|
||||
$outputPath = $this->outputDir . 'Map.php';
|
||||
|
||||
file_put_contents($outputPath, $phpSource);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user