%PDF- %PDF-
| Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/location/import/compiler/ |
| Current File : //proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/location/import/compiler/compiler.php |
<?
/**
* This class is for internal use only, not a part of public API.
* It can be changed at any time without notification.
*
* @access private
*/
/*
//HOWTO call:
$compiler = new Compiler\Compiler(array(
'workDir' => 'locations_data/',
'grabbedStuffDir' => 'locations_data/grabber/output/',
'grabber' => $grabber,
'includeYaInfo2Name' => false,
'fiasAddrobjFile' => 'locations_data/addrobj.xml'
));
$compiler->compile();
*/
namespace Bitrix\Sale\Location\Import\Compiler;
use Bitrix\Sale\Location\Import;
final class Compiler {
const OUTPUT_DIR = 'compiled/';
const MAPS_DIR = 'maps/';
const INPUT_DIR = 'output/';
const OUTPUT_FILE = 'output.txt';
const CODE_LENGTH = 10;
const TMP_DATA_DIR = 'tmp/';
const STATIC_CSV_DIR = 'static_csv/';
const GROUP_FILE = 'typegroup.csv';
const KAZAKHSTAN_SOURCE = 'ukrain_kazakhstan/loc_kz.csv';
const USA_SOURCE = 'ukrain_kazakhstan/loc_usa.csv';
const WORLD_SOURCE = 'ukrain_kazakhstan/loc_cntr.csv';
const CIS_SOURCE = 'ukrain_kazakhstan/loc_ussr_cut.csv';
const RUSSIA_YANDEX_CODE = 225;
const BELORUSSIA_YANDEX_CODE = 149;
const UKRAIN_YANDEX_CODE = 187;
const KAZAKHSTAN_YANDEX_CODE = 159;
const SOURCE_YANDEX = 'Y'; // got from yandex
const SOURCE_FIAS = 'F'; // got from fias
const SOURCE_UKRAIN = 'U'; // data sent by the office in ukrain
const SOURCE_LEGACY = 'L'; // got from old location files
const TMP_DATA_RUS_EXPORT_INDEX = 'rus_exp_index';
const TMP_DATA_RUS_GLOBAL_INDEX = 'glob_exp_index';
private $queue = false;
private $typeMap = array(
'SUBJECT_FEDERATION' => 'REGION'
);
private $headers = array(
'SHORT' => array('CODE', 'PARENT_CODE', 'NAME.RU.NAME', 'NAME.EN.NAME', 'NAME.UA.NAME'),
'LONG' => array('CODE', 'PARENT_CODE', 'TYPE_CODE', 'NAME.RU.NAME', 'NAME.EN.NAME', 'NAME.UA.NAME', 'LONGITUDE', 'LATITUDE', 'EXT.YAMARKET.0', 'EXT.ZIP.0'/*, 'EXT.ZIP.1', 'EXT.ZIP.2', 'EXT.ZIP.3'*/),
'GROUP_FILE' => array('CODE', 'TYPES')
);
private $typeGroups = array(
'LAYOUT' => array(
'CODE' => 'LAYOUT',
'TYPES' => array('COUNTRY', 'COUNTRY_DISTRICT', 'REGION'),
'HEADER' => 'LONG',
'FILE_NAME_TEMPLATE' => 'layout.csv'
),
/*
'SELECTABLE' => array(
'TYPES' => array('COUNTRY', 'COUNTRY_DISTRICT', 'REGION'),
'HEADER' => 'LONG',
'FILE_NAME_TEMPLATE' => 'selectable.csv'
),
*/
'AREAS' => array(
'CODE' => 'AREAS',
'TYPES' => array('CITY', 'SUBREGION', 'VILLAGE'/*, 'CITY_DISTRICT', 'METRO_STATION', 'OTHER'*/),
'PARENT' => 'LAYOUT',
'HEADER' => 'LONG',
'FILE_NAME_TEMPLATE' => '%BASE_PARENT_ITEM_CODE%_%CODE%.csv'
),
'STREETS' => array(
'CODE' => 'STREETS',
'TYPES' => array('STREET'),
'PARENT' => 'LAYOUT',
'HEADER' => 'LONG',
'FILE_NAME_TEMPLATE' => '%BASE_PARENT_ITEM_CODE%_%CODE%.csv'
)
);
private $fiasToBaseType = array(
'COUNTRY' => array(),
'COUNTRY_DISTRICT' => array(
'округ' => array('R' => 'округ', 'U' => true),
),
'REGION' => array(
'АО' => array('R' => 'автономный округ', 'U' => true),
'Аобл' => array('R' => 'автономная область', 'U' => true),
'край' => array('R' => 'край', 'U' => true),
'обл' => array('R' => 'область', 'U' => true),
'Респ' => array('R' => 'республика', 'U' => true),
'Чувашия' => array('R' => 'республика', 'U' => true)
),
'SUBREGION' => array(
'р-н' => array('R' => 'район', 'U' => true),
'улус' => array('R' => 'улус', 'U' => true),
'у' => array('R' => 'улус', 'U' => true),
),
'CITY' => array(
'г' => array('R' => 'город', 'U' => true),
),
'VILLAGE' => array(
'пгт' => array('R' => 'посёлок городского типа', 'U' => true),
'п' => array('R' => 'посёлок', 'U' => true),
'дп' => array('R' => 'дачный посёлок', 'U' => true),
'с/п' => array('R' => 'сельское поселение', 'U' => true),
'аал' => array('R' => 'аал', 'U' => true),
'аул' => array('R' => 'аул', 'U' => true),
'арбан' => array('R' => 'арбан', 'U' => true),
'д' => array('R' => 'деревня', 'U' => true),
'нп' => array('R' => 'населённый пункт', 'U' => true),
'сл' => array('R' => 'слобода', 'U' => true),
'х' => array('R' => 'хутор', 'U' => true),
'ферма' => array('R' => 'ферма', 'U' => true),
'с' => array('R' => 'село', 'U' => true),
'рп' => array('R' => 'рабочий посёлок', 'U' => true),
'ст' => array('R' => 'станция', 'U' => true),
'п/ст' => array('R' => 'посёлок', 'U' => true),
'ст-ца' => array('R' => 'станица', 'U' => true),
'кп' => array('R' => 'курортный поселок', 'U' => true),
'ж/д_ст' => array('R' => 'железнодорожная станция'),
'тер' => array('R' => 'территория'),
'остров' => array('R' => 'остров'),
'мкр' => array('R' => 'микрорайон', 'U' => true),
'с/с' => array('R' => 'сельсовет', 'U' => true),
'п/о' => array('R' => 'почтовое отделение', 'U' => true),
'м' => array('R' => 'местечко', 'U' => true),
'с/мо' => array('R' => 'смо', 'U' => true),
'жилрайон' => array('R' => 'жилрайон', 'U' => true),
'массив' => array('R' => 'массив'),
'ж/д_оп' => array('R' => 'ж/д остановка'),
'с/а' => array('R' => 'сельская администрация', 'U' => true),
'п/р' => array('R' => 'планировочный район'),
'ж/д_рзд' => array('R' => 'ж/д разъезд'),
'снт' => array('R' => 'снт', 'U' => true),
'с/о' => array('R' => 'сельский округ'),
'заимка' => array('R' => 'заимка'),
'городок' => array('R' => 'городок', 'U' => true)
),
//'CITY_DISTRICT' => array(),
//'METRO_STATION' => array(),
'STREET' => array(
'ул' => array('R' => 'улица', 'U' => true),
'кв-л' => array('R' => 'квартал', 'U' => true),
'аллея' => array('R' => 'аллея', 'U' => true),
'вал' => array('R' => 'вал', 'U' => true),
'въезд' => array('R' => 'въезд', 'U' => true),
'наб' => array('R' => 'набережная', 'U' => true),
'пер' => array('R' => 'переулок', 'U' => true),
'пл' => array('R' => 'площадь', 'U' => true),
'пр-кт' => array('R' => 'проспект', 'U' => true),
'проезд' => array('R' => 'проезд', 'U' => true),
'проулок' => array('R' => 'проулок', 'U' => true),
'рзд' => array('R' => 'разъезд', 'U' => true),
'сад' => array('R' => 'сад', 'U' => true),
'сквер' => array('R' => 'сквер', 'U' => true),
'спуск' => array('R' => 'спуск', 'U' => true),
'тоннель' => array('R' => 'тоннель', 'U' => true),
'тракт' => array('R' => 'тракт', 'U' => true),
'туп' => array('R' => 'тупик', 'U' => true),
'эстакада' => array('R' => 'эстакада', 'U' => true),
'б-р' => array('R' => 'бульвар', 'U' => true),
'бугор' => array('R' => 'бугор', 'U' => true),
'заезд' => array('R' => 'заезд', 'U' => true),
'канал' => array('R' => 'канал', 'U' => true),
'км' => array('R' => 'километр', 'U' => true),
'кольцо' => array('R' => 'кольцо', 'U' => true),
'парк' => array('R' => 'парк', 'U' => true),
'переезд' => array('R' => 'переезд', 'U' => true),
'стр' => array('R' => 'строение', 'U' => true),
'просек' => array('R' => 'просек', 'U' => true),
'ш' => array('R' => 'шоссе', 'U' => true),
'автодорога' => array('R' => 'дорога', 'U' => true)
)
);
private $forbiddenPathTypes = array(
'ул' => 1,
'пр-кт' => 1,
'проезд' => 1,
'ш' => 1,
'кв-л' => 1,
'км' => 1,
'просек' => 1,
'пер' => 1,
'б-р' => 1,
'наб' => 1,
'ж/д_будка' => 1,
'тракт' => 1,
'дор' => 1,
'рзд' => 1,
'пл' => 1,
'высел' => 1,
'сад' => 1,
'уч-к' => 1,
'промзона' => 1,
'автодорога' => 1,
'ж/д_платф' => 1,
);
private $forbiddenPathIds = array(
'af7cdb7f-e47d-4f65-93d5-3a2b70a809ce' => true, // Боровой микрорайон should be placed inside village, not street
'762758bb-18b9-440f-bc61-8e1e77ff3fd8' => true, // московский посёлок cannot be inside московский город, those are the same
);
private $allowedFiasStats = array(
'ACTSTATUS' => array(
1 // актуальный
),
'LIVESTATUS' => array(
1 // жив!
),
'CURRSTATUS' => array(
0, // актуальный
51, // переподчинённый
)
);
private $filePools = array(
'ukrain_kazakhstan' => array(
'DIR' => 'ukrain_kazakhstan/'
),
// where we store clean and split fias data:
'fias_tree' => array(
'DIR' => 'fias_tree/'
),
// where we keep maps from yandex to fias (REGIONS, CITIES and VILLAGES)
'fias_yamarket_links' => array(
'DIR' => 'fias_yamarket_links/'
),
// where we keep result data
'assets' => array(
'DIR' => 'compiled/bundles/extended/'
),
// where we keep result data, only for russia
'assets_standard' => array(
'DIR' => 'compiled/bundles/standard/'
),
// where we keep result data
'demo' => array(
'DIR' => 'demo/'
),
);
private $workDir = '';
private $grabbedStuffDir = '';
private $yaIdType = array();
private $relations = array();
private $options = array();
// tree builder
private $data = array();
private $optionConvertNames = false;
private $sysMaps = array();
private $fiasCPath = array();
private $fiasDB = null;
private $eTreeDB = null;
private $eTreeDBRussia = null;
public function __construct($options)
{
$this->workDir = $options['workDir'];
$this->grabbedStuffDir = $options['grabbedStuffDir'];
$this->options = $options;
//if(!file_exists($_SERVER['DOCUMENT_ROOT'].$this->workDir.self::OUTPUT_DIR))
// mkdir($_SERVER['DOCUMENT_ROOT'].$this->workDir.self::OUTPUT_DIR, 0700, true);
foreach($this->typeGroups as $id => &$params)
$params['I_TYPES'] = array_flip($params['TYPES']);
foreach($this->fiasToBaseType as $type => $fTypes)
{
foreach($fTypes as $fType => $fReplace)
{
if(strlen($fType) && !empty($fReplace))
{
$this->sysMaps['FIAS2BASETYPE'][$fType] = $type;
$this->sysMaps['FIASTYPEREPLACE'][$fType] = $fReplace['R'];
}
}
}
foreach($this->typeGroups as $groupId => $group)
{
//$this->output($group);
foreach($group['TYPES'] as $type)
{
$this->sysMaps['BASETYPE2GROUP'][$type] = $groupId;
}
}
$this->cleanOutput();
}
public function compile()
{
// step 1: build main tree from yandex market data
//$this->buildMainTree();
##########################################################
#### MAP FIAS TO YANDEX
##########################################################
// step 2: processing huge fias file
//$this->splitFiasOnRegions(); // split huge fias file onto small pieces of bundles
/*
Handwriting:
move 0c5b2444-70a0-4932-980c-b4dc0d3f02b5;1;1;Москва;г; TO 29251dcf-00a1-4e34-98d4-5c47484a36d4.csv
move c2deb16a-0330-4f05-821f-1d09c93331e6;1;1;Санкт-Петербург;г;190000 TO 6d1ebb35-70c6-4129-bd55-da3969658f5d.csv
move 6fdecb78-893a-4e3f-a5ba-aa062459463b;1;1;Севастополь;г; TO bd8e6511-e4b9-4841-90de-6bbc231a789e.csv
*/
//$this->copyFias2DB(); // place fias to db
// step 3: map fias to yandex id. There were some handwriting to map files, so do not uncomment unless you want files to be overwritten
//$this->mapFiasRootV2(); // process fias root and find matches by regions
// then we have a little handwriting on rootv2.csv
//$this->mapFiasCities(); // find cities and villages matches
// again, handwriting here
##########################################################
#### FIAS 2 DB
##########################################################
/*
$this->copyFias2DB();
update b_tmp_fias set PARENTGUID = '29251dcf-00a1-4e34-98d4-5c47484a36d4' where AOGUID = '0c5b2444-70a0-4932-980c-b4dc0d3f02b5' and AOID = '5c8b06f1-518e-496e-b683-7bf917e0d70b';
update b_tmp_fias set PARENTGUID = '6d1ebb35-70c6-4129-bd55-da3969658f5d' where AOGUID = 'c2deb16a-0330-4f05-821f-1d09c93331e6' and AOID = 'aad1469e-54ff-4605-af4f-f016c75b84d2';
update b_tmp_fias set PARENTGUID = 'bd8e6511-e4b9-4841-90de-6bbc231a789e' where AOGUID = '6fdecb78-893a-4e3f-a5ba-aa062459463b' and AOID = '6fdecb78-893a-4e3f-a5ba-aa062459463b';
*/
##########################################################
#### MAKE EXPORT TABLE
##########################################################
/*
$res = YandexGeoCoder::query(array(
'query' => 'Ненецкий автономный округ Шойна село Школьная улица',
'kind' => YandexGeoCoder::KIND_STREET
));
*/
$this->output('Build main tree');
$this->buildMainTree();
$this->createExportTables();
/*
###################################################################
###################################################################
###################################################################
// making world
$this->eTreeDB->cleanup();
$this->eTreeDB->dropIndexes();
$this->output('Generate export tree: Belarus');
$this->generateExportTreeBelorussia();
$this->output('Generate export tree: Kazakhstan');
$this->generateExportTreeLegacy(self::KAZAKHSTAN_SOURCE);
$this->output('Generate export tree: Ukrain');
$this->generateExportTreeUkrain();
$this->output('Generate export tree: USA');
$this->generateExportTreeUSA();
$this->output('Generate export tree: World Countries');
$this->generateExportTreeWorld();
$this->output('Generate export tree: EX-CIS');
$this->generateExportTreeLegacy(self::CIS_SOURCE);
###################################################################
###################################################################
###################################################################
$this->output('Last occupied: '.$this->eTreeDB->getLastOccupiedCode());
$this->output('Next free: '.$this->eTreeDB->getNextFreeCode());
// making russia
$this->eTreeDBRussia->cleanup();
$this->eTreeDBRussia->dropIndexes();
$this->output('Generate export tree: Russia');
$this->generateExportTreeRussia();
$this->output('Last occupied: '.$this->eTreeDBRussia->getLastOccupiedCode());
$this->output('Next free: '.$this->eTreeDBRussia->getNextFreeCode());
###################################################################
###################################################################
###################################################################
*/
$this->restoreExportTablesIndexes();
$this->output('Build export files');
/*
$this->cleanPoolDir('assets');
$this->eTreeDB->walkInDeep(array($this, 'generateExportFilesFromTableBundle')); // world
$this->eTreeDBRussia->walkInDeep(array($this, 'generateExportFilesFromTableBundle')); // russia
*/
$this->cleanPoolDir('assets_standard');
$this->eTreeDB->walkInDeep(array(
'ITEM' => array($this, 'generateExportFilesFromTableBundle_Standard')
)); // world
$this->eTreeDBRussia->walkInDeep(array(
'ITEM' => array($this, 'generateExportFilesFromTableBundle_Standard_YandexOnly')
)); // russia
/*
// types by groups
$this->makeTypeGroupFile(self::GROUP_FILE);
$this->copyStaticCSV();
*/
###################################################################
###################################################################
###################################################################
/*
$this->output('Build demo files');
$this->cleanPoolDir('demo');
$this->eTreeDB->walkInDeep(array($this, 'generateDemoFilesWorld'), array('VILLAGE' => 1)); // world
$this->eTreeDBRussia->walkInDeep(array($this, 'generateDemoFilesRussia'), array('VILLAGE' => 1)); // world
*/
/*
добавить сюда генерацию файла country_codes.php с содержимым:
<?
$LOCALIZATION_COUNTRY_CODE_MAP = array(
'ru' => '0000028023',
'ua' => '0000000364',
'kz' => '0000000276',
'bl' => '0000000001'
);
этот файл потом идёт в мастер установки интернет-магазина, вместе с демо-данными, types.csv и externalservice.csv
*/
$this->output('DONE');
}
#######################################################
### ABOUT EXPORT TABLE
#######################################################
private $allowedForDemo = array('COUNTRY' => 1, 'COUNTRY_DISTRICT' => 1, 'REGION' => 1, 'SUBREGION' => 1, 'CITY' => 1);
private $demoCategory = false;
public function generateDemoFilesWorld($item, $table)
{
if(!isset($this->allowedForDemo[$item['TYPE_CODE']]))
return;
if($item['TYPE_CODE'] == 'COUNTRY')
{
$this->addItemToCSV('world', 'demo', $item);
// this part must not depend on codes, which may flow left and right. in future we may add
// some markers like "is_ukrain" or "is_russia" etc to database instead of relying on names
if($item['NAME'] == 'Україна')
$this->demoCategory = 'ukrain';
elseif($item['NAME'] == 'Казахстан')
$this->demoCategory = 'kazakhstan';
elseif($item['NAME'] == 'Беларусь')
$this->demoCategory = 'belarus';
elseif($item['NAME'] == 'США')
$this->demoCategory = 'usa';
else
$this->demoCategory = false;
}
//$this->output($table->getWalkPathString());
//$this->output($this->demoCategory);
if($this->demoCategory !== false)
$this->addItemToCSV($this->demoCategory, 'demo', $item);
}
public function generateDemoFilesRussia($item, $table)
{
if(!isset($this->allowedForDemo[$item['TYPE_CODE']]))
return;
if($item['TYPE_CODE'] == 'COUNTRY')
$this->addItemToCSV('world', 'demo', $item);
$this->addItemToCSV('russia', 'demo', $item);//done
}
private function createExportTables()
{
$this->eTreeDB = new Db\ExportTreeTable();
$this->eTreeDB->create();
$this->eTreeDBRussia = new Db\ExportTreeRussiaTable();
$this->eTreeDBRussia->create();
}
private function cleanUpExportTables()
{
$this->eTreeDB->cleanup();
$this->eTreeDB->dropIndexes();
$this->eTreeDBRussia->cleanup();
$this->eTreeDBRussia->dropIndexes();
}
private function restoreExportTablesIndexes()
{
$this->eTreeDB->restoreIndexes();
$this->eTreeDBRussia->restoreIndexes();
}
private function copyStaticCSV()
{
$workDir = $_SERVER['DOCUMENT_ROOT'].'/'.$this->workDir;
system('cp '.$workDir.self::STATIC_CSV_DIR.'externalservice.csv '.$workDir.'/'.self::OUTPUT_DIR);
system('cp '.$workDir.self::STATIC_CSV_DIR.'type.csv '.$workDir.'/'.self::OUTPUT_DIR);
}
private $currentParentGroup = '';
private function addItemToCSV($fName, $group, $item)
{
$data = array(
'CODE' => $item['CODE'],
'PARENT_CODE' => $item['PARENT_CODE'],
'TYPE_CODE' => $item['TYPE_CODE']
);
$data['NAME.RU.NAME'] = '';
$data['NAME.EN.NAME'] = '';
$data['NAME.UA.NAME'] = '';
$name = unserialize($item['LANGNAMES']);
foreach($name as $lid => $values)
{
foreach($values as $i => $val)
$data['NAME.'.$lid.'.'.$i] = $val;
}
$data['EXT.YAMARKET.0'] = '';
$data['EXT.ZIP.0'] = '';
$externals = unserialize($item['EXTERNALS']);
if(!empty($externals))
{
foreach($externals as $type => $values)
{
if(is_array($values))
{
foreach($values as $i => $val)
$data['EXT.'.$type.'.'.$i] = $val;
}
}
}
$data['LONGITUDE'] = $item['LONGITUDE'];
$data['LATITUDE'] = $item['LATITUDE'];
/*
$this->output($data);
$this->output($group);
$this->output($fName);
*/
$this->putToFile2(
$data,
$group,
$fName,
true
);
}
public function generateExportFilesFromTableBundle($item, $table)
{
if(in_array($item['TYPE_CODE'], $this->typeGroups['LAYOUT']['TYPES']))
$this->currentParentGroup = $item['CODE'];
########################################################
########################################################
########################################################
$cat = $this->sysMaps['BASETYPE2GROUP'][$item['TYPE_CODE']];
$fName = $this->typeGroups[$cat]['FILE_NAME_TEMPLATE'];
$fName = str_replace(array(
'%BASE_PARENT_ITEM_CODE%',
'%CODE%',
'.csv'
), array(
$cat == 'LAYOUT' ? '' : $this->currentParentGroup,
ToLower($cat),
''
), $fName);
$this->addItemToCSV($fName, 'assets', $item);
########################################################
########################################################
########################################################
}
public function generateExportFilesFromTableBundle_Standard($item, $table)
{
if(in_array($item['TYPE_CODE'], $this->typeGroups['LAYOUT']['TYPES']))
$this->currentParentGroup = $item['CODE'];
########################################################
########################################################
########################################################
$cat = $this->sysMaps['BASETYPE2GROUP'][$item['TYPE_CODE']];
$fName = $this->typeGroups[$cat]['FILE_NAME_TEMPLATE'];
$fName = str_replace(array(
'%BASE_PARENT_ITEM_CODE%',
'%CODE%',
'.csv'
), array(
$cat == 'LAYOUT' ? '' : $this->currentParentGroup,
ToLower($cat),
''
), $fName);
$this->addItemToCSV($fName, 'assets_standard', $item);
########################################################
########################################################
########################################################
}
public function generateExportFilesFromTableBundle_Standard_YandexOnly($item, $table)
{
if(in_array($item['TYPE_CODE'], $this->typeGroups['LAYOUT']['TYPES']))
$this->currentParentGroup = $item['CODE'];
########################################################
########################################################
########################################################
if($item['TYPE_CODE'] == 'VILLAGE' && strpos($item['EXTERNALS'], 'YAMARKET') === false/*not from yandex database*/)
{
//$this->output($item['NAME'].' skipped');
return false;
}
$cat = $this->sysMaps['BASETYPE2GROUP'][$item['TYPE_CODE']];
$fName = $this->typeGroups[$cat]['FILE_NAME_TEMPLATE'];
$fName = str_replace(array(
'%BASE_PARENT_ITEM_CODE%',
'%CODE%',
'.csv'
), array(
$cat == 'LAYOUT' ? '' : $this->currentParentGroup,
ToLower($cat),
''
), $fName);
$this->addItemToCSV($fName, 'assets_standard', $item);
########################################################
########################################################
########################################################
return true;
}
private function generateExportTreeRussia()
{
$this->fiasDB = new Db\FiasTable();
$this->eTreeDBRussia->dropCodeIndex();
$this->eTreeDBRussia->setExportOffset(intval($this->eTreeDB->getNextFreeCode())); // start where the previous table ended
// get yandex regions
$regions = $this->readFiasRootMapV2();
// add Russia (country), districts and regions, that are taken from yandex
$this->generateExportTreePutRussiaBundle(array(self::RUSSIA_YANDEX_CODE), $regions, 0);
// add all precious content from fias: subregions, cities, villages, streets
$this->generateExportTreePutRussiaInner();
$this->eTreeDBRussia->doneInsert();
$this->eTreeDBRussia->switchIndexes(true);
}
private function getYandexToFiasCityMap($yandexRegionId)
{
$result = array();
$fias2yandex = $this->getDataFromCSV('fias_yamarket_links', 'region_'.$yandexRegionId);
foreach($fias2yandex as $map)
{
unset($map['HZ']); // csv viewer would crash without this key (wonder why)
$result[$map['AOGUID']] = $map;
}
return $result;
}
private function generateExportTreePutRussiaInner()
{
// get yandex-to-fias region code map
$links = $this->getFias2YamarketRootLinks(false, true);
$i = -1;
// for each region we must dump its content
// $yRId is a yandex id for the target region
// $fiasRegions is one (mostly) or several corresponding "regions" from fias
foreach($links as $yRId => $fiasRegions)
{
$i++;
// get yandex-to-fias city code map for the current region
$this->fias2yandexCityMap = $this->getYandexToFiasCityMap($yRId);
$this->currentRegion = $this->mapETCodeAsYandex($yRId);
$this->eTreeDBRussia->dropCodeIndex(); // drop previous region index
foreach($fiasRegions as $regionGuid)
{
$this->fiasPath = array();
$this->generateExportTreePutRussiaInnerBundle($regionGuid);
}
//break;
}
}
private function checkIsAllowedCityVillage($item)
{
$baseType = $this->sysMaps['FIAS2BASETYPE'][$item['SHORTNAME']];
//if($baseType == 'CITY' || $baseType == 'VILLAGE')
// $this->output('Doubtfull city\village: '.$item['FORMALNAME'].' ('.$item['SHORTNAME'].')');
$skip = array('5544bf6a-0ec1-4b5f-bbc5-49294f71de16'/*тягловая подстанция*/, '22a77f13-3764-41dc-aa23-db680b03ef5d'/*6 км АЗС*/, '3f2ab130-274e-4fd6-b611-a94467b04f57'/*Велтон Парк duplicate*/, '762758bb-18b9-440f-bc61-8e1e77ff3fd8', /*Московский посёлок, not exists*/);
return ($baseType == 'CITY' || $baseType == 'VILLAGE') &&
(
$this->fiasToBaseType[$baseType][$item['SHORTNAME']]['U'] /*code is in a list of allowed types for export*/
||
isset($this->fias2yandexCityMap[$item['AOGUID']] /*code is present in yandex2fias city map*/
) &&
!in_array($item['AOGUID'], $skip) // not one of those forbidden broken items
);
}
private function checkIsAllowedStreet($item)
{
$baseType = $this->sysMaps['FIAS2BASETYPE'][$item['SHORTNAME']];
return ($baseType == 'STREET' && $this->fiasToBaseType[$baseType][$item['SHORTNAME']]['U']); /*street code is in a list of allowed types for export*/
}
public function generateExportTreePutRussiaFiasPathCutForbidden($path)
{
/*
$object = $path[count($path) - 1];
if($object['AOGUID'] == 'da99f366-1a88-43b1-9aa8-c1b66334c97f')
{
$found = true;
\_print_r('Wow: da99f366-1a88-43b1-9aa8-c1b66334c97f');
\_print_r($object);
}
*/
//$path = array_reverse($path);
$newPath = array();
$lastValidId = false;
$neepPasteLastValid = false;
foreach($path as $item)
{
if(isset($this->forbiddenPathTypes[$item['SHORTNAME']]) || isset($this->forbiddenPathIds[$item['AOGUID']]) || $this->checkIsAllowedStreet($item['SHORTNAME']))
{
$neepPasteLastValid = true;
continue;
}
else
{
if($lastValidId !== false && $neepPasteLastValid)
{
$item['PARENTGUID'] = $lastValidId;
$neepPasteLastValid = false;
}
$lastValidId = $item['AOGUID'];
}
$newPath[] = $item;
}
/*
if($found)
{
\_print_r('Path is now:');
\_print_r($newPath);
die();
}
*/
return $newPath;
}
private function generateExportTreePutRussiaFiasPath($targetItem)
{
// pre-process, cut off unwanted types (actually, streets)
$newPath = $this->generateExportTreePutRussiaFiasPathCutForbidden($this->fiasPath);
$i = -1;
foreach($newPath as $item)
{
$i++;
// external data
$externals = array();
if(strlen($item['POSTALCODE']))
$externals['ZIP'][] = $item['POSTALCODE'];
if(isset($this->fias2yandexCityMap[$item['AOGUID']]))
$externals['YAMARKET'][] = $this->fias2yandexCityMap[$item['AOGUID']]['ID'];
// type and name
$itemType = $item['SHORTNAME'];
$baseType = $this->sysMaps['FIAS2BASETYPE'][$itemType];
$typeNameReplace = $baseType != 'CITY' ? $this->sysMaps['FIASTYPEREPLACE'][$itemType] : ''; // replace base type (e.g. "п" => "посёлок", "д" => "деревня", ...)
$name = trim($item['FORMALNAME']).(strlen($typeNameReplace) ? ' '.$typeNameReplace : '');
$this->eTreeDBRussia->insert(array(
'TYPE_CODE' => $baseType,
'FIAS_TYPE' => $itemType,
'NAME' => $name,
'LANGNAMES' => array('RU' => array('NAME' => $name)),
'EXTERNALS' => $externals,
'SOURCE' => self::SOURCE_FIAS,
'SYS_CODE' => $this->mapETCodeAsFias($item['AOGUID']),
'PARENT_SYS_CODE' => $i ? $this->mapETCodeAsFias($item['PARENTGUID']) : $this->currentRegion
));
}
}
private function generateExportTreePutRussiaStreets($parentGuid)
{
if(!strlen($parentGuid))
return;
$res = $this->fiasDB->getActualChildren($parentGuid);
while($item = $res->fetch())
{
$itemType = $item['SHORTNAME'];
if($this->checkIsAllowedStreet($item))
{
$externals = array();
if(strlen($item['POSTALCODE']))
$externals['ZIP'][] = $item['POSTALCODE'];
$baseType = $this->sysMaps['FIAS2BASETYPE'][$itemType];
$name = trim($item['FORMALNAME']).' '.$this->sysMaps['FIASTYPEREPLACE'][$itemType];
$this->eTreeDBRussia->insert(array(
'TYPE_CODE' => $baseType,
'FIAS_TYPE' => $itemType,
'NAME' => $name,
'LANGNAMES' => array('RU' => array('NAME' => $name)),
'EXTERNALS' => $externals,
'SOURCE' => self::SOURCE_FIAS,
'SYS_CODE' => $this->mapETCodeAsFias($item['AOGUID']),
'PARENT_SYS_CODE' => $this->mapETCodeAsFias($parentGuid),
));
}
}
}
private function generateExportTreePutRussiaInnerBundle($parentGuid)
{
if(!strlen($parentGuid))
return;
$res = $this->fiasDB->getActualChildren($parentGuid);
while($item = $res->fetch())
{
$item['PARENTGUID'] = $parentGuid;
array_push($this->fiasPath, $item);
if($this->checkIsAllowedCityVillage($item)) // check if this is a village or city or what else we should add to export
{
//$this->output('Allowed city\village '.$item['FORMALNAME']);
$this->generateExportTreePutRussiaFiasPath($item); // ALSO store intermediate locations from current region-to-city(village, etc) being stored
$this->generateExportTreePutRussiaStreets($item['AOGUID']); // store all streets of current village\city\...
}
$this->generateExportTreePutRussiaInnerBundle($item['AOGUID']);
array_pop($this->fiasPath);
}
}
private function generateExportTreePutRussiaBundle($bundle, $regions, $dl = 0)
{
foreach($bundle as $id)
{
$node = $this->data['TREES']['MAIN']['NODES'][$id];
$edges = array();
if(isset($this->data['TREES']['MAIN']['EDGES'][$id]))
$edges = $this->data['TREES']['MAIN']['EDGES'][$id];
if(in_array($node['TYPE_CODE'], array('COUNTRY', 'COUNTRY_DISTRICT', 'REGION')))
{
if($node['TYPE_CODE'] == 'REGION')
{
// get fias code & postal code, if any
$fNode = $this->fiasDB->getByAOGUID($regions[$node['ID']]['AOGUID']);
if(strlen($fNode['POSTALCODE']))
$node['EXT']['ZIP'][] = $fNode['POSTALCODE'];
$edges = array(); // no way farther
}
// set english name for Russia
if($node['TYPE_CODE'] == 'COUNTRY')
$node['NAME']['EN']['NAME'] = 'Russian Federation';
if($node['NAME']['RU']['NAME'] == 'Москва и Московская область')
$node['NAME']['RU']['NAME'] = 'Московская область';
if($node['NAME']['RU']['NAME'] == 'Санкт-Петербург и Ленинградская область')
$node['NAME']['RU']['NAME'] = 'Ленинградская область';
$this->eTreeDBRussia->insert(array(
'TYPE_CODE' => $node['TYPE_CODE'],
'NAME' => $node['NAME']['RU']['NAME'],
'LANGNAMES' => $node['NAME'],
'EXTERNALS' => $node['EXT'],
'SOURCE' => self::SOURCE_YANDEX,
'SYS_CODE' => $this->mapETCodeAsYandex($node['ID']),
'PARENT_SYS_CODE' => strlen($node['PARENT_ID']) && $dl > 0 ? $this->mapETCodeAsYandex($node['PARENT_ID']) : ''
));
if(!empty($edges))
$this->generateExportTreePutRussiaBundle($edges, $regions, $dl+1);
}
}
}
#########################
private function generateExportTreeWorld()
{
$this->eTreeDB->dropCodeIndex();
$this->eTreeDB->restoreExportOffset();
$this->eTreeDB->switchIndexes(false);
$csv = new Import\CSVReader();
$csv->loadFile($_SERVER['DOCUMENT_ROOT'].'/locations_data/'.self::WORLD_SOURCE);
$countries = array();
while($item = $csv->Fetch())
{
$item = explode(',', $item[0]);
if(!isset($item[1])) // its a language marker
continue;
// exclude the following countries, kz we got an extended file for them
if(in_array($item[2], array('USA', 'Kazakhstan', 'Ukraine', 'Byelorussia', 'Russian Federation', 'Azerbaijan', 'Estonia', 'Georgia', 'Latvia', 'Lithuania', 'Moldavia', 'Turkmenistan', 'Armenia', 'Tadjikistan', 'Uzbekistan')))
continue;
$id = implode(':', $item);
$countries[] = $item[2].' - '.$item[4];
$this->eTreeDB->insert(array(
'TYPE_CODE' => 'COUNTRY',
'NAME' => $item[4],
'LANGNAMES' => serialize(array(
'RU' => array('NAME' => $item[4]),
'EN' => array('NAME' => $item[2])
)),
'EXTERNALS' => '',
'SOURCE' => self::SOURCE_LEGACY,
'SYS_CODE' => $this->mapETCodeAsLegacy($id),
'PARENT_SYS_CODE' => ''
));
}
$this->eTreeDB->doneInsert();
$this->eTreeDB->switchIndexes(true);
}
#########################
private function generateExportTreeLegacy($source)
{
$this->eTreeDB->dropCodeIndex();
$this->eTreeDB->restoreExportOffset();
$this->eTreeDB->switchIndexes(false);
$csv = new Import\CSVReader();
$csv->loadFile($_SERVER['DOCUMENT_ROOT'].'/locations_data/'.$source);
$lastOnes = array();
while($item = $csv->Fetch())
{
$item = explode(',', $item[0]);
if(!isset($item[1])) // its a language marker
continue;
if($item[0] == 'R')
{
$item[2] = preg_replace('# obl$#', ' region', $item[2]);
$item[4] = preg_replace('# обл$#', ' область', $item[4]);
}
$parentId = '';
if($item[0] == 'S')
$type = 'COUNTRY';
if($item[0] == 'R')
$type = 'REGION';
if($item[0] == 'T')
$type = 'CITY';
$id = implode(':', $item);
if($type == 'REGION')
$parentId = $lastOnes['COUNTRY'];
elseif($type == 'CITY')
$parentId = $lastOnes['PARENT'];
else
$parentId = '';
if($type != 'CITY')
{
$lastOnes[$type] = $id;
$lastOnes['PARENT'] = $id;
}
$this->eTreeDB->insert(array(
'TYPE_CODE' => $type,
'NAME' => $item[4],
'LANGNAMES' => serialize(array(
'RU' => array('NAME' => $item[4]),
'EN' => array('NAME' => $item[2])
)),
'EXTERNALS' => '',
'SOURCE' => self::SOURCE_LEGACY,
'SYS_CODE' => $this->mapETCodeAsLegacy($id),
'PARENT_SYS_CODE' => strlen($parentId) ? $this->mapETCodeAsLegacy($parentId) : ''
));
}
$this->eTreeDB->doneInsert();
$this->eTreeDB->switchIndexes(true);
}
#########################
private function generateExportTreeUSA()
{
$this->eTreeDB->dropCodeIndex();
$this->eTreeDB->restoreExportOffset();
$this->eTreeDB->switchIndexes(false);
$csv = new Import\CSVReader();
$csv->loadFile($_SERVER['DOCUMENT_ROOT'].'/locations_data/'.self::USA_SOURCE);
$lastOnes = array();
while($item = $csv->Fetch())
{
$item = explode(',', $item[0]);
if(!isset($item[1])) // its a language marker
continue;
$parentId = '';
if($item[0] == 'S')
$type = 'COUNTRY';
if($item[0] == 'R')
$type = 'REGION';
if($item[0] == 'T')
$type = 'CITY';
$id = implode(':', $item);
if($type == 'REGION')
$parentId = $lastOnes['COUNTRY'];
elseif($type == 'CITY')
$parentId = $lastOnes['PARENT'];
else
$parentId = '';
if($type != 'CITY')
{
$lastOnes[$type] = $id;
$lastOnes['PARENT'] = $id;
}
if($item['2'] == 'USA')
$item['4'] = 'США';
$this->eTreeDB->insert(array(
'TYPE_CODE' => $type,
'NAME' => $item[4],
'LANGNAMES' => serialize(array(
'RU' => array('NAME' => $item[4]),
'EN' => array('NAME' => $item[2])
)),
'EXTERNALS' => '',
'SOURCE' => self::SOURCE_LEGACY,
'SYS_CODE' => $this->mapETCodeAsLegacy($id),
'PARENT_SYS_CODE' => strlen($parentId) ? $this->mapETCodeAsLegacy($parentId) : ''
));
}
$this->eTreeDB->doneInsert();
$this->eTreeDB->switchIndexes(true);
}
#########################
private function generateExportTreeBelorussia()
{
$this->eTreeDB->dropCodeIndex();
$this->eTreeDB->restoreExportOffset();
$this->eTreeDB->switchIndexes(false);
$this->generateExportTreePutBelorussiaBundle(array(self::BELORUSSIA_YANDEX_CODE));
$this->eTreeDB->doneInsert();
$this->eTreeDB->switchIndexes(true);
}
private function generateExportTreePutBelorussiaBundle($bundle)
{
foreach($bundle as $id)
{
$node = $this->data['TREES']['MAIN']['NODES'][$id];
$edges = array();
if(isset($this->data['TREES']['MAIN']['EDGES'][$id]))
$edges = $this->data['TREES']['MAIN']['EDGES'][$id];
// attach to belorussia its en-name
if($node['TYPE_CODE'] == 'COUNTRY')
$node['NAME']['EN']['NAME'] = 'Belarus';
// these two types are not allowed currently, because we do not have the corresponding types in fias
if($node['TYPE_CODE'] == 'METRO_STATION' || $node['TYPE_CODE'] == 'CITY_DISTRICT')
continue;
$this->eTreeDB->insert(array(
'TYPE_CODE' => $node['TYPE_CODE'],
'NAME' => $node['NAME']['RU']['NAME'],
'LANGNAMES' => serialize($node['NAME']),
'EXTERNALS' => serialize($node['EXT']),
'SOURCE' => self::SOURCE_YANDEX,
'SYS_CODE' => $this->mapETCodeAsYandex($node['ID']),
'PARENT_SYS_CODE' => strlen($node['PARENT_ID']) ? $this->mapETCodeAsYandex($node['PARENT_ID']) : ''
));
if(!empty($edges))
$this->generateExportTreePutBelorussiaBundle($edges);
}
}
#########################
private function generateExportTreeUkrain()
{
$this->eTreeDB->dropCodeIndex();
$this->eTreeDB->restoreExportOffset();
$cd2r = $this->getDataFromCSV('ukrain_kazakhstan', 'ukrain_district2region');
$tree = array();
$tree['NODES'][self::UKRAIN_YANDEX_CODE] = array(
'NAME' => array(
'RU' => array('NAME' => 'Украина'),
'UA' => array('NAME' => 'Україна'),
'EN' => array('NAME' => 'Ukraine')
),
'TYPE_CODE' => 'COUNTRY',
'SOURCE' => self::SOURCE_YANDEX,
'ID' => self::UKRAIN_YANDEX_CODE,
'EXT' => array(
'YAMARKET' => array(
self::UKRAIN_YANDEX_CODE
)
)
);
foreach($cd2r as $line)
{
// add country district
if(!isset($tree['NODES'][$line['CDID']]))
{
$tree['NODES'][$line['CDID']] = array(
'NAME' => $line['CDNAME'],
'TYPE_CODE' => 'COUNTRY_DISTRICT',
'SOURCE' => self::SOURCE_YANDEX,
'ID' => $line['CDID'],
'PARENT_ID' => self::UKRAIN_YANDEX_CODE,
'EXT' => array(
'YAMARKET' => array(
$line['CDID'] // country district id in file
),
)
);
}
$tree['EDGES'][self::UKRAIN_YANDEX_CODE][$line['CDID']] = true;
$regionId = 'r'.md5($line['RNAME']['UA']['NAME']);
if($line['RNAME']['UA']['NAME'] == 'Севастополь, Місто' || $line['RNAME']['UA']['NAME'] == 'Автономна Республіка Крим')
$source = self::SOURCE_UKRAIN;
else
$source = self::SOURCE_YANDEX;
if($line['RNAME']['UA']['NAME'] == 'Севастополь, Місто')
{
$typeCode = 'SUBREGION';
}
else
{
$typeCode = 'REGION';
}
// add region
if(!isset($tree['NODES'][$regionId]))
{
$tree['NODES'][$regionId] = array(
'NAME' => $line['RNAME'],
'TYPE_CODE' => $typeCode,
'SOURCE' => $source,
'ID' => $regionId,
'PARENT_ID' => $line['CDID'],
);
if($source == self::SOURCE_YANDEX)
$tree['NODES'][$regionId]['EXT']['YAMARKET'][] = $line['RID'];
}
$tree['EDGES'][$line['CDID']][$regionId] = true;
}
$res = $this->getDataFromCSV('ukrain_kazakhstan', 'ukrain');
foreach($res as $line)
{
if($line['REGION'] == 'Автономна республіка Крим')
$line['REGION'] = 'Автономна Республіка Крим';
$line['REGION'] = $this->mb_str_replace('Місто', 'місто', $line['REGION']);
$line['SUBREGION'] = $this->mb_str_replace('Місто', 'місто', $line['SUBREGION']);
$line['CITY'] = $this->mb_str_replace('Місто', 'місто', $line['CITY']);
$regionId = 'r'.md5($line['REGION']);
$subRegionId = 'sr'.md5($line['SUBREGION']);
$cityId = 'c'.md5($line['CITY']);
if($line['REGION'] != 'Севастополь, Місто')
{
if(!isset($tree['NODES'][$subRegionId]))
{
$tree['NODES'][$subRegionId] = array(
'NAME' => array('UA' => array('NAME' => $line['SUBREGION'])),
'TYPE_CODE' => 'SUBREGION',
'SOURCE' => self::SOURCE_UKRAIN,
'ID' => $subRegionId,
'PARENT_ID' => $regionId,
'EXT' => array()
);
if(!isset($tree['EDGES'][$regionId][$subRegionId]))
$tree['EDGES'][$regionId][$subRegionId] = true;
}
}
if(!isset($tree['NODES'][$cityId]))
{
$tree['NODES'][$cityId] = array(
'NAME' => array('UA' => array('NAME' => $line['CITY'])),
'TYPE_CODE' => 'CITY',
'SOURCE' => self::SOURCE_UKRAIN,
'ID' => $cityId,
'PARENT_ID' => $subRegionId,
'EXT' => array()
);
if(!isset($tree['EDGES'][$subRegionId][$cityId]))
$tree['EDGES'][$subRegionId][$cityId] = true;
}
}
foreach($tree['EDGES'] as $k => $edges)
$tree['EDGES'][$k] = array_keys($edges);
$this->data['TREES']['UKRAIN'] = $tree;
$this->generateExportTreePutUkrainBundle(array(self::UKRAIN_YANDEX_CODE));
unset($this->data['TREES']['UKRAIN']);
$this->eTreeDB->doneInsert();
}
private function generateExportTreePutUkrainBundle($bundle)
{
foreach($bundle as $id)
{
$node = $this->data['TREES']['UKRAIN']['NODES'][$id];
$edges = array();
if(isset($this->data['TREES']['UKRAIN']['EDGES'][$id]))
$edges = $this->data['TREES']['UKRAIN']['EDGES'][$id];
$this->eTreeDB->insert(array(
'TYPE_CODE' => $node['TYPE_CODE'],
'NAME' => $node['NAME']['UA']['NAME'],
'LANGNAMES' => serialize($node['NAME']),
'EXTERNALS' => serialize($node['EXT']),
'SOURCE' => $node['SOURCE'],
'SYS_CODE' => $this->mapETCodeAsUkrainian($node['ID']),
'PARENT_SYS_CODE' => strlen($node['PARENT_ID']) ? $this->mapETCodeAsUkrainian($node['PARENT_ID']) : ''
));
if(!empty($edges))
$this->generateExportTreePutUkrainBundle($edges);
}
}
private function mapETCodeAsYandex($code)
{
return 'Y_'.$code;
}
private function mapETCodeAsFias($code)
{
return 'F_'.$code;
}
private function mapETCodeAsUkrainian($name)
{
return 'U_'.md5($name);
}
private function mapETCodeAsLegacy($name)
{
return 'L_'.md5($name);
}
#######################################################
### ABOUT EXPORT TREE GENERATION
#######################################################
private function mapETCodeBySource($value, $source)
{
if($source == self::SOURCE_YANDEX)
return 'Y_'.$value;
if($source == self::SOURCE_FIAS)
return 'F_'.$value;
if($source == self::SOURCE_UKRAIN)
return 'U_'.md5($name);
if($source == self::SOURCE_KAZAKHSTAN)
return 'K_'.md5($name);
}
private function startExportFromScratch()
{
$this->cleanTemporalData(self::TMP_DATA_RUS_EXPORT_INDEX);
$this->cleanTemporalData(self::TMP_DATA_RUS_GLOBAL_INDEX);
$this->cleanPoolDir('assets');
}
private function generateExportTreeRussiaRoot()
{
$this->restoreTDRusExpIndex();
if(!empty($this->alreadyDumped))
return;
$regions = $this->readFiasRootMapV2();
$this->generateExportTreePutRussiaBundleOld(array(self::RUSSIA_YANDEX_CODE), $regions, 0);
$this->storeTemporalData(self::TMP_DATA_RUS_EXPORT_INDEX, $this->alreadyDumped);
}
private function restoreTDRusExpIndex()
{
if(!empty($this->alreadyDumped))
return;
$this->alreadyDumped = $this->getStoredTemporalData(self::TMP_DATA_RUS_EXPORT_INDEX);
}
private function storeTDGlobalExpIndex()
{
$this->storeTemporalData(self::TMP_DATA_RUS_GLOBAL_INDEX, array('I' => $this->exportOffset));
}
private function restoreTDGlobalExpIndex()
{
if($this->exportOffset == 0)
{
$data = $this->getStoredTemporalData(self::TMP_DATA_RUS_GLOBAL_INDEX);
$this->exportOffset = intval($data['I']);
}
}
private function generateExportTreePutRussiaBundleOld($bundle, $regions, $dl = 0)
{
foreach($bundle as $id)
{
$node = $this->data['TREES']['MAIN']['NODES'][$id];
$edges = array();
if(isset($this->data['TREES']['MAIN']['EDGES'][$id]))
$edges = $this->data['TREES']['MAIN']['EDGES'][$id];
if(in_array($node['TYPE_CODE'], array('COUNTRY', 'COUNTRY_DISTRICT', 'REGION')))
{
if($node['TYPE_CODE'] == 'REGION')
{
// get fias code & postal code, if any
//$node['EXT']['FIAS'][] = $regions[$node['ID']]['AOGUID'];
$fNode = $this->fiasGetByAOGUID($regions[$node['ID']]['AOGUID']);
if(strlen($fNode['POSTALCODE']))
$node['EXT']['ZIP'][] = $fNode['POSTALCODE'];
$edges = array(); // no way farther
}
$this->addItemToExportTree(array(
'ID' => $this->mapETCodeAsYandex($node['ID']),
'PARENT_ID' => strlen($node['PARENT_ID']) && $dl > 0 ? $this->mapETCodeAsYandex($node['PARENT_ID']) : '',
'TYPE' => $node['TYPE_CODE'],
'NAME' => $node['NAME'],
'EXTERNALS' => $node['EXT'],
'SOURCE' => self::SOURCE_YANDEX,
));
if(!empty($edges))
$this->generateExportTreePutRussiaBundle($edges, $regions, $dl+1);
}
}
}
private $fiasPath = array();
private $alreadyStoredPathItems = array();
private $fias2yandexMap = array();
private $alreadyDumped = array();
private $currentRegion = false;
private function generateExportTreeRussiaInner()
{
$links = $this->getFias2YamarketRootLinks(false, true);
//$this->output($links);
$i = -1;
foreach($links as $yRId => $regions)
{
$i++;
$this->restoreTDGlobalExpIndex();
$this->alreadyDumped = array();
$this->restoreTDRusExpIndex();
$this->fias2yandexMap = array();
$fias2yandex = $this->getDataFromCSV('fias_yamarket_links', 'region_'.$yRId);
foreach($fias2yandex as $map)
{
$this->fias2yandexMap[$map['AOGUID']] = $map;
}
unset($fias2yandex);
$this->currentRegion = $this->mapETCodeBySource($yRId, self::SOURCE_YANDEX);
foreach($regions as $regionId)
{
$this->fiasPath = array();
$this->output('CCCurrent REGION is '.$this->currentRegion);
//$this->output($this->alreadyDumped);
$this->generateExportTreeRussiaInnerBundle($regionId);
}
$this->storeTDGlobalExpIndex();
//break; // tmp
//if($i == 1)break;
}
}
private function generateExportTreeRussiaInnerBundle($parentGuid)
{
if(!strlen($parentGuid))
return;
$res = $this->getDataFromCSV('fias_tree', $parentGuid);
foreach($res as $item)
{
if($item['LIVESTATUS'] != '1' || $item['ACTSTATUS'] != '1')
continue;
$item['PARENT_ID'] = $parentGuid;
array_push($this->fiasPath, $item);
if($this->checkIsAllowedCityVillage($item['ID'], $item['TYPE']))
{
// ADD!!!
$this->storeCurrentFiasPath2();
$this->generateExportTreeRussiaInnerStreets($item['ID']);
}
$this->generateExportTreeRussiaInnerBundle($item['ID']);
array_pop($this->fiasPath);
}
}
private function addItemToExportTree($item)
{
$this->exportOffset++;
$this->output('ADD: '.$item['NAME']['RU']['NAME'].' '.$item['TYPE']);
//$this->output($item);
$cat = $this->sysMaps['BASETYPE2GROUP'][$item['TYPE']];
$fName = $this->typeGroups[$cat]['FILE_NAME_TEMPLATE'];
$header = $this->typeGroups[$cat];
$this->alreadyDumped[$item['ID']] = $this->exportOffset;
$parentCode = strlen($item['PARENT_ID']) ? $this->addLeadingZero($this->alreadyDumped[$item['PARENT_ID']], self::CODE_LENGTH) : '';
$data = array(
'CODE' => $this->addLeadingZero($this->exportOffset, self::CODE_LENGTH),
'PARENT_CODE' => $parentCode,
'TYPE_CODE' => $item['TYPE']
);
foreach($item['NAME'] as $lid => $values)
{
foreach($values as $i => $val)
$data['NAME.'.$lid.'.'.$i] = $val;
}
$data['EXT.YAMARKET.0'] = '';
$data['EXT.ZIP.0'] = '';
if(!empty($item['EXTERNALS']))
{
foreach($item['EXTERNALS'] as $type => $values)
{
foreach($values as $i => $val)
$data['EXT.'.$type.'.'.$i] = $val;
}
}
$parentGroupId = strlen($item['PARENT_GROUP_ID']) ? $this->addLeadingZero($this->alreadyDumped[$item['PARENT_GROUP_ID']], self::CODE_LENGTH) : '';
$data['LONGITUDE'] = '';
$data['LATITUDE'] = '';
//$this->output('PGID is set to '.$parentGroupId);
$fName = str_replace(array(
'%BASE_PARENT_ITEM_CODE%',
'%CODE%',
'.csv'
), array(
$parentGroupId,
ToLower($cat),
''
), $fName);
$this->output('PUT:');
$this->output($data);
$this->output('TO:');
$this->output($fName);
$this->putToFile2(
$data,
'assets',
$fName,
true
);
}
#######################################################
### ABOUT MAIN TREE
#######################################################
// map yandex cities to fias cities
public function buildMainTree()
{
$this->queue = false;
$this->data['TREES']['MAIN'] = array();
$this->data['MAPS'] = array();
$this->data['INDEXES'] = array();
$done = false;
while(!$done)
$done = $this->buildMainTreeNext();
// build name-path index for russia
$this->buildRussiaPathIndex($this->data['TREES']['MAIN']['EDGES'][self::RUSSIA_YANDEX_CODE], array());
}
private function buildMainTreeNext()
{
$next = $this->queueShift();
$bundle = $this->getBundleFromFile($next);
if(!empty($bundle))
{
foreach($bundle as $item)
{
$this->data['TREES']['MAIN']['NODES'][$item['ID']] = $item;
$parent = isset($item['PARENT_ID']) ? $item['PARENT_ID'] : 'ROOT';
$this->data['TREES']['MAIN']['EDGES'][$parent][] = $item['ID'];
if($item['CHILDREN_COUNT'] > 0)
$this->queue[] = $item['ID'];
}
}
return empty($this->queue);
}
#######################################################
### ABOUT FIAS PROCESS
#######################################################
// temporal function
private function checkFiasMaps()
{
$links = $res = $this->getDataFromCSV('fias_yamarket_links', 'rootv2');
$uTotal = 0;
foreach($links as $reg)
{
if($reg['CITIES_MAPPED'] != '1')
{
//$this->output($reg);
$rMap = $this->getDataFromCSV('fias_yamarket_links', 'region_'.$reg['YAMARKET']);
$this->output('============================ For: '.$reg['YAMARKET_NAME'].' '.$reg['YAMARKET']);
$unmapped = 0;
foreach($rMap as $map)
{
if(!strlen($map['AOGUID']))
{
$unmapped++;
$this->output($map);
$res = DB\FiasTable::getList(array('filter' => array(
'FORMALNAME' => $map['NAME'],
'!SHORTNAME' => array('ул', 'пер'),
'ACTSTATUS' => '1',
'LIVESTATUS' => '1'
)));
while($item = $res->fetch())
{
$this->output($item);
}
}
}
$this->output('Unmapped: '.$unmapped);
$uTotal += $unmapped;
}
}
$this->output('TOTAL: '.$uTotal);
}
private function showChildren($pId)
{
$res = DB\FiasTable::getList(array('filter' => array(
'PARENTGUID' => $pId,
'ACTSTATUS' => '1',
'LIVESTATUS' => '1'
)));
while($item = $res->fetch())
{
$this->output($item);
}
}
private function findPathes()
{
$pathes = array(
'aea7bac4-f9b4-4160-95f2-3d667b4d3f92', // отрадное, калиниградская область, 10857
'bda061ac-cbd0-4db8-8d18-69db43e76c2d', // отрадное, калиниградская область, 10857
'436b841d-a44f-431e-b1ec-7d76456d4a11', // отрадное, калиниградская область, 10857
'807943cc-31c0-4a86-a3fe-46d9262101e9', // дагомыс, краснодарский край, 10995
);
foreach($pathes as $id)
{
$this->fiasFindPath($id);
}
}
private function fiasFindPath($aoguid)
{
$pId = $aoguid;
while($pId && $res = DB\FiasTable::getList(array('filter' => array(
'AOGUID' => $pId,
'ACTSTATUS' => '1',
'LIVESTATUS' => '1'
)))->fetch())
{
$this->output($res);
if($res['PARENTGUID'])
$pId = $res['PARENTGUID'];
else
$pId = false;
}
}
private function fiasFind2()
{
$res = DB\FiasTable::getList(array('filter' => array(
'FORMALNAME' => array(
),
//'ACTSTATUS' => '1',
//'LIVESTATUS' => '1'
)));
while($item = $res->fetch())
{
$this->output($item);
}
}
private function fiasFind()
{
$findInFias = array(
//СС А РРР ГГГ ВВВ ППП УУУУ ЭЭЭЭ ЦЦЦ
'11 0 007 000 000 009 0000 0000 000', // кажым, коми, 10939
'35 0 003 000 000 001 0000 0000 000', // им бабушкина, волог. обл, 10853
'05 0 017 000 000 019 0000 0000 000', // ачи-су, дагестан, 11010
'20 0 028 000 000 001 0000 0000 000', // итум-кали, чечня, 11024
'16 0 022 000 000 023 0000 0000 000', // куланга, татарстан, 11119
'59 0 020 000 000 003 0000 0000 000', // гамово, пермский край, 11108
'56 0 000 000 000 002 0000 0000 000', // зато комаровский, оренбургская область, 11084
'86 0 003 000 000 031 0000 0000 000', // узюм-юрганская гкс, ханты-мансийскиий ао, 11193
'70 0 007 000 000 000 0000 0047 000', // игол, томская область, 11353
'27 0 009 000 000 001 0000 0000 000', // им полины осипенко, хабаровскйи край, 11457
'28 0 014 000 000 045 0000 0000 000', // свободный-21, амурская область, 11375
'14 0 010 000 000 001 0000 0000 000', // багатай, саха якутия, 11443
);
$res = DB\FiasTable::getList(array('filter' => array(
'CODE' => array_values($findInFias),
'ACTSTATUS' => '1',
'LIVESTATUS' => '1'
)));
while($item = $res->fetch())
{
$this->output($item);
}
}
private function fiasGetByAOGUID($fiasId)
{
return DB\FiasTable::getList(array('filter' => array(
'=AOGUID' => $fiasId,
)))->fetch();
}
/*
private function parseFiasCode($code)
{
//СС(0) А(1) РРР(2) ГГГ(3) ВВВ(4) ППП(5) УУУУ(6) ЭЭЭЭ(7) ЦЦЦ(8)
$code = explode(' ', $code);
return array(
'REGIONCODE' => $code[0],
'AREACODE' => $code[2],
'AUTOCODE' => $code[1],
'CITYCODE' => $code[3],
'CTARCODE' => $code[4],
'PLACECODE' => $code[5],
'STREETCODE' => $code[6],
'EXTRCODE' => $code[7],
'SEXTCODE' => $code[8]
);
}
private function checkFitItemByCode($code, $item)
{
$code = $this->parseFiasCode($code);
return (
$item['REGIONCODE'] == $code['REGIONCODE']
&&
$item['AREACODE'] == $code['AREACODE']
&&
$item['AUTOCODE'] == $code['AUTOCODE']
&&
$item['CITYCODE'] == $code['CITYCODE']
&&
$item['CTARCODE'] == $code['CTARCODE']
&&
$item['PLACECODE'] == $code['PLACECODE']
&&
$item['STREETCODE'] == $code['STREETCODE']
&&
$item['EXTRCODE'] == $code['EXTRCODE']
&&
$item['SEXTCODE'] == $code['SEXTCODE']
);
}
*/
private function mapFiasCities()
{
//$this->output($this->data['MAPS']['REGIONS']);
$links = $this->getFias2YamarketRootLinks();
//$this->output($links);
$typesToSearch = array('CITY', 'VILLAGE');
// for each region and city we choose the correpongind ones from fias, saving routes
foreach($links as $id => $fiasSource)
{
$region = $this->data['MAPS']['REGIONS'][$id];
$this->output('FOR region: '.$region);
$this->output($region);
$toBeFound = array(); // among all nodes get only ones with following types
$this->getMainTreeNodesOfType(array($id), $typesToSearch, $toBeFound);
//$this->output(count($toBeFound));
if(!empty($toBeFound)) // search them in fias prepared tree
{
foreach($fiasSource as $fiasId)
{
$this->output('In: '.$fiasId);
$this->walkFiasTreeAndKeepFollowing($fiasId, $toBeFound, $typesToSearch);
}
}
$this->cleanUpFile('fias_yamarket_links', 'region_'.$region['ID']);
foreach($toBeFound as $node)
{
$exactId = '';
$exactName = '';
$exactType = '';
$exactCode = '';
if(!empty($node['MATCH']))
{
$match = array_shift($node['MATCH']);
$exactId = $match['ID'];
$exactName = $match['NAME'];
$exactType = $match['TYPE'];
$item = $this->fiasGetByAOGUID($exactId);
if($item)
{
$exactCode = $item['CODE'];
}
else
$this->output('no record in fias for: '.$exactId);
}
$data = array(
'HZ' => 'libre',
'ID' => $node['ID'],
'NAME' => $node['NAME']['RU']['NAME'],
'AOGUID' => $exactId,
'FNAME' => $exactName,
'FTYPE' => $exactType,
'CODE' => $exactCode
);
for($i = 0; $i < 3; $i++)
{
$data['VAR_AOGUID_'.$i] = '';
$data['VAR_NAME_'.$i] = '';
$data['VAR_TYPE_'.$i] = '';
}
$i = 0;
if(!empty($node['MATCH']))
{
foreach($node['MATCH'] as $item)
{
$data['VAR_AOGUID_'.$i] = $item['ID'];
$data['VAR_NAME_'.$i] = $item['NAME'];
$data['VAR_TYPE_'.$i] = $item['TYPE'];
$i++;
}
}
if(!empty($node['POSSIBLE']))
{
foreach($node['POSSIBLE'] as $item)
{
$data['VAR_AOGUID_'.$i] = $item['ID'];
$data['VAR_NAME_'.$i] = $item['NAME'];
$data['VAR_TYPE_'.$i] = $item['TYPE'];
$i++;
}
}
$this->putToFile2(
$data,
'fias_yamarket_links',
'region_'.$region['ID'],
true
);
}
//break;//tmp
}
}
private function checkAllowedState($node)
{
return $node['ACTSTATUS'] == '1' && $node['LIVESTATUS'] == '1';
}
private function mb_str_replace($needle, $replace_text, $haystack)
{
return implode($replace_text, mb_split($needle, $haystack));
}
private function checkNamesEqual($one, $two)
{
// try trim-lc
$one = $this->makeNameIndexKey($one);
$two = $this->makeNameIndexKey($two);
if($one == $two)
return true;
// try ё => e
$one = $this->mb_str_replace('ё', 'е', $one);
$two = $this->mb_str_replace('ё', 'е', $two);
if($one == $two)
return true;
// try й => и
$one = $this->mb_str_replace('й', 'и', $one);
$two = $this->mb_str_replace('й', 'и', $two);
if($one == $two)
return true;
// there could be also multiple spaces between
//if(!($keptNode['NAME_I'] == $name || strpos($keptNode['NAME_I'], $name) !== false || strpos($name, $keptNode['NAME_I']) !== false))
// continue;
return false;
}
private function checkNamesAlmostEqual($one, $two)
{
$one = $this->makeNameIndexKey($one);
$two = $this->makeNameIndexKey($two);
if(strpos($one, $two) !== false || strpos($two, $one) !== false)
return true;
$one = $this->mb_str_replace('ё', 'е', $one);
$two = $this->mb_str_replace('ё', 'е', $two);
if(strpos($one, $two) !== false || strpos($two, $one) !== false)
return true;
$one = $this->mb_str_replace('й', 'и', $one);
$two = $this->mb_str_replace('й', 'и', $two);
if(strpos($one, $two) !== false || strpos($two, $one) !== false)
return true;
$one = preg_replace('#\s+-\s+#', '-', $one);
$two = preg_replace('#\s+-\s+#', '-', $two);
if(strpos($one, $two) !== false || strpos($two, $one) !== false)
return true;
return false;
}
private function walkFiasTreeAndKeepFollowing($node, &$toBeFound, $typesToSearch)
{
$bundle = $this->getDataFromCSV('fias_tree', $node);
if(is_array($bundle) && !empty($bundle))
{
//$this->output($bundle);
foreach($bundle as $node)
{
$name = $this->makeNameIndexKey($node['NAME']);
//$this->output($node);
// check if we need this
if(strlen($node['TYPE']) && isset($this->sysMaps['FIAS2BASETYPE'][$node['TYPE']]))
{
$type = $this->sysMaps['FIAS2BASETYPE'][$node['TYPE']];
if(in_array($type, $typesToSearch)) // type fits
{
// check if name fits too
foreach($toBeFound as &$keptNode)
{
if($keptNode['TYPE_CODE'] != $type)
continue;
if(!$this->checkAllowedState($node))
continue;
if($this->checkNamesEqual($name, $keptNode['NAME']['RU']['NAME']))
{
$keptNode['MATCH'][$node['AOGUID']] = $node;
}
elseif($this->checkNamesAlmostEqual($name, $keptNode['NAME']['RU']['NAME']))
{
$keptNode['POSSIBLE'][$node['AOGUID']] = $node;
}
}
}
}
$this->walkFiasTreeAndKeepFollowing($node['ID'], $toBeFound, $typesToSearch);
}
}
}
private function getFias2YamarketRootLinks($skipMapped = true, $skipCompiled = false)
{
$res = $this->getDataFromCSV('fias_yamarket_links', 'rootv2');
$result = array();
foreach($res as $reg)
{
if($skipMapped && $reg['CITIES_MAPPED'] == '1')
continue;
if($skipCompiled && $reg['COMPILED'] == '1')
continue;
$fias = array($reg['AOGUID']);
if(strlen($reg['ADDITIONAL']))
{
$variants = explode(', ', $reg['ADDITIONAL']);
foreach($variants as $var)
{
$id = explode(':', $var);
$fias[] = $id[0];
}
}
$result[$reg['YAMARKET']] = $fias;
}
return $result;
}
public function splitFiasOnRegions()
{
$this->cleanPoolDir('fias_tree');
$this->walkFias('fiasGotOneSplit');
}
public function copyFias2DB()
{
$this->fiasDB = new Db\FiasTable();
$this->fiasDB->create();
$this->fiasDB->switchIndexes(false);
$this->fiasDB->deleteAll();
$this->walkFias('fiasGotOneAdd2DB');
$this->fiasDB->doneInsert();
$this->fiasDB->switchIndexes(true);
}
/*
public function dropFiasTreeDuplicates()
{
foreach(new \DirectoryIterator($this->getPoolDirName('fias_tree')) as $file)
{
if($file->isDot() || $file->isDir())
continue;
$csv = $this->getDataFromCSV('fias_tree', str_replace('.csv', '', $file->getFilename()));
$index = array();
foreach($csv as $id => $line)
{
if(isset($index[$line['ID']]))
{
unset($csv[$id]);
continue;
}
$index[$line['ID']] = true;
}
$this->putDataToCSV($csv, 'fias_tree', str_replace('.csv', '', $file->getFilename()));
unset($index);
unset($csv);
}
}
*/
public function fiasGotOneSplit($data)
{
$item = $data['__ATTR'];
//$this->manageFiasPath($item);
//$this->output(str_repeat('-', intval($item['AOLEVEL']) - 1).$item['FORMALNAME']);
//$this->output($this->printCurrentFiasPath());
//$this->test[$item['PARENTGUID']][] = $item['AOGUID'];
$this->putToFile2(
array(
'ID' => $item['AOGUID'],
'ACTSTATUS' => $item['ACTSTATUS'],
'LIVESTATUS' => $item['LIVESTATUS'],
'NAME' => $item['FORMALNAME'],
'TYPE' => $item['SHORTNAME'],
'POSTALCODE' => $item['POSTALCODE']
),
'fias_tree',
strlen($item['PARENTGUID']) ? $item['PARENTGUID'] : 'root',
true
);
}
public function fiasGotOneAdd2DB($data)
{
$item = $data['__ATTR'];
$code = implode(' ', array(
$item['REGIONCODE'],
$item['AUTOCODE'],
$item['AREACODE'],
$item['CITYCODE'],
$item['CTARCODE'],
$item['PLACECODE'],
$item['STREETCODE'],
$item['EXTRCODE'],
$item['SEXTCODE'],
));
// if db works in cp1251
/*
$formalName = \CharsetConverter::ConvertCharset($item['FORMALNAME'], 'UTF-8', SITE_CHARSET);
$nameLC = \CharsetConverter::ConvertCharset($this->makeNameIndexKey($item['FORMALNAME']), 'UTF-8', SITE_CHARSET);
$shortName = \CharsetConverter::ConvertCharset($item['SHORTNAME'], 'UTF-8', SITE_CHARSET);
*/
$formalName = $item['FORMALNAME'];
$nameLC = $this->makeNameIndexKey($item['FORMALNAME']);
$shortName = $item['SHORTNAME'];
$this->fiasDB->insert(array(
'AOGUID' => $item['AOGUID'],
'PARENTGUID' => $item['PARENTGUID'],
'AOID' => $item['AOID'],
'NEXTID' => $item['NEXTID'],
'FORMALNAME' => $formalName,
'SHORTNAME' => $shortName,
'POSTALCODE' => $item['POSTALCODE'],
'ACTSTATUS' => $item['ACTSTATUS'],
'LIVESTATUS' => $item['LIVESTATUS'],
'NAME_LC' => $nameLC,
'CODE' => $code
));
}
private function getByAOID($aoid)
{
$id = explode('-', $aoid);
}
private function printCurrentFiasPath()
{
$path = array();
foreach($this->fiasCPath as $item)
$path[] = $item['NAME'];
return implode('>', $path);
}
private function manageFiasPath($item)
{
$guid = $item['AOGUID'];
$parentGUID = $item['PARENTGUID'];
//$this->truncateCurrentFiasPath($parentGUID);
//$this->fiasCPath[] = array('GUID' => $guid, 'NAME' => $item['FORMALNAME']);
}
private function truncateCurrentFiasPath($guid)
{
foreach($this->fiasCPath as $i => $node)
{
if($node['GUID'] == $guid)
{
array_splice($this->fiasCPath, $i + 1);
return;
}
}
}
#######################################################
### ABOUT FIAS PROCESS ROOT v2
#######################################################
public function mapFiasRootV2()
{
$this->cleanUpFile('fias_yamarket_links', 'rootv2');
$this->walkFias('fiasGotOneMapRootV2');
foreach($this->data['MAPS']['REGIONS'] as $id => $reg)
{
$foundId = '';
$foundName = '';
$additResults = '';
if(count($reg['MATCH']))
{
$foundId = $reg['MATCH'][0]['ID'];
$foundName = $reg['MATCH'][0]['NAME'];
array_shift($reg['MATCH']);
if(count($reg['MATCH']))
{
$additResults = array();
foreach($reg['MATCH'] as $additRes)
$additResults[] = $additRes['ID'].':"'.$additRes['NAME'].'"';
$additResults = implode(', ', $additResults);
}
}
$this->putToFile(
array(
'YAMARKET' => $id,
'YAMARKET_NAME' => $reg['NAME']['RU']['NAME'],
'AOGUID' => $foundId,
'FIAS_NAME' => $foundName,
'ADDITIONAL' => $additResults
),
'fias_yamarket_links',
'rootv2'
);
}
}
public function fiasGotOneMapRootV2($data)
{
$item = $data['__ATTR'];
$type = $item['SHORTNAME'];
$name = $this->makeNameIndexKey($item['FORMALNAME']);
if($this->sysMaps['FIAS2BASETYPE'][$type] == 'REGION') // this is fias-region
{
$result = array();
foreach($this->data['MAPS']['REGIONS'] as $id => &$node)
{
$rName = $this->makeNameIndexKey($node['NAME']['RU']['NAME']);
if($rName == $name || strpos($rName, $name) !== false)
{
$node['MATCH'][] = array(
'ID' => $item['AOGUID'],
'NAME' => $item['FORMALNAME'].' '.$item['SHORTNAME']
);
}
}
}
}
private function readFiasRootMapV2()
{
try
{
$csv = new Import\CSVReader('R', false);
$result = array();
$data = $csv->ReadBlock($this->getPoolFileName('fias_yamarket_links', 'rootv2', false));
foreach($data as $region)
$result[$region['YAMARKET']] = $region;
return $result;
}
catch(\Exception $e)
{
return array();
}
}
private function walkFias($callback, $limit = -1)
{
$sax = new SAXParser(array(
'watch4Tag' => 'Object',
'onEachParseResult' => array($this, $callback),
'limit' => $limit,
'collapseAttr' => true
));
$fd = fopen($_SERVER['DOCUMENT_ROOT'].$this->options['fiasAddrobjFile'], 'r');
while($block = fread($fd, 1024))
{
if(!$sax->putToParser($block))
break;
}
unset($sax);
}
#######################################################
### ABOUT MAIN DATA
#######################################################
private function buildRussiaPathIndex($bundle, $parentPath = array())
{
foreach($bundle as $id)
{
$node = $this->data['TREES']['MAIN']['NODES'][$id];
$name = $this->makeNameIndexKey($node['NAME']['RU']['NAME']);
//regions:
if($node['TYPE_CODE'] == 'REGION')
$this->data['MAPS']['REGIONS'][$id] = $node;
if(isset($this->data['TREES']['MAIN']['EDGES'][$id]))
$this->buildRussiaPathIndex($this->data['TREES']['MAIN']['EDGES'][$id], $ppp);
}
}
private function getMainTreeNodesOfType($bundle, $types = array(), &$buffer)
{
foreach($bundle as $id)
{
$node = $this->data['TREES']['MAIN']['NODES'][$id];
if(in_array($node['TYPE_CODE'], $types))
{
//$node['NAME_I'] = $this->makeNameIndexKey($node['NAME']['RU']['NAME']);
$buffer[$id] = $node;
}
if(isset($this->data['TREES']['MAIN']['EDGES'][$id]))
$this->getMainTreeNodesOfType($this->data['TREES']['MAIN']['EDGES'][$id], $types, $buffer);
}
}
#######################################################
### ABOUT FILE POOL
#######################################################
private function putToFile($data, $poolName, $fileSubname)
{
$dir = $_SERVER['DOCUMENT_ROOT'].$this->workDir.$this->filePools[$poolName]['DIR'];
if(!file_exists($dir))
mkdir($dir, 0755, true);
if(!isset($this->filePoolsp[$poolName][$fileSubname]))
{
$fd = $this->filePoolsp[$poolName][$fileSubname] = fopen($dir.$fileSubname.'.csv', 'w');
$head = implode(';', array_keys($data));
fputs($fd, $head.PHP_EOL);
$this->filePoolsp[$poolName][$fileSubname] = $fd;
}
fputs($this->filePoolsp[$poolName][$fileSubname], implode(';', $data).PHP_EOL);
}
private function putToFile2($data, $poolName, $fileSubname, $checkDir = false)
{
$dir = $_SERVER['DOCUMENT_ROOT'].$this->workDir.$this->filePools[$poolName]['DIR'];
$fName = $dir.$fileSubname.'.csv';
if($checkDir && !file_exists($dir))
mkdir($dir, 0755, true);
if(!file_exists($fName))
file_put_contents($fName, implode(';', array_keys($data)).PHP_EOL, FILE_APPEND);
file_put_contents($fName, implode(';', $data).PHP_EOL, FILE_APPEND);
}
private function cleanUpFile($poolName, $fileSubname)
{
$name = $_SERVER['DOCUMENT_ROOT'].$this->workDir.$this->filePools[$poolName]['DIR'].$fileSubname.'.csv';
if(file_exists($name))
unlink($name);
}
private function getPoolFileName($poolName, $fileSubname, $docRoot = true)
{
return ($docRoot ? $_SERVER['DOCUMENT_ROOT'] : '/').$this->workDir.$this->filePools[$poolName]['DIR'].$fileSubname.'.csv';
}
private function getPoolDirName($poolName, $docRoot = true)
{
return ($docRoot ? $_SERVER['DOCUMENT_ROOT'] : '/').$this->workDir.$this->filePools[$poolName]['DIR'];
}
private function cleanPoolDir($poolName)
{
$dir = $_SERVER['DOCUMENT_ROOT'].$this->workDir.$this->filePools[$poolName]['DIR'];
if(file_exists($dir))
system('rm -rf '.$dir);
mkdir($dir, 0755, true);
}
private function getDataFromCSV($poolName, $fileSubname)
{
try
{
$csv = new Import\CSVReader('R', false);
return $csv->ReadBlock($this->getPoolFileName($poolName, $fileSubname, false));
}
catch(\Exception $e)
{
return array();
}
}
private function putDataToCSV($data, $poolName, $fileSubname)
{
$fName = $this->getPoolFileName($poolName, $fileSubname);
if(file_exists($fName))
{
$header = implode(';', array_keys($data[0])).PHP_EOL;
file_put_contents($fName, $header);
foreach($data as $line)
file_put_contents($fName, implode(';', $line).PHP_EOL, FILE_APPEND);
}
}
#######################################################
### ABOUT COMPILER
#######################################################
private function mapFiasTypeToMain($fiasType)
{
return isset($this->sysMaps['FIAS2BASETYPE'][$fiasType]) ? $this->sysMaps['FIAS2BASETYPE'][$fiasType] : false;
}
private function makeNameIndexKey($name)
{
return trim(mb_strtolower($name, 'UTF-8'));
}
private function makeTypeGroupFile($file = '')
{
$fd = $this->fileOpen(strlen($file) ? $file : self::GROUP_FILE);
fputs($fd, implode(';', $this->headers['GROUP_FILE']).PHP_EOL);
foreach($this->typeGroups as $code => $group)
{
$line = array();
foreach($this->headers['GROUP_FILE'] as $colCode)
$line[] = is_array($group[$colCode]) ? implode(':', $group[$colCode]) : $group[$colCode];
fputs($fd, implode(';', $line).PHP_EOL);
}
fclose($fd);
}
private function makeNext()
{
$next = $this->queueShift();
$bundle = $this->getBundleFromFile($next);
if(!empty($bundle))
{
foreach($bundle as $item)
{
$this->putToGroups($item);
if($item['CHILDREN_COUNT'] > 0)
$this->queue[] = $item['ID'];
}
}
return empty($this->queue);
}
private function queueShift()
{
if($this->queue !== false)
return array_shift($this->queue);
return 'root';
}
private function getBundleFromFile($id)
{
$data = unserialize(file_get_contents($_SERVER['DOCUMENT_ROOT'].$this->grabbedStuffDir.$id));
foreach($data as $k => &$item)
{
if(in_array($item['NAME'], array('Прочее', 'Общероссийские', 'Универсальное', 'Другие города региона')))
{
unset($data[$k]);
continue;
}
//$item['NAME'] = \CharsetConverter::ConvertCharset($item['NAME'], 'UTF-8', SITE_CHARSET); // temp
if(isset($this->typeMap[$item['TYPE_CODE']]))
$item['TYPE_CODE'] = $this->typeMap[$item['TYPE_CODE']];
// type "OTHER" which is a child of type "REGION" is actually a "SUBREGION"
if($item['TYPE_CODE'] == 'OTHER')
{
$parentType = $this->yaIdType[$item['PARENT_ID']];
if($parentType == 'REGION')
$item['TYPE_CODE'] = 'SUBREGION';
}
$code = $this->addLeadingZero($this->codeOffset, $this->leading);
$this->yaIdType[$item['ID']] = $item['TYPE_CODE'];
$this->relations[$item['CODE']] = $item['PARENT_CODE'];
$this->code2type[$item['CODE']] = $item['TYPE_CODE'];
$ruName = $item['NAME'];
//if($this->optionConvertNames)
// $ruName = \CharsetConverter::ConvertCharset($ruName, 'UTF-8', SITE_CHARSET);
$item['NAME'] = array();
$item['NAME']['RU']['NAME'] = $ruName.($this->options['includeYaInfo2Name'] ? ' ('.$item['TYPE_CODE'].', '.$item['ID'].')' : '');
//$item['NAME.EN.NAME'] = '[no-translation]'; // attach translations from old import files
//$item['NAME.UA.NAME'] = '[no-translation]'; // attach translations from old import files
$item['EXT']['YAMARKET'][] = $item['ID'];
//unset($item['ID']);
//unset($item['PARENT_ID']);
}
return $data;
}
private function getParentOfType($code, $types)
{
if(empty($types))
return '';
$nextCode = $code;
$i = -1;
while($nextCode)
{
$i++;
if($i > 50)
throw new Main\SystemException('Recursion gone too deep when trying to find parent of type');
if(isset($types[$this->code2type[$nextCode]]))
return $nextCode;
$nextCode = $this->relations[$nextCode];
}
return '';
}
private function putToGroups($item)
{
foreach($this->typeGroups as $gCode => &$group)
{
//_dump_r('Item '.$item['NAME.RU.NAME'].' ('.$item['TYPE_CODE'].')');
if(!isset($group['I_TYPES'][$item['TYPE_CODE']]))
continue;
//_dump_r('Goes to group: '.$gCode);
$baseParent = $this->getParentOfType($item['CODE'], $this->typeGroups[$group['PARENT']]['I_TYPES']);
//_dump_r('Base parent is: '.$baseParent);
if(!$group['FD'][$baseParent])
{
$fName = str_replace(array(
'%BASE_PARENT_ITEM_CODE%',
'%CODE%'
), array(
$baseParent,
ToLower($gCode)
), $group['FILE_NAME_TEMPLATE']);
$group['FD'][$baseParent] = $this->fileOpen($fName);
fputs($group['FD'][$baseParent], implode(';', $this->headers[$group['HEADER']]).PHP_EOL);
}
$header = $this->headers[$group['HEADER']];
$line = array();
foreach($header as $code)
$line[] = isset($item[$code]) ? $item[$code] : '';
fputs($group['FD'][$baseParent], implode(';', $line).PHP_EOL);
}
}
private function fileOpen($name)
{
return fopen($_SERVER['DOCUMENT_ROOT'].$this->workDir.self::OUTPUT_DIR.$name, 'w');
}
private static function addLeadingZero($value, $length)
{
if(strlen($value) >= $length)
return $value;
$diff = abs($length - strlen($value));
for($i = 0; $i < $diff; $i++)
$value = '0'.$value;
return $value;
}
#######################################################
### ABOUT DATA
#######################################################
private function storeTemporalData($dataCode, $data)
{
$dir = $_SERVER['DOCUMENT_ROOT'].$this->workDir.self::TMP_DATA_DIR;
if(!file_exists($dir))
mkdir($dir, 0755, true);
file_put_contents($dir.$dataCode, serialize($data));
}
private function getStoredTemporalData($dataCode)
{
$file = $_SERVER['DOCUMENT_ROOT'].$this->workDir.self::TMP_DATA_DIR.$dataCode;
if(is_readable($file))
return unserialize(file_get_contents($file));
else
return array();
}
private function cleanTemporalData($dataCode)
{
$file = $_SERVER['DOCUMENT_ROOT'].$this->workDir.self::TMP_DATA_DIR.$dataCode;
if(is_readable($file))
unlink($file);
}
/*
private function dropTemporalFile()
{
$file = $_SERVER['DOCUMENT_ROOT'].$this->workDir.self::TMP_DATA_FILE;
if(is_readable($file))
unlink($file);
}
*/
public function cleanOutput()
{
$file = $_SERVER['DOCUMENT_ROOT'].$this->workDir.self::OUTPUT_FILE;
if(is_readable($file))
unlink($file);
}
public function output($data, $important = true)
{
if(!$important)
return false;
ob_start();
print_r($data);
$data = ob_get_contents();
ob_end_clean();
file_put_contents($_SERVER['DOCUMENT_ROOT'].$this->workDir.self::OUTPUT_FILE, $data.PHP_EOL, FILE_APPEND);
}
}