function executeProcess(array $argv) { $CLASS_PATTERN = file_get_contents(file_path(__DIR__, 'class.txt')); $METHOD_PATTERN = file_get_contents(file_path(__DIR__, 'method.txt')); /* * Название тестового файла. * Для проверки мы сначала удалим класс для него, если он был, потом проверим, что за класс был сгенерирован. */ $TEST_MESSAGES_FILE = 'ExampleSdkProcessMessages'; //Убедимся, что тестовый .msgs существует и удалим тестовый .php файл $TEST_PHP_DI = DirItem::inst(__DIR__ . '/classes', $TEST_MESSAGES_FILE, PsConst::EXT_PHP)->remove(); $TEST_MSGS_DI = DirItem::inst(__DIR__ . '/classes', $TEST_MESSAGES_FILE, PsConst::EXT_MSGS); check_condition($TEST_MSGS_DI->isFile(), "File {$TEST_MSGS_DI->getAbsPath()} must exists"); dolog('Loading all files, ended with Messages.msgs'); //TODO - после нужно получать эту информацию из какого-нибудь места $exceptDirs[] = DirManager::autogen()->relDirPath(); $exceptDirs[] = DirManager::resources()->relDirPath(); $exceptDirs[] = DirManager::stuff()->relDirPath(); //$exceptDirs = array(); $items = DirManager::inst()->getDirContentFull(null, function (DirItem $di) { dolog($di->getAbsPath()); return $di->isFile() && ends_with($di->getName(), 'Messages.msgs'); }, $exceptDirs); dolog('Message files for processing: {}', count($items)); //Проверим, что был выбран тестовый файл check_condition(in_array($TEST_MSGS_DI, $items, true), "Test file [{$TEST_MESSAGES_FILE}] is not included"); //Удалим его из массива... array_remove_value($items, $TEST_MSGS_DI, true); //И поместим наверх, чтобы он был обработан первым array_unshift($items, $TEST_MSGS_DI); /* @var $msgsDi DirItem */ foreach ($items as $msgsDi) { LOGBOX('PROCESSING [{}]', $msgsDi->getAbsPath()); //Сбросим методы $METHODS = array(); //Извлечём название класса $CLASS = $msgsDi->getNameNoExt(); //DirItem файла с сообщениями php $classDi = DirItem::inst($msgsDi->getDirname(), $CLASS, PsConst::EXT_PHP); //Получаем сообщения из файла .msgs $messages = $msgsDi->getFileAsProps(); foreach ($messages as $MSG_KEY => $MGG_VALUE) { dolog(' >> {}={}', $MSG_KEY, $MGG_VALUE); //Получим список всех параметров из макросов ({0}, {1}, {2} и т.д.) preg_match_all("/\\{(.+?)\\}/", $MGG_VALUE, $args); $args = array_values(array_unique($args[1])); sort($args, SORT_NUMERIC); $ARGS = array(); for ($index = 0; $index < count($args); $index++) { $arg = $args[$index]; $lineDescr = PsStrings::replaceWithBraced('[{}] in line [{}={}]', $msgsDi->getRelPath(), $MSG_KEY, $MGG_VALUE); check_condition(is_inumeric($arg), "Invalid argument [{$arg}] for {$lineDescr}"); check_condition($index == $args[$index], "Missing index [{$index}] for {$lineDescr}"); $ARGS[] = '$p' . $index; } $ARGS = join(', ', $ARGS); //Добавляем метод dolog(" A: {}::{} ({})", $CLASS, $MSG_KEY, $ARGS); $PARAMS['SUPPORT_CLASS'] = PsMsgs::getClass(); $PARAMS['MESSAGE'] = $MGG_VALUE; $PARAMS['FUNCTION'] = $MSG_KEY; $PARAMS['ARGS'] = $ARGS; $METHODS[] = PsStrings::replaceMapBracedKeys($METHOD_PATTERN, $PARAMS); } dolog('Made methods: ({})', count($METHODS)); if ($METHODS) { $PARAMS['FILE'] = $msgsDi->getAbsPath(); $PARAMS['CLASS'] = $CLASS; $PARAMS['DATE'] = date(DF_PS); $PARAMS['METHODS'] = "\n" . join("\n\n", $METHODS) . "\n"; $CLASS_PHP = PsStrings::replaceMapBracedKeys($CLASS_PATTERN, $PARAMS); $classDi->putToFile($CLASS_PHP); } /* * Если обрабатываем тестовый файл - проверим его */ //TEST CLASS VALIDATION START >>> if ($msgsDi->equals($TEST_MSGS_DI)) { dolog(''); dolog('Validating test class {}', $TEST_MESSAGES_FILE); //Проверим, что .php был сгенерирован check_condition($TEST_PHP_DI->isFile(), "File {$TEST_PHP_DI->getAbsPath()} was not created!"); //Проверим, что для каждого сообщения был создан метод $methods = PsUtil::newReflectionClass($TEST_MESSAGES_FILE)->getMethods(); $messages = $TEST_MSGS_DI->getFileAsProps(); check_condition(count($methods) == count($messages), 'Methods count missmatch, check ' . $TEST_PHP_DI->getAbsPath()); /* @var $method ReflectionMethod */ foreach ($methods as $method) { check_condition(array_key_exists($method->getName(), $messages), "No method {$TEST_MESSAGES_FILE}::" . $method->getName()); } //Проверим, что возвращают методы тестового сгенерированного класса function doTest($className, $methodName, array $params, $expected) { $method = "{$className}::{$methodName}"; $actual = call_user_func_array($method, $params); dolog("{}({})='{}', Expected='{}'", $method, join(', ', $params), $actual, $expected); check_condition($actual == $expected, "{$actual} != {$expected}"); } doTest($TEST_MESSAGES_FILE, 'message1', array(), 'Message 1'); doTest($TEST_MESSAGES_FILE, 'message2', array('a', 'b', 'c'), 'Parametred a,c,b'); dolog('Test class is valid!'); } //TEST CLASS VALIDATION END <<< } //# DirItems validation end }
function executeProcess(array $argv) { PsConnectionPool::assertDisconnectied(); /* * СОЗДАЁМ SQL * * Нам нужны настройки таблиц, которые неоткуда взять, кроме как из базы, поэтому для экспорта данных нужна БД. * Все данные из "редактируемых" таблиц также загружаются из этой БД. */ $DB = DirManager::inst(__DIR__ . '/temp'); $SDK = DirManager::inst(__DIR__ . '/temp/sdk'); //Почистим файлы для удаления dolog('Clearing not .sql/.txt from temp dir'); /* @var $item DirItem */ foreach ($DB->getDirContentFull(null, DirItemFilter::FILES) as $item) { if (!$item->checkExtension(array(PsConst::EXT_TXT, PsConst::EXT_SQL))) { dolog('[-] {}', $item->remove()->getRelPath()); } } dolog(); /* * SDK */ //dolog('Processing objects.sql'); /* @var $DIR DirManager */ foreach (array(ENTITY_SCOPE_SDK => $SDK, ENTITY_SCOPE_PROJ => $DB) as $scope => $DM) { dolog(); dolog('***************************************************************'); dolog('>>> Processing scope [{}], dir: [{}]', $scope, $DM->absDirPath()); $SCHEMA = $DM->getDirItem(null, 'schema.sql'); if (!$SCHEMA->isFile()) { dolog('schema.sql is not exists, skipping'); continue; //--- } $DM_SYSOBJECTS = DirManager::inst($DM->absDirPath(), 'sysobjects'); /* * Очищаем папку, в которой будет содержимое для автосгенерированных файлов */ $DM_AUTO = DirManager::inst($DM_SYSOBJECTS->absDirPath(), 'auto')->clearDir(); /* * Создадим ссылку на файл с данными, выгруженными из таблиц */ $DI_AUTO_DATA = $DM_AUTO->getDirItem(null, 'data.sql'); /* * Сначала сделаем триггеры на таблицы, от которых зависит кеш и к которым привязаны фолдинги. */ LOGBOX_INIT(); LOGBOX('Making cache and folding table triggers'); $DM_AUTO_TRIGGERS = $DM_AUTO->getDirItem('triggers')->makePath(); $DI_AUTO_TRIGGERS_SQL = $DM_AUTO->getDirItem(null, 'triggers', 'sql')->getSqlFileBuilder(); $triggerPattern = $SDK->getDirItem('sysobjects/patterns', 'ta_iud_pattern.sql')->getFileContents(); //BUILDIAN AND ADDING TRIGGERS foreach (PsTriggersAware::getTriggeredTables($scope) as $table) { foreach (PsTriggersAware::getActions() as $action) { $actions = PsTriggersAware::getTriggerActions($table, $scope, $action); if (empty($actions)) { continue; //--- } $name = 'ta' . strtolower(first_char($action)) . '_' . $table; $trigger = str_replace('<%NAME%>', $name, $triggerPattern); $trigger = str_replace('<%TABLE%>', $table, $trigger); $trigger = str_replace('<%ACTION%>', $action, $trigger); $trigger = str_replace('<%CALL%>', implode("\n", $actions), $trigger); dolog("+ {$name}"); foreach ($actions as $_action) { dolog($_action); } $DI_AUTO_TRIGGERS_SQL->appendFile($DM_AUTO_TRIGGERS->getDirItem(null, $name, 'sql')->putToFile($trigger)); } } //Все автоматически сгенерированные триггеры положим в отдельный файл $DI_AUTO_TRIGGERS_SQL->save(); $autoTriggers = DirManager::inst($DM_AUTO_TRIGGERS->getAbsPath())->getDirContent(null, PsConst::EXT_SQL); dolog('Triggers made: {}', count($autoTriggers)); /* * objects.sql */ $OBJECTS_SQL = $DM_AUTO->getDirItem(null, 'objects.sql')->getSqlFileBuilder(); /* * Добавляем автосгенерированные триггеры */ LOGBOX('Processing objects.sql'); if (empty($autoTriggers)) { dolog('No auto triggers'); } else { dolog('Adding {} auto triggers', count($autoTriggers)); $OBJECTS_SQL->appendMlComment('AUTO TRIGGERS SECTION'); /* @var $triggerDi DirItem */ foreach ($autoTriggers as $triggerDi) { dolog('+ {}', $triggerDi->getName()); $OBJECTS_SQL->appendFile($triggerDi); } } /* * Получаем строки с включениями */ $ALL = $DM_SYSOBJECTS->getDirItem(null, 'all.txt')->getFileLines(false); if (empty($ALL)) { dolog('No includes'); } else { dolog('Adding {} includes from all.txt', count($ALL)); $OBJECTS_SQL->appendMlComment('INCLUDES SECTION'); foreach ($ALL as $include) { dolog('+ {}', $include); $OBJECTS_SQL->appendFile($DM_SYSOBJECTS->getDirItem($include)); } } $OBJECTS_SQL->save(); /* * Создаём скрипты инициализации для схем */ foreach (PsConnectionParams::getDefaultConnectionNames() as $connection) { if (PsConnectionParams::has($connection, $scope)) { $props = PsConnectionParams::get($connection, $scope); $database = $props->database(); if (empty($database)) { continue; //Не задана БД - пропускаем (для root) } LOGBOX('Making schema script for {}', $props); $SCHEMA_SQL = $DM_AUTO->getDirItem('schemas', $database, 'sql')->makePath()->getSqlFileBuilder(); //DROP+USE $SCHEMA_SQL->clean(); $SCHEMA_SQL->appendLine("DROP DATABASE IF EXISTS {$database};"); $SCHEMA_SQL->appendLine("CREATE DATABASE {$database} CHARACTER SET utf8 COLLATE utf8_general_ci;"); $SCHEMA_SQL->appendLine("USE {$database};"); if ($scope == ENTITY_SCOPE_PROJ) { dolog('+ SDK PART'); //Добавим секцию в лог $SCHEMA_SQL->appendMlComment('>>> SDK'); //CREATE CHEMA SCRIPT $SCHEMA_SQL->appendFile($SDK->getDirItem(null, 'schema.sql')); //OBJECTS SCRIPT $SCHEMA_SQL->appendFile($SDK->getDirItem('sysobjects/auto', 'objects.sql')); //Добавим секцию в лог $SCHEMA_SQL->appendMlComment('<<< SDK'); } //CREATE CHEMA SCRIPT $SCHEMA_SQL->appendFile($SCHEMA); //OBJECTS SCRIPT $SCHEMA_SQL->appendFile($OBJECTS_SQL->getDi()); //CREATE USER $grant = "grant all on {}.* to '{}'@'{}' identified by '{}';"; $SCHEMA_SQL->appendMlComment('Grants'); $SCHEMA_SQL->appendLine(PsStrings::replaceWithBraced($grant, $database, $props->user(), $props->host(), $props->password())); /* * Мы должны создать тестовую схему, чтобы убедиться, что всё хорошо и сконфигурировать db.ini */ if ($connection == PsConnectionParams::CONN_TEST) { dolog('Making physical schema {}', $props); $rootProps = PsConnectionParams::get(PsConnectionParams::CONN_ROOT); dolog('Root connection props: {}', $rootProps); $rootProps->execureShell($SCHEMA_SQL->getDi()); dolog('Connecting to [{}]', $props); PsConnectionPool::configure($props); $tables = PsTable::all(); /* * Нам нужно определить новый список таблиц SDK, чтобы по ним * провести валидацию новых db.ini. * * Если мы обрабатываем проект, то SDK-шный db.ini уже готов и * можем положиться на него. Если мы подготавливаем SDK-шный db.ini, * но новый список таблиц возмём из развёрнутой тестовой БД. */ $sdkTableNames = $scope == ENTITY_SCOPE_SDK ? array_keys($tables) : DbIni::getSdkTables(); if ($scope == ENTITY_SCOPE_PROJ) { //Уберём из всех таблиц - SDK`шные array_remove_keys($tables, $sdkTableNames); } $scopeTableNames = array_keys($tables); sort($scopeTableNames); /* * Составим список таблиц. * Он нам особенно не нужен, но всёже будем его формировать для наглядности - какие таблицы добавились. */ $tablesDi = $DM_AUTO->getDirItem(null, 'tables.txt')->putToFile(implode("\n", $scopeTableNames)); dolog('Tables: {} saved to {}', print_r($scopeTableNames, true), $tablesDi->getAbsPath()); /* * Загружаем полный список таблиц схемы и на основе имеющихся db.ini файлов строим новые, добавляя/удаляя * таблицы, добавленные/удалённые из схемы. */ $dbIniProps = PsDbIniHelper::makeDbIniForSchema($scope, $tables); dolog('db.ini props: {}', print_r($dbIniProps, true)); $dbIniErrors = PsDbIniHelper::validateAndSaveDbIniTableProps($scope, $dbIniProps, $sdkTableNames); if ($dbIniErrors) { PsUtil::raise('db.ini errors for {}: {}', $scope, print_r($dbIniErrors, true)); } /* * Для проекта выгружаем данные, хранящиеся в файлах */ if ($scope == ENTITY_SCOPE_PROJ) { dolog('Exporting tables data from files'); $DM_AUTO->getDirItem('data')->makePath(); $AUTO_DATA_SQL = $DI_AUTO_DATA->touch()->getSqlFileBuilder(); //Пробегаемся по таблицам foreach (DbIni::getTables() as $tableName) { $table = PsTable::inst($tableName); if ($table->isFilesync()) { $fileData = $table->exportFileAsInsertsSql(); if ($fileData) { dolog(' + {}', $tableName); $AUTO_DATA_SQL->appendFile($DM_AUTO->getDirItem('data', $tableName, 'sql')->putToFile($fileData)); } else { dolog(' - {}', $tableName); } } } $AUTO_DATA_SQL->save(); /* * Вставим данные в тестовую схему */ dolog('Inserting data to test schema.'); $props->execureShell($DI_AUTO_DATA); } /* * Теперь ещё создадим тестовые объекты. * Мы уверены, что для SDK тестовая часть есть всегда. */ $TEST_SCHEMA_SQL = $DM_AUTO->getDirItem('test', 'schema', 'sql')->makePath()->getSqlFileBuilder(); if ($scope == ENTITY_SCOPE_PROJ) { dolog('+ SDK TEST PART'); //Добавим секцию в лог $TEST_SCHEMA_SQL->appendMlComment('>>> SDK'); //CREATE CHEMA SCRIPT $TEST_SCHEMA_SQL->appendFile($SDK->getDirItem('sysobjects/auto/test', 'schema.sql')); //Добавим секцию в лог $TEST_SCHEMA_SQL->appendMlComment('<<< SDK'); } $TEST_SCHEMA_SQL->appendFile($DM_SYSOBJECTS->getDirItem('test', 'schema.sql'), false); $TEST_SCHEMA_SQL->appendFile($DM_SYSOBJECTS->getDirItem('test', 'data.sql'), false); $TEST_SCHEMA_SQL->save(); /* * На тестовой схеме прогоняем скрипты с тестовыми данными */ dolog('Making test schema objects.'); $props->execureShell($TEST_SCHEMA_SQL->getDi()); } #end conn== TEST /* * Если были сгенерированы данные из файлов - добавляем их */ if ($DI_AUTO_DATA->isFile() && $DI_AUTO_DATA->getSize() > 0) { dolog('Append data inserts to {}', $SCHEMA_SQL->getDi()->getName()); $SCHEMA_SQL->appendFile($DI_AUTO_DATA); } //SAVE .sql $SCHEMA_SQL->save(); } } } dolog('Database schemas successfully exported'); }
*/ LOGBOX('Set consts'); $props = DirItem::inst(__DIR__, 'consts.txt')->getFileAsProps(); dolog(print_r($props, true)); PsGlobals::inst()->updateProps($props); /* * УДАЛИМ ТЕСТОВЫЕ ДИРЕКТОРИИ */ LOGBOX('Remove test dirs'); $dirs = DirManager::inst()->getDirContentFull(null, DirItemFilter::DIRS); $testDirNames = array('temp', 'orig', '4use', 'tests', 'testcase'); $testDirStartsWith = array('!'); /* @var $dir DirItem */ foreach ($dirs as $dir) { if (in_array($dir->getName(), $testDirNames) || starts_with($dir->getName(), $testDirStartsWith)) { $path = $dir->getAbsPath(); dolog('Removing: ' . $path); DirManager::inst($path)->clearDir(null, true); } } /* * УДАЛИМ АРХИВЫ */ LOGBOX('Remove archivs'); $archivs = DirManager::inst()->getDirContentFull(null, DirItemFilter::ARCHIVES); /* @var $dir DirItem */ foreach ($archivs as $arc) { dolog('Removing: ' . $arc->getAbsPath()); $arc->remove(); } dolog("\nFile actions successfully finished\n");