public static function valueOf($name) { if (in_array($name, self::names())) { return static::$name(); } PsUtil::raise('Enum {} not contains value {}', get_called_class(), $name); }
/** * Метод возвращает экземпляр класса-хранилища маппингов. * Может быть переопределён в config.ini */ private static final function inst() { if (isset(self::$inst)) { return self::$inst; //---- } /* * Получим название класса */ $class = ConfigIni::mappingStorage(); /* * Класс совпадает с базовым? */ if (__CLASS__ == $class) { return self::$inst = new MappingStorage(); } /* * Нам передан класс, который отличается от SDK */ $classPath = Autoload::inst()->getClassPath($class); if (!PsCheck::isNotEmptyString($classPath)) { return PsUtil::raise('Не удалось найти класс хранилища маппингов [{}]', $class); } /* * Указанный класс должен быть наследником данного */ if (!PsUtil::isInstanceOf($class, __CLASS__)) { return PsUtil::raise('Указанное хранилище маппингов [{}] не является наследником класса [{}]', $class, __CLASS__); } return self::$inst = new $class(); }
/** * Метод вызывается для инициализации окружения: * 1. Директория ресурсов окружения будет подключена в Autoload * 2. Файл, включающий окружение, будет выполнен */ public static function init() { if (self::$inited) { return; //--- } self::$inited = true; //--- /* * Проверим, нужно ли подключать окружение */ if (self::isSkipInclude()) { return; //--- } $env = self::env(); if (!$env) { return; //--- } $envDir = array_get_value($env, ConfigIni::environments()); if (!$envDir) { return PsUtil::raise('Environment [{}] not found', $env); } if (!is_dir($envDir)) { return PsUtil::raise('Environment dir for [{}] not found', $env); } $envSrcDir = next_level_dir($envDir, DirManager::DIR_SRC); $envIncFile = file_path($envDir, $env, PsConst::EXT_PHP); if (!is_file($envIncFile)) { return PsUtil::raise('Environment include file for [{}] not found', $env); } $LOGGER = PsLogger::inst(__CLASS__); if ($LOGGER->isEnabled()) { $LOGGER->info('Including \'{}\' environment for context \'{}\'', $env, PsContext::describe()); $LOGGER->info('Env dir: {}', $envDir); $LOGGER->info('Src dir: {}', $envSrcDir); $LOGGER->info('Inc file: {}', $envIncFile); } //Проинициализировано окружение self::$included = true; //Регистрируем директорию с классами, специфичными только для данного окружения Autoload::inst()->registerBaseDir($envSrcDir, false); //Выполним необходимое действие $PROFILER = PsProfiler::inst(__CLASS__); try { $LOGGER->info('{'); $PROFILER->start($env); self::initImpl($LOGGER, $envIncFile); $secundomer = $PROFILER->stop(); $LOGGER->info('}'); $LOGGER->info('Inc file included for {} sec', $secundomer->getTime()); } catch (Exception $ex) { $PROFILER->stop(false); $LOGGER->info('Inc file execution error: [{}]', $ex->getMessage()); throw $ex; //--- } }
public function __construct(array $data) { /* * Инициализируем поля */ parent::__construct($data); /* * Определим тип поля ($coltype) */ switch ($this->getDataType()) { //ЧИСЛОВЫЕ case 'tinyint': if (starts_with($this->getName(), 'b_')) { $this->coltype = self::TYPE_BIT; break; } case 'int': if (starts_with($this->getName(), 'dt_')) { $this->coltype = self::TYPE_INT_DATE; break; } $this->coltype = self::TYPE_INT; break; //ТЕКСТОВЫЕ //ТЕКСТОВЫЕ case 'char': if ($this->getCharMaxlen() == 1) { $this->coltype = self::TYPE_CHAR; break; } case 'varchar': if ($this->getCharMaxlen() <= 255) { if (starts_with($this->getName(), 'dt_')) { $this->coltype = self::TYPE_STRING_DATE; } else { $this->coltype = self::TYPE_STRING; } break; } case 'text': $this->coltype = self::TYPE_TEXT; break; default: PsUtil::raise('Неизвестный тип данных для столбца {}.{}: {}.', $this->getTableName(), $this->getName(), $this->getDataType()); break; } }
public static function format($__CLASS__, $__FUNCTION__, array $arguments) { if (!array_key_exists($__CLASS__, self::$MESSAGES)) { /* * Защита от зацикливания */ self::$MESSAGES[$__CLASS__] = null; /* * Определим, где расположен класс с сообщениями */ $classPath = Autoload::inst()->getClassPath($__CLASS__); if (!$classPath) { return PsUtil::raise('Группа сообщений {} не зарегистрирована', $__CLASS__); } /* * Получим DirItem сообщений для этого класса */ $messagesDi = DirItem::inst(dirname($classPath), $__CLASS__, PsConst::EXT_MSGS); if (!$messagesDi->isFile()) { return PsUtil::raise('Файл с сообщениями {} не существует', $messagesDi->getName()); } /* * Распарсим сообщения из файла */ self::$MESSAGES[$__CLASS__] = $messagesDi->getFileAsProps(); } /* * Проверим на зацикливание */ if (self::$MESSAGES[$__CLASS__] === null) { PsUtil::raise('Зацикливание при попытке получить сообещние {}::{}', $__CLASS__, $__FUNCTION__); } /* * Проверим на существование самого сообщения */ if (!array_key_exists($__FUNCTION__, self::$MESSAGES[$__CLASS__])) { return PsUtil::raise('Сообщение {}::{} не существует', $__CLASS__, $__FUNCTION__); } /* * Заменим макросы {} и вернём сообщение */ return PsStrings::replaceMapBracedKeys(self::$MESSAGES[$__CLASS__][$__FUNCTION__], $arguments); }
/** * Метод предназначен для загрузки единичной записи. Если извлекается более одной записи - * выбразывается исключение. * * $ensureHasOne: * true - если не найдена единственная запись, выкидывает ошибку * false - если не найдена единственная запись, метод возвращает null */ public static function getRec($query, $inputarr = false, $ensureHasOne = false) { $rs = self::executeQuery($query, $inputarr, $queryFinal, $paramsFinal); $rs->Close(); switch ($rs->RecordCount()) { case 0: if ($ensureHasOne) { throw new DBException('No data found', DBException::ERROR_NO_DATA_FOUND, $queryFinal, $paramsFinal); } return null; //--- //--- case 1: return $rs->fields; //--- //--- default: throw new DBException('Too many rows', DBException::ERROR_TOO_MANY_ROWS, $queryFinal, $paramsFinal); } PsUtil::raise('Unexpected recs count requrned: {}', $rs->RecordCount()); }
/** * Метод возвращает экземпляр класса-хранилища экземпляров фолдинов. * Для переопределения этого класса, на уровне проектного config.ini * должен быть задан другой класс. * * @return FoldedStorageInsts */ protected static final function inst() { if (isset(self::$inst)) { return self::$inst; //---- } /* * Получим название класса */ $class = FoldingsIni::foldingsStore(); /* * Класс совпадает с базовым */ if (__CLASS__ == $class) { return self::$inst = new FoldedStorageInsts(); } /* * Нам передан класс, который отличается от SDK */ $classPath = Autoload::inst()->getClassPath($class); if (!PsCheck::isNotEmptyString($classPath)) { return PsUtil::raise('Не удалось найти класс регистрации экземпляров фолдингов [{}]', $class); } /* * Указанный класс должен быть наследником данного */ if (!PsUtil::isInstanceOf($class, __CLASS__)) { return PsUtil::raise('Указанный класс регистрации экземпляров фолдингов [{}] не является наследником класса [{}]', $class, __CLASS__); } return self::$inst = new $class(); }
/** * Метод возвращает экземпляр класса-плагина Smarty. * Для переопределения этого класса, на уровне проектного config.ini * должен быть задан другой класс. * * Это позволит использовать стандартизованный метод подключения плагинов */ public static final function inst() { if (isset(self::$inst)) { return self::$inst; //---- } /* * Получим название класса */ $class = ConfigIni::smartyPlugin(); /* * Класс подключения библиотек совпадает с базовым */ if (__CLASS__ == $class) { return self::$inst = new PSSmartyPlugin(); } /* * Нам передан класс, который отличается от SDK */ $classPath = Autoload::inst()->getClassPath($class); if (!PsCheck::isNotEmptyString($classPath)) { return PsUtil::raise('Не удалось найти класс плагинов Smarty [{}]', $class); } /* * Указанный класс должен быть наследником данного */ if (!PsUtil::isInstanceOf($class, __CLASS__)) { return PsUtil::raise('Указанный плагин Smarty [{}] не является наследником класса [{}]', $class, __CLASS__); } return self::$inst = new $class(); }
<?php /* * wordpress - Классы окружения, когда ps-sdk работает, как wordpress plugin. * Нужно учитывать, что ps-sdk может быть вызван после подключения классов * wordpress (например при построении страницы, когда подключаются плагины) или до этого */ if (PsUtil::isWordPress()) { /* * Мы уже работаем как часть WordPress, ничего делать не нужно. * Классы src подключатся автоматически. */ $LOGGER->info('WordPress is already loaded, skip including...'); //Нужно подключить данный класс, так как он подключается после пагинов //Код подключения находится в файле /wp-settings.php require_once ABSPATH . WPINC . '/pluggable.php'; } else { /* * Нас вызвали раньше wordpress. Это может быть процесс, или ajax, или ещё что-либо. * Необходимо проанализировать контекст выполнения, нужно ли подключить ядро. */ $wpInc = PATH_BASE_DIR . 'wp-load.php'; $LOGGER->info('WordPress is not loaded yet, include wp core \'{}\'', $wpInc); if (is_file($wpInc)) { require_once $wpInc; } else { PsUtil::raise('WordPress core file not found, environment cannot be loaded.'); } } //Установим специальный провайдер безопасности PsSecurity::set(new PsSecurityProviderWp());
/** * Загрузка конкретной настройки */ public static function getProp($group, $prop, $mandatory = true, $scope = ENTITY_SCOPE_ALL) { if (self::hasProp($group, $prop, $scope)) { return self::getGroup($group, true, $scope)[$prop]; } if ($mandatory) { PsUtil::raise('Required config property [{}/{}] not found in {} [{}]', $group, $prop, static::getConfigName(), $scope); } return null; //-- }
public function registerContents($contents) { $this->getEntitys(); $contents = to_array($contents); foreach ($contents as $entity) { if (is_array($entity)) { $this->registerContents($entity); continue; } if (!is_object($entity)) { continue; } if (!method_exists($entity, 'getId') || !method_exists($entity, 'getIdent')) { return PsUtil::raise('Контент сущности {} не имеет методов getId и getIdent', $this->entityTitle()); } $id = $entity->getId(); $this->assertExistsWithId($id); $this->ENTITYS[$id] = $entity; $this->CONTENTS[$id] = true; } }
/** * Проверка состояния * * @param int $state - одно из состояний */ private function checkState($state) { if ($state !== $this->STATE) { PsUtil::raise('Invalid state of {}. Current state: {}. Expected: {}.', __CLASS__, PsUtil::getClassConstByValue(__CLASS__, 'STATE_', $this->STATE), PsUtil::getClassConstByValue(__CLASS__, 'STATE_', $state)); } }
/** * Извлекает тип и подтип фолдинга из его идентификатора: * [lib-p] => [lib, p] */ public static function extractFoldedTypeAndSubtype($foldedUnique, &$type, &$subtype) { $tokens = explode('-', PsCheck::notEmptyString($foldedUnique), 3); $tokensCnt = count($tokens); switch ($tokensCnt) { case 1: $type = PsCheck::notEmptyString($tokens[0]); $subtype = ''; break; case 2: $type = PsCheck::notEmptyString($tokens[0]); $subtype = PsCheck::notEmptyString($tokens[1]); break; default: PsUtil::raise('Invalid folded resource ident: [{}]', $foldedUnique); } }
public function assertExtension($ext) { if (PsCheck::notEmptyString($ext) !== $this->getExtension()) { PsUtil::raise('File with extention [.{}] is expected', $ext); } }
/** * Метод получения коннекта к БД * * @return ADOConnection */ protected final function getConnection() { if ($this->CONNECTION != null) { return $this->CONNECTION; //--- } if (!$this->isConfigured()) { PsUtil::raise('Cannot get DB connection, {} is not configured.', get_called_class()); } $this->LOGGER->info(); $this->LOGGER->info('? Connection for [{}] is requested', $this->CONNECTION_PARAMS); $URL = $this->CONNECTION_PARAMS->url(); //Посмотрим, есть ли у нас нужный коннект if (array_key_exists($URL, $this->CONNECTIONS)) { $this->LOGGER->info('< Fast returned from cache'); return $this->CONNECTION = $this->CONNECTIONS[$URL]; } //Отлогируем $this->LOGGER->info('+ Establishing connection {}', $this->CONNECTION_PARAMS); //Подключаем adodb PsLibs::inst()->AdoDb(); //Подключаемся $this->CONNECTION = ADONewConnection($URL); if (!is_object($this->CONNECTION)) { PsUtil::raise("Unable to connect to [{}]", $this->CONNECTION_PARAMS); } //Зададим некоторые настройки $this->CONNECTION->debug = ADODB_DEBUG; $this->CONNECTION->SetFetchMode(ADODB_FETCH_ASSOC); $this->CONNECTION->query("SET NAMES 'utf8'"); $this->CONNECTION->query("SET CHARACTER SET 'utf8'"); //Положим соединение в пул if (array_key_exists($URL, $this->CONNECTIONS)) { raise_error('Double trying to register db connection'); } $this->LOGGER->info('< Established connection returned'); return $this->CONNECTIONS[$URL] = $this->CONNECTION; }
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'); }
/** * Метод возвращает экземпляр класса, подключающего библиотеки. * Для переопределения этого класса, на уровне проектного config.ini * должен быть задан другой класс, отвечающий за подключение библиотек. * * Это позволит: * 1. Использовать стандартизованный метод подключения внешних библиотек * 2. Переопределить подключение библиотек из SDK */ public static final function inst() { if (isset(self::$inst)) { return self::$inst; //---- } /* * Получим название класса, отвечающего за подключение библиотек */ $class = ConfigIni::libsIncluder(); /* * Подготовим директории */ $SDK_LIB_DIR = DirManager::inst(PS_DIR_INCLUDES, DirManager::DIR_LIB)->absDirPath(); $PROJ_LIB_DIR = DirManager::inst(PS_DIR_ADDON, DirManager::DIR_LIB)->absDirPath(); /* * Класс подключения библиотек совпадает с базовым */ if (__CLASS__ == $class) { self::$inst = new PsLibs(); self::$inst->SDK_LIB_DIR = $SDK_LIB_DIR; self::$inst->LOGGER = PsLogger::inst($class); self::$inst->LOGGER->info('Libs includer SDK: [{}]', __FILE__); self::$inst->LOGGER->info('Libs directory SDK: [{}]', $SDK_LIB_DIR); return self::$inst; //--- } /* * Нам передан класс, который отличается от SDK */ $classPath = Autoload::inst()->getClassPath($class); if (!PsCheck::isNotEmptyString($classPath)) { return PsUtil::raise('Не удалось найти класс загрузчика библиотек [{}]', $class); } /* * Указанный класс должен быть наследником данного */ if (!PsUtil::isInstanceOf($class, __CLASS__)) { return PsUtil::raise('Указанный загрузчик библиотек [{}] не является наследником класса [{}]', $class, __CLASS__); } self::$inst = new $class(); self::$inst->SDK_LIB_DIR = $SDK_LIB_DIR; self::$inst->PROJ_LIB_DIR = $PROJ_LIB_DIR; self::$inst->LOGGER = PsLogger::inst($class); self::$inst->LOGGER->info('Libs includer CUSTOM: [{}]', $classPath); self::$inst->LOGGER->info('Libs directory SDK: [{}]', $SDK_LIB_DIR); self::$inst->LOGGER->info('Libs directory CUSTOM: [{}]', $PROJ_LIB_DIR); return self::$inst; //--- }
public function fetchResult(array $ROWS) { switch ($this->fetchType) { /* * Фетчим в массив */ case self::FETCH_TYPE_ARRAY: $idxCol = $this->idxCol; $result = array(); foreach ($ROWS as $row) { if ($idxCol) { $idx = $row[$idxCol]; if ($this->filterKey($idx)) { $inst = $this->getInst($row); if ($inst) { if ($this->useFetcher) { //http://stackoverflow.com/questions/3637164/why-does-the-error-expected-to-be-a-reference-value-given-appear $params = array(); $params[] = $inst; $params[] =& $result; $params[] = $row; call_user_func_array($this->fetcher, $params); } else { $result[$idx] = $inst; } } } } else { $inst = $this->getInst($row); if ($inst) { if ($this->useFetcher) { $params = array(); $params[] = $inst; $params[] =& $result; $params[] = $row; call_user_func_array($this->fetcher, $params); } else { $result[] = $inst; } } } } return $result; /* * Фетчим одну запись */ /* * Фетчим одну запись */ case self::FETCH_TYPE_RECORD: case self::FETCH_TYPE_RECORD_OR_NULL: $rowsCnt = count($ROWS); switch ($rowsCnt) { case 0: if ($this->fetchType == self::FETCH_TYPE_RECORD_OR_NULL) { return null; //-- } return PsUtil::raise('Данные для объекта [{}] не найдены', $this->RC->getName()); case 1: $inst = $this->getInst($ROWS[0]); if ($inst) { return $inst; } return PsUtil::raise('Объект [{}] загружен, но не прошёл фильтрацию', $this->RC->getName()); } return PsUtil::raise('Найдено {} записей при извлечении объекта [{}]', $rowsCnt, $this->RC->getName()); } PsUtil::raise('Неизвестный тип фетчинга {} для {}', $this->fetchType, __CLASS__); }
/** * Метод возвращает путь к классу для сущности фолдинга * Если сущности не существует или мы не поддерживаем работу с классами - выдаём ошибку. */ public function getClassPath($ident) { if (self::PATTERN_NAME === $ident) { return PsUtil::raise('Нельзя загрузить путь к классу для сущности {}', self::PATTERN_NAME); } $this->assertAllowedResourceType(self::RTYPE_PHP); return check_condition(FoldedStorage::tryGetEntityClassPath($this->CLASS_PREFIX . $ident), 'Не найден класс реализации для сущности ' . $this->getTextDescr($ident)); }
/** * Конструктор класса для работы с кешем. * Кеширование идёт в два этапа: * 1. Кеширование на уровне класса для максимально быстрого доступа * 2. Кеширование в долгосрочном хранилище, которое реализуется отдельным классом - "движком" кеширования * * Движок кеширования должен быть задан на уровне config.ini * * @return PSCache */ protected function __construct() { $this->LOGGER = PsLogger::inst(__CLASS__); /* * Получим название класса "движка" кеширования */ $class = ConfigIni::cacheEngine(); /* * Проверим наличие класса */ $classPath = Autoload::inst()->getClassPath($class); if (!PsCheck::isNotEmptyString($classPath)) { return PsUtil::raise('Не удалось найти класс для кеширования [{}]', $class); } /* * Правильный ли класс указан? */ if (!PsUtil::isInstanceOf($class, 'PSCacheEngine')) { return PsUtil::raise('Указанный класс кеширования [{}] не является наследником класса [{}]', $class, 'PSCacheEngine'); } $this->LOGGER->info('Используем движок кеширования: {}', $class); $this->CACHE_ENGINE = new $class(); }
/** * Метод вызывается для выполнения периодических задач cron * * @return type */ public function execute() { if ($this->called) { return $this->executed; //--- } $this->called = true; $LOGGER = PsLogger::inst(__CLASS__); $LOGGER->info('Executing {}', __CLASS__); /* * Получим список классов, которые нужно выполнить */ $processes = ConfigIni::cronProcesses(); if (empty($processes)) { $LOGGER->info('No cron processes configured, fast return...'); return $this->executed; //--- } $processes = array_unique($processes); $LOGGER->info('Configured processes: {}', array_to_string($processes)); foreach ($processes as $class) { if (!PsUtil::isInstanceOf($class, 'PsCronProcess')) { PsUtil::raise("Class {$class} cannot be executed as cron process, it should be instance of PsCronProcess"); } } $locked = PsLock::lock(__CLASS__, false); $LOGGER->info('Lock accured ? {}', var_export($locked, true)); if (!$locked) { return $this->executed; //--- } $LOCKFILE = DirManager::autoNoDel(DirManager::DIR_SERVICE)->getDirItem(null, __CLASS__, PsConst::EXT_LOCK); $LOCKFILE_LIFETIME = $LOCKFILE->getFileLifetime(); $MAX_LIFETIME = 5 * 60; $NED_PROCESS = $LOCKFILE_LIFETIME === null || $LOCKFILE_LIFETIME > $MAX_LIFETIME; $LOGGER->info("Lock file {}: {}", $LOCKFILE_LIFETIME === null ? 'NOT EXISTS' : 'EXISTS', $LOCKFILE->getRelPath()); if ($LOCKFILE_LIFETIME !== null) { $LOGGER->info('Last modified: {} seconds ago. Max process delay: {} seconds.', $LOCKFILE_LIFETIME, $MAX_LIFETIME); // } if (!$NED_PROCESS) { $LOGGER->info('Skip execution.'); //Отпустим лок PsLock::unlock(); //Выходим return $this->executed; //--- } //Обновим время последнего выполнения $LOCKFILE->touch(); //Отпустим лок, так как внутри он может потребоваться для выполнения других действий, например для перестройки спрайтов PsLock::unlock(); $LOGGER->info(); $LOGGER->info('External process execution started...'); //Запускаем режим неограниченного выполнения PsUtil::startUnlimitedMode(); //Начинаем выполнение $this->executed = true; //Создаём профайлер $PROFILER = PsProfiler::inst(__CLASS__); //Создадим конфиг выполнения процесса $config = new PsCronProcessConfig(); //Пробегаемся по процессам и выполняем. При первой ошибке - выходим. foreach ($processes as $class) { $LOGGER->info('Executing cron process {}', $class); $PROFILER->start($class); try { $inst = new $class(); $inst->onCron($config); $secundomer = $PROFILER->stop(); $LOGGER->info(" > Cron process '{}' executed in {} seconds", $class, $secundomer->getTotalTime()); } catch (Exception $ex) { $PROFILER->stop(); $LOGGER->info(" > Cron process '{}' execution error: '{}'", $class, $ex->getMessage()); } } $LOGGER->info('Removing cron lock file.'); $LOCKFILE->remove(); return $this->executed; }
private function raiseNotRealised($__CLASS__, $__FUNCTION__, $tagName) { PsUtil::raise("Не реализована функиця {$__CLASS__}->{$__FUNCTION__}, при этом она вызвана для тега {$tagName}"); }