/** * Основной метод, регистрирующий класс для закрытия * * @param Destructable $inst - Экземпляр класса, которй будет гарантированно закрыт в свою очередь * @param int $order - порядок закрытия */ public static function registerDestructable(Destructable $inst, $order) { /* * Класс получаем через get_called_class(), так как PsShotdownSdk может быть переопределён проектным */ $class = get_called_class(); /* * Проверяем, что нам передан валидный order */ $order = PsUtil::assertClassHasConstVithValue($class, null, PsCheck::int($order)); /* * Регистрируем shutdown */ if (is_null(self::$DESTRUCTS)) { PsUtil::assertClassHasDifferentConstValues($class); self::$DESTRUCTS = array(); register_shutdown_function(array(__CLASS__, '_doShotdown')); } /* * Проверим, что нет попытки повторной регистрации с тем-же order */ if (array_key_exists($order, self::$DESTRUCTS)) { raise_error("Попытка повторно зарегистрировать Destructable с порядком [{$order}] для класса " . get_class($inst)); } /* * Регистрируем класс на закрытие */ self::$DESTRUCTS[$order] = $inst; }
protected function registerPluginsImpl() { $pluginType = strtolower(cut_string_end(cut_string_start(get_called_class(), 'Smarty'), 's')); foreach (PsUtil::getClassMethods(get_called_class(), true, true, null, true) as $tagName) { $this->register($tagName, $pluginType); } }
/** * Метод возвращает экземпляр класса-хранилища маппингов. * Может быть переопределён в 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(); }
/** * Метод безопасно получает контент. * В случае возникновения ошибки возвращает её стек. */ public static function getContent($objOrTpl, $method = 'buildContent') { $isCallable = is_callable($objOrTpl); $isTpl = $objOrTpl instanceof Smarty_Internal_Template; if (!$isCallable && !$isTpl) { check_condition(is_object($objOrTpl), 'Not object passed to ' . __FUNCTION__); PsUtil::assertMethodExists($objOrTpl, $method); } $returned = null; $flushed = null; ob_start(); ob_implicit_flush(false); try { if ($isCallable) { $returned = call_user_func($objOrTpl); } else { if ($isTpl) { $returned = $objOrTpl->fetch(); } else { $returned = $objOrTpl->{$method}(); } } } catch (Exception $ex) { ob_end_clean(); return ExceptionHandler::getHtml($ex); } $flushed = ob_get_contents(); ob_end_clean(); return isEmpty($returned) ? isEmpty($flushed) ? null : $flushed : $returned; }
public static function valueOf($name) { if (in_array($name, self::names())) { return static::$name(); } PsUtil::raise('Enum {} not contains value {}', get_called_class(), $name); }
protected function doBuild(\PageContext $ctxt, \PageBuilderContext $builderCtxt, \RequestArrayAdapter $requestParams, \ArrayAdapter $buildParams) { //1. ЗАГОЛОВОК $builderCtxt->setTitle($this->authed ? 'Админка | ' . $this->adminPage->title() : 'xxx'); //2. JAVASCRIPT $builderCtxt->setJsParams($this->authed ? $this->adminPage->getJsParams() : null); //3. SMARTY RESOURCES if ($this->authed) { $builderCtxt->setSmartyParams4Resources($this->adminPage->getSmartyParams4Resources()); $builderCtxt->setSmartyParam4Resources('IDENT', $this->adminPage->getPageIdent()); $builderCtxt->setSmartyParam4Resources('TIMELINE_ENABE', true); } $smartyParams['authed'] = $this->authed; if (!$this->authed) { return $smartyParams; } //Запустим неограниченный по времени режим - мало ли, что мы там будем делать:) PsUtil::startUnlimitedMode(); //Получаем содержимое админской страницы $content = ContentHelper::getContent($this->adminPage); //Добавляем к ней ресурсы $content = APagesResources::inst()->getResourcesLinks($this->adminPage->getPageIdent(), $content); $smartyParams['page'] = $this->adminPage; $smartyParams['content'] = $content; $smartyParams['pagesLayout'] = AdminPagesManager::getInstance()->getLayout(); return $smartyParams; }
/** * Метод вызывается для инициализации окружения: * 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 getMethodAdapters($public = true, $static = null, $final = null, $checkOwned = true) { $methods = array(); foreach (PsUtil::getClassMethods($this->rc->name, $public, $static, $final, $checkOwned) as $method) { $methods[$method] = PhpMethodAdapter::inst($this->rc->name, $method); } return $methods; }
public final function decodeAction($action, $canBeNull = true) { $action = $this->validateAction($action, $canBeNull); if ($action === null) { return 'null'; } return PsUtil::getClassConstByValue($this->CLASS, 'ACTION_', $action) . ' (' . $action . ')'; }
/** * Метод возвращает спрайты для всех зарегистрированных директорий */ public static function getAllDirsSptites() { $sprites = array(); foreach (PsUtil::getClassConsts(__CLASS__, 'DIR_') as $dirName) { $sprites[$dirName] = self::getSprite($dirName); } return $sprites; }
/** * Идентификатор акции - хэш от типа акции и её параметров. * Две акции с одним типом но разными кодами считаются разными. * * @param array $params - параметры акции */ private function sign(array $params) { $type = self::getType(); $sign['_STOCK_CLASS_TYPE_'] = $type; foreach (PsUtil::getClassConsts($this, 'DATA_') as $param) { $sign[$param] = check_condition(array_get_value($param, $params), "Для акции {$type} не указан обязательный параметр [{$param}]."); } return simple_hash($sign); }
protected function getPlugins() { $type = strtolower(cut_string_end(cut_string_start($this->CLASS, 'Smarty'), 's')); $result = array(); foreach (PsUtil::getClassMethods($this->CLASS, true, true, null, true) as $method) { $result[$method] = $type; } return $result; }
/** * Возвращает названия всех классов в директории */ public static function getDirClassNames($__DIR__, $subDir, $parent) { $classes = array(); foreach (DirManager::inst($__DIR__)->getDirContent($subDir, PsConst::EXT_PHP, DirManager::DC_NAMES_NO_EXT) as $name) { if (PsUtil::isInstanceOf($name, $parent)) { $classes[] = $name; } } return $classes; }
public static function ident($item) { if ($item instanceof AbstractPost) { return self::postId($item->getPostType(), $item->getIdent()); } if ($item instanceof Rubric) { return self::rubricId($item->getPostType(), $item->getIdent()); } raise_error('В IdHelper передан элемент неподдрживаемого типа: ' . PsUtil::getClassName($item)); }
/** * Вызов выполнения метода. Используется из ajax. */ public static function execute($method, array $params) { check_condition(array_key_exists($method, self::getMethodsList()), "Method TestManager::{$method} cannot be called"); PsUtil::startUnlimitedMode(); PsLogger::inst('TestManager')->info("Method TestManager::{$method} called with params: " . array_to_string($params)); $s = Secundomer::startedInst(); call_user_func_array(array(TestManager::inst(), $method), $params); $s->stop(); PsLogger::inst('TestManager')->info("Call done in {$s->getTotalTime()} seconds"); }
public static function psctrl(array $params) { $id = array_get_value_unset('id', $params); $class = to_array(array_get_value_unset('class', $params)); $class[] = 'pscontrols'; if (!empty($params)) { array_remove_keys($params, array_diff(array_keys($params), PsUtil::getClassConsts(__CLASS__, 'ACTION_'))); } return empty($params) ? '' : PSSmarty::template('common/pscontrols.tpl', array('id' => $id, 'class' => PsHtml::classes2string($class), 'actions' => $params))->fetch(); }
/** * В конструкторе мы провалидируем настройки бина и проинициализируем protected поля */ protected final function __construct() { parent::__construct(); $this->SETTINGS = PsUtil::assertInstanceOf($this->PostBeanSettings(), PostBeanSettings::getClass()); //Инициализируем поля для быстрого доступа внутри бина $this->rubricsTable = $this->SETTINGS->getRubricsTable(); $this->rubricsView = $this->SETTINGS->getRubricsView(); $this->postsTable = $this->SETTINGS->getPostsTable(); $this->postsView = $this->SETTINGS->getPostsView(); $this->commentsTable = $this->SETTINGS->getCommentsTable(); }
/** * Метод добавляет шорткоды * TODO - вынести на конфиги */ public static function addShortcodes() { $wpShortcodes = new PsWpShortCodes(); $methods = PsUtil::getClassMethods($wpShortcodes, true, false, true, false); $LOGGER = PsLogger::inst(__CLASS__); $LOGGER->info(); $LOGGER->info(__METHOD__); foreach ($methods as $action) { $LOGGER->info(' + {}', $action); add_shortcode($action, array($wpShortcodes, $action)); } }
/** * Выполняет замену смарти-функций на вызов функций данного класса */ public static function preCompile($source) { $class = __CLASS__; foreach (PsUtil::getClassMethods($class, true, true, true) as $method) { if ($method == __FUNCTION__) { continue; } $source = str_replace('{' . $method . '}', "{if {$class}::{$method}()}", $source); $source = str_replace('{/' . $method . '}', '{/if}', $source); } return $source; }
private function buildJsDefs(PageParams $params, PageContext $ctxt) { $JS_CLASS_CONSTS = PsUtil::getClassConsts('PsConstJs'); $JS_CONSTS = $this->jsConsts(); $JS_COMMON = $this->jsCommon($ctxt); $JS_PAGE = $params->getJsParams(); $defs = json_encode(array_merge($JS_CONSTS, $JS_COMMON, $JS_PAGE)); $const = json_encode($JS_CLASS_CONSTS); $defs = "var defs={$defs}; var CONST={$const};"; $defs = PsHtml::linkJs(null, $defs); $this->LOGGER->infoBox('JS DEFS', $defs); return $defs; }
/** * @param type $group - группа дискуссий (должна быть уникальна среди всех групп, например - посты или фидбеки) * @param type $subgroup - подгруппа дискуссии (должна быть уникальна в рамках группы) * @param type $unique - уникальный код дискуссии, комбинация группы и подгруппы * @param type $table - таблица с сообщениями * @param type $idColumn - первичный ключ таблицы с сообщениями * @param type $threadIdColumn - столбец с кодом треда (для дискуссий, работающих с тредами) * @param type $themeColumn - столбец с темой (если идёт работа с темой) * @param type $msgClass - клсс, хранящий сообщение. Должен быть наследником DiscussionMsg. * @param type $templatable - признак, можно ли использовать шаблонные сообщения */ public function __construct($group, $subgroup, $table, $idColumn, $msgClass = 'DiscussionMsg', $threadIdColumn = null, $themeColumn = null, $templatable = false, $votable = true) { $this->group = $group; $this->subgroup = $subgroup; $this->unique = $group . ($subgroup ? "-{$subgroup}" : ''); $this->table = $table; $this->idColumn = $idColumn; $this->msgClass = $msgClass; $this->threadIdColumn = $threadIdColumn; $this->themeColumn = $themeColumn; $this->templatable = $templatable; $this->votable = $votable; check_condition(PsUtil::isInstanceOf($msgClass, 'DiscussionMsg'), "Класс '{$msgClass}' не наследует DiscussionMsg"); }
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 function __construct($message, $code, $query, array $params, $previous = null) { $this->query = $query; $this->params = $params; $code = PsUtil::assertClassHasConstVithValue(__CLASS__, 'ERROR_', $code); if ($code == self::ERROR_NOT_CLASSIFIED) { /* * Если ошибка не классифицирована, то мы попробуем её классифицировать */ if (starts_with($message, 'Duplicate entry ')) { $code = self::ERROR_DUPLICATE_ENTRY; } } $message = $message ? $message : 'Unknown db error'; $message = "{$message}. Query: [{$query}]" . ($params ? ', Params: ' . array_to_string($params) . '.' : ''); parent::__construct($message, $code, $previous); }
/** * В процессе закрытия данного класса мы напишем полный список изменённых сущностей */ public function onDestruct() { foreach (array('ACTION_FOLDING_' => 'Фолдинги', 'ACTION_ENTITY_' => 'Сущности') as $CONST_PREFIX => $name) { $this->LOGGER->infoBox($name); foreach (PsUtil::getClassConsts($this, $CONST_PREFIX) as $action) { $idents = array_get_value($action, $this->ACTIONS, array()); $count = count($idents); $this->LOGGER->info(); $this->LOGGER->info($action . ':'); if ($count > 0) { for ($i = 0; $i < $count; $i++) { $this->LOGGER->info("\t" . (1 + $i) . '. ' . $idents[$i][0] . ($idents[$i][1] ? ' [' . $idents[$i][1] . ']' : '')); } } else { $this->LOGGER->info("\t -- Нет --"); } } } }
public function buildContent() { PsUtil::startUnlimitedMode(); $s = Secundomer::inst(); $data = array(); for ($num = 0; $num <= self::REQUESTS_COUNT; $num++) { $s->start(); file_get_contents($this->url); $s->stop(); $data[$num]['time'] = $s->getTime(); $data[$num]['total'] = $s->getTotalTime(); if ($num == 0) { //Запросим один раз, чтобы сработало кеширование, если оно включено $s->clear(); } } $params = array('url' => $this->url, 'data' => $data, 'average' => $s->getAverage()); echo $this->getFoldedEntity()->fetchTpl($params); }
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); }
private function executeImpl($lifeTimeOnCall, $__FUNCTION__) { if ($this->called) { return $this->executed; //--- } $this->called = true; $LOGGER = PsLogger::inst(__CLASS__); $LOGGER->info("Function [{$__FUNCTION__}] called."); $needProcess = false; $LOCKFILE = DirManager::autogen('service')->getDirItem(null, __CLASS__, 'lock'); if ($LOCKFILE->isFile()) { $lifeTime = $LOCKFILE->getFileLifetime(); $needProcess = !$lifeTime || !$lifeTimeOnCall || $lifeTime >= $lifeTimeOnCall; $LOGGER->info('{} process. Lock file modified {} seconds ago. Process delay: {} seconds.', $needProcess ? 'Need' : 'Not need', $lifeTime, $lifeTimeOnCall); } else { $needProcess = true; $LOGGER->info('Need process. Lock file is not exists.'); } if (!$needProcess) { return $this->executed; //--- } $locked = PsLock::lock(__CLASS__, false); $LOGGER->info('External process lock {} execution.', $locked ? 'acquired, start' : 'not acquired, skip'); if ($locked) { $LOCKFILE->touch(); PsUtil::startUnlimitedMode(); //Отпустим лок, так как внутри он может потребоваться для выполнения других действий, например для перестройки спрайтов PsLock::unlock(); //Начинаем выполнение $this->executed = true; $job = new ExternalProcessJob(); PsProfiler::inst(__CLASS__)->start(__FUNCTION__); $job->execute(); $secundomer = PsProfiler::inst(__CLASS__)->stop(); if ($secundomer) { $LOGGER->info("{$secundomer}"); } } return $this->executed; }
/** * Метод предназначен для загрузки единичной записи. Если извлекается более одной записи - * выбразывается исключение. * * $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()); }
private static function makeProvider($content) { if ($content instanceof Rubric) { if ($content->isTpl()) { return new RubricContentProviderTpl($content); } else { return new RubricContentProviderDB($content); } } if ($content instanceof Post) { if ($content->is(POST_TYPE_ISSUE)) { return new IssueContentProvider($content); } if ($content->isTpl()) { return new PostContentProviderTpl($content); } else { return new PostContentProviderDB($content); } } raise_error('Не удалось построить ' . __CLASS__ . ' для ' . PsUtil::getClassName($content)); }
/** * Метод собирает всю необходимую информацию о галерее и кеширует её для быстрого доступа. */ private function getSnapshot() { $DATA = PSCache::GALLERY()->getFromCache($this->gallery, PsUtil::getClassConsts($this, 'PARAM_')); if (is_array($DATA)) { return $DATA; //--- } $DATA = array(); /* * Информация о галерее (из базы) */ $galleryInfo = GalleryBean::inst()->getGalleryInfo($this->gallery); //name $gallName = $galleryInfo ? trim($galleryInfo['v_name']) : ''; $gallName = $gallName ? $gallName : 'Галерея'; /* * Картинки, входящие в галерею (те, для которых есть запись в БД и b_show=1). * Мы также сразу отсеим те картинки, для которых нет файла на файловой системе, * чтобы потом клиент не делал лишний запрос на наш сервер. */ $galleryImages = GalleryBean::inst()->getGalleryItems($this->gallery, false, $this->getDirectoryImgNames()); //Проведём фетчинг необходимых представлений галереи $SmartyParams['id'] = $this->gallery; $SmartyParams['name'] = $gallName; $SmartyParams['images'] = $galleryImages; //.box_images - блок картинок, который будет преобразован в галерею с помощью js. $imagesHtml = PSSmarty::template('mmedia/gallery/box_images.tpl', $SmartyParams)->fetch(); $imagesHtml = normalize_string($imagesHtml); //.as_list - для отображения списка картинок в popup окне $asListHtml = PSSmarty::template('mmedia/gallery/as_list.tpl', $SmartyParams)->fetch(); $asListHtml = normalize_string($asListHtml); //Все сложим в файл и сохраним в кеш $DATA[self::PARAM_CNT] = count($galleryImages); $DATA[self::PARAM_NAME] = $gallName; $DATA[self::PARAM_ASLIST] = $asListHtml; $DATA[self::PARAM_BOXIMGS] = $imagesHtml; return PSCache::GALLERY()->saveToCache($DATA, $this->gallery); }