From f2938b13531177fb44a91235ad9c455fb97eef00 Mon Sep 17 00:00:00 2001 From: origami11 Date: Thu, 9 Feb 2017 17:14:11 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B8=D0=BD=D1=85=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BB=20=D1=87=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=87=D0=BD=D0=BE=20=D1=81=20CMS2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + src/collection.php | 7 +- src/controller/action.php | 648 ++++++++---------- src/controller/controller.php | 341 --------- src/controller/front.php | 14 +- src/controller/model.php | 426 ++++++++++++ src/controller/state.php | 15 +- src/filter/actionlogger.php | 2 - src/filter/{filterbase.php => filter.php} | 0 src/filter/{filterlogin.php => login.php} | 8 +- src/filter/useraccess.php | 5 +- src/form/form.php | 10 +- src/functions.php | 52 +- src/httprequest.php | 69 +- src/layout/{layout.php => manager.php} | 22 +- src/layout/none.php | 11 + src/mail.php | 62 +- .../{simple_bb_code.php => simplebbcode.php} | 4 +- src/numbers.php | 2 +- src/path.php | 419 ++++++----- src/registry.php | 2 + src/session.php | 2 +- src/settings.php | 35 +- src/setup.php | 218 +++++- src/shortcut.php | 19 +- src/tales.php | 50 +- src/tools/drawing.php | 8 +- src/view/composite.php | 40 ++ src/view/{compositeview.php => top.php} | 41 +- src/zipfile.php | 13 +- 30 files changed, 1447 insertions(+), 1099 deletions(-) create mode 100644 .gitignore delete mode 100644 src/controller/controller.php create mode 100644 src/controller/model.php rename src/filter/{filterbase.php => filter.php} (100%) rename src/filter/{filterlogin.php => login.php} (94%) rename src/layout/{layout.php => manager.php} (82%) create mode 100644 src/layout/none.php rename src/markup/{simple_bb_code.php => simplebbcode.php} (97%) create mode 100644 src/view/composite.php rename src/view/{compositeview.php => top.php} (89%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7664704 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.bak \ No newline at end of file diff --git a/src/collection.php b/src/collection.php index 5ab61ec..467175e 100644 --- a/src/collection.php +++ b/src/collection.php @@ -1,8 +1,7 @@ data[$key] = $value; } @@ -54,7 +53,7 @@ class Collection implements ArrayAccess */ public function get($key, $default = null) { - return isset($this->data[$key]) ? $this->data[$key] : $default; + return isset($this->data[$key]) && $this->data[$key] != '' ? $this->data[$key] : $default; } public function getInt($key, $default = 0) diff --git a/src/controller/action.php b/src/controller/action.php index 24d8eb1..42eb674 100644 --- a/src/controller/action.php +++ b/src/controller/action.php @@ -1,423 +1,339 @@ table->setHeader - */ - public $tableSchema = null; - public $formSchema = array(); +/** + * Контроллер страниц + */ +class Controller_Action +{ - public $menu; + const TEMPLATE_EXTENSION = ".html"; // Расширение для шаблонов + const ACTION_PREFIX = "action"; // Префикс для функций действий + + public $jsPath; // Глобальный путь к скриптам + public $themePath; // Глобальный путь к текущей теме + + // Параметры устанавливаются при создании контроллера + public $name; // Имя модуля + public $viewPath = null; // Путь к шаблонам контроллера + public $db; // Соединение с базой данных + + // Фильтры + public $access = null; // Обьект хранит параметры доступа + public $logger = null; // Обьект для ведения лога + + private $factory = null; // Ссылка на обьект создания модели + private $helpers = array(); // Помошники для действий + public $param = array(); // Параметры для ссылки + + public /*.Registry.*/$_registry; // Ссылка на реестр + public $_shortcut; + public $modulePrefix = ''; + public $iconPath = ''; public $path; - public $table; - public function __construct() + public function __construct () { - $this->path = new PathMenu(); - $this->menu = new PageMenu(); - $this->table = new ListTable(); + // } - /** - */ - function setUp() + public function setUp () { - $this->table->addMenuItem($this->aUrl('delete'), 'удалить', false, 'all', 'warning'); - //$this->table->addMenuItem($this->nUrl('form'), 'редактировать', 'edit-24.png'); + // override this } - function saveParameters($args, $list) - { - foreach ($list as $item) { - $args->session()->set(array($this, $item), $args->get($item)); - } - } - - protected function getJSONList(/*Mapper*/ $model, Collection $request) - { - $result = array(); - $this->saveParameters($request, array('size','page','desc', 'key')); - - $result['list'] = $model->findAll($request, $request->get('ref')); - $result['size'] = $model->getCount($request, $request->get('ref')); - return json::encode($result); - } - - /** - * Удаление сторк из таблицы - */ - public function actionDelete(HttpRequest $request) - { - $model = $this->getModel($this->useModel); - // Почему table_item ??? - $list = ($request->get('table_item')) ? $request->get('table_item'): $request->get('id'); - $model->deleteList($list); - - return $this->getJSONList($model, $request); - } - - /** - * Ответ на запрос по поиску - */ - public function actionSearch(HttpRequest $request) - { - $model = $this->getModel($this->useModel); - $model->addFilter($model->requestToSQL($request, $this->formSchema)); - - return $this->getJSONList($model, $request); - } - - /** - * Список элементов - */ - public function actionList(HttpRequest $request) - { - $model = $this->getModel($this->useModel); - return $this->getJSONList($model, $request); - } - - - private function setFormSchema() - { - require_once 'core/mapper/uimapper.php'; - - $model = $this->getModel($this->useModel); - $ui = new UIMapper($model); - - $this->formSchema = $ui->getFormSchema(); - } - - /** - * Сохранение формы - */ - function beforeSave(/*Model*/ $item, Collection $request) - { - if (empty($this->formSchema)) { - $this->setFormSchema(); - } - // Сделать отображение Формы в обьект и обратно <-- Убрать в beforeSave - foreach ($this->formSchema as $key => $conv) { - list($value, $type) = $conv; - $item->$value = call_user_func(array('Cast', 'to_' . $type), $request->get($key)); // Здесть нужно преобразовывать тип значения - } - } - - /** - * Обновление формы - */ - function formUpdate(TForm $form, Collection $request) - { - } - - /** - * Загрузка формы - */ - function beforeLoad(/*Model*/ $item, TForm $form) - { - if (empty($this->formSchema)) { - $this->setFormSchema(); - } - // Вставка значений из данных в форму - // Отображение обьекта в поля формы - $form->fill($item, $this->formSchema); - } - - // Проверка ввода - protected function validate($validator, $request) - { - } - - /** - * Действие для проверки формы - */ - public function actionValidate($request) - { - require_once "core/validator/validator.php"; - $validator = new Validator(); - $validator->addRuleList($this->schema); - - // Действия до проверки формы - $this->validate($validator, $request); // <--| - $validator->validate($request); // --| - // Проверка формы - if (!$validator->isValid()) { - return json::encode($validator->getErrorMsg()); - } - return json::encode(true); - } - - /** - * Инициализация формы - */ - protected function formSetup($form, $id = null, $ref = null) - { - if (empty($this->schema)) { - $model = $this->getModel($this->useModel); - $ui = new UIMapper($model); - $schema = $ui->getEditSchema(); - - $form->addFieldList($schema); + public function loadConfig($name) { + $filename = Shortcut::getUrl('config', $name); + if (file_exists($filename)) { + include($filename); } else { - $form->addFieldList($this->schema); + throw new Exception('Невозможно загрузить файл настроек ' . $name); + } + return $settings; + } + + public function getConnection() + { + return $this->db; + } + + public function installPath($name) + { + return Path::join(CMS_PATH, "modules", $name, "install"); + } + + public function addSuggest($view, $name) + { + $suggest = array(); + $file = Path::join($this->viewPath, 'help', $name . '.suggest'); + if (file_exists($file) && include($file)) { + $view->addScriptRaw("add_suggest(".json::encode($suggest).");\n"); } } - /** - * Добавление пользователя - */ - public function actionAdd(HttpRequest $request) + function findIcon($icon, $size) { - require_once "core/validator/validator.php"; - // {{{ тоже может быть один ref или несколько - $ref = $request->get('ref'); - $this->addParameter('ref', $ref); // Добавляет параметр в url - /// }}} - - if ($this->checkPageId($request, $request->get('page'))) { - // Проверка - $validator = new Validator(); - $validator->addRuleList($this->schema); + return Path::join($this->iconPath, $size . 'x' . $size, $icon . '.png'); + } - // Действия до проверки формы - $this->validate($validator, $request); // <--| - $validator->validate($request); // --| - // Проверка формы - if (!$validator->isValid()) { - $request->setAction('form'); - $this->getActionPath($request); - - $form = new TForm(); - $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы - - $form->setValues($request); // <-- Убрать в formUpdate - $this->formUpdate($form, $request); - - $form->setError($validator); // Установка ошибок для формы - - $tpl = $this->formPage($form, $request); - $id = $request->get('id'); - if ($id) { // Редактирование - $tpl->action = forceUrl($this->nUrl('add', array('id' => $id, 'page' => $this->getPageId($request)))); // action Совйство формы - } - return $tpl /*->execute()*/; - } - - // Нужен тест для формы - $model = $this->getModel($this->useModel); - $className = $model->className; - $item = new $className(); - - // Сохраняем значение в базе данных - $item->id = $request->get('id'); - // Если таблица связана с другой таблицей - if ($request->get('ref') && $model->reference[1]) { - $ref_id = $model->reference[1]; - $item->$ref_id = $request->get('ref'); - } - - // Подготовка к сохранению - $this->beforeSave($item, $request); // Сюдаже и истрия переходов - // nextId ??? или выход или новая форма для создания новости - $model->saveDB($item, $request); - } - - // Для страницы со списком id -> идентефикатор родительской таблицы !!?? -// $request->set('id', $request->get('ref')); - if ($request->get('apply')) { - $request->setAction('form'); - return $this->forward('actionForm', $request); - } - return $this->forward('actionIndex', $request); - } - /** - * Заголовок + * Создает представление + * @param string $file + * @return template */ - private function setTitlePath($ref) + public function getView($name) { - if ($ref) { - $model = $this->getModel($this->useModel); - if (is_array($model->reference) && $model->reference[0]) { - $refmodel = $this->getModel($model->reference[0]); - try { - $parent = $refmodel->findById($ref); - $this->path->addTitle($parent->getTitle()); // Заголовок к подписям путей - } catch (Exception $e) { - // Не найден заголовок потому что неправильно определен родительский элемент - } - } + $file = $name . self::TEMPLATE_EXTENSION; + // Список возможных директорий для поиска файла шаблона + $theme = $this->_registry->readKey(array('system', 'theme')); + $icon_theme = $this->_registry->readKey(array('system', 'icon_theme')); + $list = array( + Path::join($this->viewPath, TEMPLATES) => Path::join(WWW_PATH, "modules", $this->name, TEMPLATES), + PHPTAL_TEMPLATE_REPOSITORY => ""); + + + // Поиск файла для шаблона + foreach($list as $ospath => $path) { + $template = Path::join($ospath, $file); + if(file_exists($template)) { break; } } - } - - /** - * Форма для редактирования - */ - public function actionForm(HttpRequest $request) - { - $this->getActionPath($request); - $ref = $request->get('ref'); - $this->addParameter('ref', $ref); // Добавляет параметр в url - $this->setTitlePath($ref); - $model = $this->getModel($this->useModel); - $form = new TForm(); // Показываем форму - $form->header = 'Редактирование записи'; - $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы + $tpl = new View_Composite($template); + $tpl->icons = $this->iconPath; // Путь к файлам текущей темы + $tpl->media = $this->themePath; // Путь к файлам текущей темы + $tpl->script = $this->jsPath; // Путь к файлам скриптов + $tpl->template = $path; // Путь к файлам текущего шаблона + $tpl->setAlias(array( + '${icons}' => $this->iconPath, + '${media}' => $this->themePath, + '${script}' => $this->jsPath, + '${template}' => $path)); - $list = $request->get('table_item'); - $id = ($list[0]) ? $list[0] : $request->get('id'); + $tpl->loadImports(Path::skipExtension($template) . ".import"); - $tpl = $this->formPage ($form, $request); - if ($id) { // Редактирование - $form->action = forceUrl($this->nUrl('add', array('id' => $id, 'page' => $this->getPageId($request)))); // action Свойство формы - $item = $model->findById($id); - // Загрузка формы - $this->beforeLoad($item, $form); - /// - } + $this->addSuggest($tpl, $name); return $tpl; } - /** - */ - function tableSetup($table, $id = null, $ref = null) + public function getModel($name) { - // FIXME: После замены везде $tableSchema -> table->setHeader удалить! - if ($this->tableSchema) { - $table->setHeader($this->tableSchema); - } else { - // Настройка таблицы отображения по схеме данных - require_once 'core/mapper/uimapper.php'; - $model = $this->getModel($this->useModel); - $ui = new UIMapper($model); - $schema = $ui->getTableSchema(); - $schema[0]['action'] = $table->getFirstItem(); - - $table->setHeader($schema); + if (!$this->factory) { + $this->factory = new ModelFactory($this->db, $this->_registry, $this->_shortcut); } + return $this->factory->getModel($name); } /** + * Выбор действия + * Т.к действия являются методами класса то + * 1. Можно переопределить действия + * 2. Использовать наследование чтобы добавить к старому обработчику новое поведение + * @param $request Обьект запроса */ - public function actionIndex(HttpRequest $request) + public function execute1(HTTPRequest $request) { - $this->getActionPath($request, 'index'); - // Такое мета действие наверное можно вынести в отдельный класс - return $this->metaActionIndex($request, array($this, 'tableSetup'), $this->aUrl('list')); + $action = self::ACTION_PREFIX . ucfirst($request->getAction()); + if (method_exists($this, $action)) { + return $this->forward($action, $request); + } else { + return $this->forward("actionIndex", $request); + } + } + + public function execute(HTTPRequest $request) + { + $result = $this->execute1($request); + if ($result) { + $this->view = $result; + } + return $this->render(); + } + + public function forward($action, HTTPRequest $args) + { + // Действия до вызова основного обработчика + /*foreach($this->_aspect as $aspect) { + if (isset($aspect->before[$action])) { + call_user_func ($aspect->before[$action], $action, $args); + } + }*/ + return call_user_func(array($this, $action), $args); } /** * Страница по умолчанию */ - public function metaActionIndex(HttpRequest $request, $setup, $list) + public function actionIndex(HttpRequest $request) { - // может быть одно ref или несколько - // {{{ история переходов - $ref = null; - if ($request->get('ref')) { - $ref = $request->get('ref'); - } else if ($request->session()->get('ref')) { - $ref = $request->session()->get('ref'); + return ""; + } + + public function postUrl($name, $param) + { + return "?" . http_build_query( + array_merge(array('module' => strtolower(get_class($this)), "action" => $name), + $this->param, $param)); + } + + /** + * Генерация ссылки c учетом прав пользователя на ссылки + * + * @parma string $name Действие + * @parma string $param Дополнительные параметры + */ + public function nUrl($name, array $param = array()) + { + if (!$this->access || $this->access->checkAction($name)) { + return lcurry(array($this, 'postUrl'), $name, $param); } + return null; + } - $request->session->set('ref', $ref); - $this->addParameter('ref', $ref); - // }}} - $this->setTitlePath($ref); - - $tpl = $this->getView('list'); - - // Помошники действий - $this->callHelpers($request); - // Таблица - if ($request->session()->get(strtolower(get_class($this)))) { - $session = $request->session()->get(strtolower(get_class($this))); - if (isset($session['view'])) { - $this->table->setView($session['view']); - } - $this->table->setData('state', array( - 'page' => $session['page'], - 'size' => $session['size'], - 'desc' => $session['desc'])); - - $this->table->setData('sorter', $session['key']); - if (isset($session['desc'])) { - $this->table->setData('desc', $session['desc']); - } - } - - call_user_func($setup, $this->table, $request->get('id'), $ref);// --> Эквивалент formSetup - $this->table->setAction($list); - // - $tpl->menu_path = $this->path->getItems(); - - // Поиск - $search = new SearchDialog(); - $search->setTitle('Поиск'); - $search->setAction($this->aUrl('search')); - $search->setFriend($this->table); - $search->addFields($this->schemaSearch); - - // Настройки - $setup = new SetupDialog(); - $setup->setTitle('Настройки'); - $setup->setAction($this->nUrl('setup')); - $setup->setFriend($this->table); - - // Меню - $this->menu->addMenuItem('?menu=toggle&id=' . $search->getName(), 'поиск', 'actions/system-search'); // Стандартный размер для иконок 22-24px - $this->menu->addMenuItem('?menu=toggle&id=' . $setup->getName(), 'настройки', 'categories/applications-system'); - // Добавление компонентов - $this->addChild('menu', $this->menu); - $this->addChild('search', $search); - $this->addChild('setup', $setup); - $this->addChild('table', $this->table); - // - return $tpl; + public function fUrl($name, array $param = array()) + { + return forceUrl($this->nUrl($name, $param)); } /** + * Добавляет параметр для всех ссылок создаваемых функцией nUrl, aUrl */ - public function actionSetup($request) + public function addParameter($name, $value) { - $left = explode(",", $request->get('left')); - $right = explode(",", $request->get('right')); - - $$request->session()->set(strtolower(get_class($this)), - array('view' => array('left' => $left, 'right' => $right))); - - return $this->forward('actionIndex', $request); + if ($value) { + $this->param [$name] = $value; + } } /** + * Генерация ссылки на действие контроллера + * Ajax определяется автоматически mode = ajax используется для смены layout */ - private function formPage($form, $request) + public function aUrl($name, array $param = array()) { - $view = $this->getView('form'); - $view->setView('form', $form); - $view->action = forceUrl($this->nUrl('add', array('page' => $this->getPageId($request)))); // Действие для формы - - $view->menu_path = $this->path->getItems(); - $view->back = $this->path->getPrev(); - return $view; + return $this->nUrl($name, array_merge(array('mode' => 'ajax'), $param)); // FIXME } - // Тоже убрать в метод Controller_Model - function getActionPath(HttpRequest $request/*, $action = false*/) + /** + * Добавление помошника контроллера + */ + public function addHelper($class) { - require_once 'state.php'; - $this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction()); - } + $this->helpers [] = $class; + } + + /** + * Вызов помошников контроллера + */ + public function callHelpers(HttpRequest $request) + { + $action = self::ACTION_PREFIX . $request->getAction(); + foreach ($this->helpers as $helper) { + if (method_exists($helper, $action)) { + return call_user_func(array($helper, $action), $request, $this); + } else { + return $helper->actionIndex($request, $this); // Вместо return response ??? + } + } + } + + /** + * Загрузка файла класса + */ + public function loadClass($path, $setup = null) + { + if (file_exists($path)) { + require_once ($path); + $class = pathinfo($path, PATHINFO_FILENAME); + return new $class($setup); + } + return null; + } + + public function loadSettings($path) + { + $result = new Settings($path); + $result->read(); + return $result->export(); + } + + // Для Widgets + public $view = null; + public $childNodes = array(); + public $childViews = array(); + + public function setView($name) + { + $this->view = $this->getView($name); + } + + /** + * Установка заголовка для отображения + */ + public function setTitle($title) + { + $this->view->setTitle($title); + } + + /** + * Добавление widget к отображению + */ + public function addChild(/*Widget*/ $section, $node) + { + $this->childNodes[$section] = $node; + } + + /** + * Добавление дочернего отображения к текущему отображению + */ + public function addView(/*CompositeView*/ $section, $node) + { + $this->childViews[$section] = $node; + } + + /** + * Генерация содержания + * Путаница c execute и render + */ + public function render() + { + foreach ($this->childNodes as $name => $node) { + $node->make($this); + $this->view->setView($name, $node->view); + } + foreach ($this->childViews as $name => $node) { + $this->view->setView($name, $node); + } + return $this->view; + } + + function getPageId($request) + { + $pageId = time(); + $request->session()->set('page', $pageId); + return $pageId; + } + + function checkPageId($request, $page) + { + $_page = $request->session()->get('page'); + $result = ($_page && $_page == $page); + $request->session()->clean('page'); + return $result; + } + + function redirect($action) { + header('location: ' . $this->fUrl($action)); + exit(); + } } + diff --git a/src/controller/controller.php b/src/controller/controller.php deleted file mode 100644 index 2072006..0000000 --- a/src/controller/controller.php +++ /dev/null @@ -1,341 +0,0 @@ -db; - } - - public function installPath($name) - { - return Path::join(CMS_PATH, "modules", $name, "install"); - } - - public function addSuggest($view, $name) - { - $suggest = array(); - $file = Path::join($this->viewPath, 'help', $name . '.suggest'); - if (file_exists($file) && include($file)) { - $view->addScriptRaw("add_suggest(".json::encode($suggest).");\n"); - } - } - - function findIcon($icon, $size) - { - return Path::join($this->iconPath, $size . 'x' . $size, $icon . '.png'); - } - - /** - * Создает представление - * @param string $file - * @return template - */ - public function getView($name) - { - require_once "core/view/compositeview.php"; - - $file = $name . self::TEMPLATE_EXTENSION; - // Список возможных директорий для поиска файла шаблона - $theme = $this->_registry->readKey(array('system', 'theme')); - $icon_theme = $this->_registry->readKey(array('system', 'icon_theme')); - $list = array( - Path::join($this->viewPath, TEMPLATES) => Path::join(WWW_PATH, "modules", $this->name, TEMPLATES), - PHPTAL_TEMPLATE_REPOSITORY => ""); - - - // Поиск файла для шаблона - foreach($list as $ospath => $path) { - $template = Path::join($ospath, $file); - if(file_exists($template)) { break; } - } - - $tpl = new View_Composite($template); - $tpl->icons = $this->iconPath; // Путь к файлам текущей темы - $tpl->media = $this->themePath; // Путь к файлам текущей темы - $tpl->script = $this->jsPath; // Путь к файлам скриптов - $tpl->template = $path; // Путь к файлам текущего шаблона - $tpl->setAlias(array( - '${icons}' => $this->iconPath, - '${media}' => $this->themePath, - '${script}' => $this->jsPath, - '${template}' => $path)); - - $tpl->loadImports(Path::skipExtension($template) . ".import"); - - $this->addSuggest($tpl, $name); - return $tpl; - } - - public function getModel($name) - { - if (!$this->factory) { - $this->factory = new ModelFactory($this->db, $this->_registry, $this->_shortcut); - } - return $this->factory->getModel($name); - } - - /** - * Выбор действия - * Т.к действия являются методами класса то - * 1. Можно переопределить действия - * 2. Использовать наследование чтобы добавить к старому обработчику новое поведение - * @param $request Обьект запроса - */ - public function execute1(HTTPRequest $request) - { - $action = self::ACTION_PREFIX . ucfirst($request->getAction()); - if (method_exists($this, $action)) { - return $this->forward($action, $request); - } else { - return $this->forward("actionIndex", $request); - } - } - - public function execute(HTTPRequest $request) - { - $result = $this->execute1($request); - if ($result) { - $this->view = $result; - } - return $this->render(); - } - - public function forward($action, HTTPRequest $args) - { - // Действия до вызова основного обработчика - /*foreach($this->_aspect as $aspect) { - if (isset($aspect->before[$action])) { - call_user_func ($aspect->before[$action], $action, $args); - } - }*/ - return call_user_func(array($this, $action), $args); - } - - /** - * Страница по умолчанию - */ - public function actionIndex(HttpRequest $request) - { - return ""; - } - - public function postUrl($name, $param) - { - return "?" . http_build_query( - array_merge(array('module' => strtolower(get_class($this)), "action" => $name), - $this->param, $param)); - } - - /** - * Генерация ссылки c учетом прав пользователя на ссылки - * - * @parma string $name Действие - * @parma string $param Дополнительные параметры - */ - public function nUrl($name, array $param = array()) - { - if (!$this->access || $this->access->checkAction($name)) { - return lcurry(array($this, 'postUrl'), $name, $param); - } - return null; - } - - public function fUrl($name, array $param = array()) - { - return forceUrl($this->nUrl($name, $param)); - } - - /** - * Добавляет параметр для всех ссылок создаваемых функцией nUrl, aUrl - */ - public function addParameter($name, $value) - { - if ($value) { - $this->param [$name] = $value; - } - } - - /** - * Генерация ссылки на действие контроллера - * Ajax определяется автоматически mode = ajax используется для смены layout - */ - public function aUrl($name, array $param = array()) - { - return $this->nUrl($name, array_merge(array('mode' => 'ajax'), $param)); // FIXME - } - - /** - * Добавление помошника контроллера - */ - public function addHelper($class) - { - $this->helpers [] = $class; - } - - /** - * Вызов помошников контроллера - */ - public function callHelpers(HttpRequest $request) - { - $action = self::ACTION_PREFIX . $request->getAction(); - foreach ($this->helpers as $helper) { - if (method_exists($helper, $action)) { - return call_user_func(array($helper, $action), $request, $this); - } else { - return $helper->actionIndex($request, $this); // Вместо return response ??? - } - } - } - - /** - * Загрузка файла класса - */ - public function loadClass($path, $setup = null) - { - if (file_exists($path)) { - require_once ($path); - $class = pathinfo($path, PATHINFO_FILENAME); - return new $class($setup); - } - return null; - } - - public function loadSettings($path) - { - $result = new Settings($path); - $result->read(); - return $result->export(); - } - - // Для Widgets - public $view = null; - public $childNodes = array(); - public $childViews = array(); - - public function setView($name) - { - $this->view = $this->getView($name); - } - - /** - * Установка заголовка для отображения - */ - public function setTitle($title) - { - $this->view->setTitle($title); - } - - /** - * Добавление widget к отображению - */ - public function addChild(/*Widget*/ $section, $node) - { - $this->childNodes[$section] = $node; - } - - /** - * Добавление дочернего отображения к текущему отображению - */ - public function addView(/*CompositeView*/ $section, $node) - { - $this->childViews[$section] = $node; - } - - /** - * Генерация содержания - * Путаница c execute и render - */ - public function render() - { - foreach ($this->childNodes as $name => $node) { - $node->make($this); - $this->view->setView($name, $node->view); - } - foreach ($this->childViews as $name => $node) { - $this->view->setView($name, $node); - } - return $this->view; - } - - function getPageId($request) - { - $pageId = time(); - $request->session()->set('page', $pageId); - return $pageId; - } - - function checkPageId($request, $page) - { - $_page = $request->session()->get('page'); - $result = ($_page && $_page == $page); - $request->session()->clean('page'); - return $result; - } - - function redirect($action) { - header('location: ' . $this->fUrl($action)); - exit(); - } -} - -class Controller_Action extends Controller {} - diff --git a/src/controller/front.php b/src/controller/front.php index c88d74e..badcf43 100644 --- a/src/controller/front.php +++ b/src/controller/front.php @@ -1,30 +1,24 @@ _registry = $_registry; $this->_shortcut = $_shortcut; $this->db = Database::getConnection($registry->readKey(array('system', 'dsn'))); - $this->installer = new Installer($_registry); } @@ -36,8 +30,6 @@ class Controller_Front extends Controller */ public function loadModule($name, Collection $request) { - $this->installer->setUp($this->db, array($this, 'installPath')); - $this->installer->doUpdates($name); // ModuleLoader (1) $moduleFile = Shortcut::getUrl($this->shortcut, $name); // ModuleLoader (2) $module = $this->loadClass($moduleFile); @@ -59,10 +51,10 @@ class Controller_Front extends Controller $module->db = $this->db; // Не для всех приложений нужно вести лог действий // Ведение лога - $logger = $this->loadClass(FRAMEWORK_PATH . '/core/filter/actionlogger.php', $module); + $logger = $this->loadClass(FRAMEWORK_PATH . '/src/filter/actionlogger.php', $module); $logger->before = $this->loadSettings(Shortcut::getUrl('logger', $name)); // Управление доступом - $module->access = $this->loadClass(FRAMEWORK_PATH . '/core/filter/actionaccess.php', $logger); + $module->access = $this->loadClass(FRAMEWORK_PATH . '/src/filter/actionaccess.php', $logger); $module->access->access = $this->loadSettings(Shortcut::getUrl('access', $name)); $module->setUp(); diff --git a/src/controller/model.php b/src/controller/model.php new file mode 100644 index 0000000..9c4dab7 --- /dev/null +++ b/src/controller/model.php @@ -0,0 +1,426 @@ +table->setHeader + */ + public $tableSchema = null; + public /*.array.*/$formSchema = array(); + + public $menu; + public $table; + + protected /*.string.*/$useModel; + protected /*.string.*/$itemModel; + + public function __construct() + { + $this->path = new PathMenu(); + $this->menu = new PageMenu(); + $this->table = new ListTable(); + } + + /** + */ + function setUp() + { + $this->table->addMenuItem($this->aUrl('delete'), 'удалить', false, 'all', 'warning'); + //$this->table->addMenuItem($this->nUrl('form'), 'редактировать', 'edit-24.png'); + } + + function saveParameters($args, $list) + { + foreach ($list as $item) { + $args->session()->set(array($this, $item), $args->get($item)); + } + } + + protected function getJSONList(/*Mapper*/ $model, Collection $request) + { + $result = array(); + $this->saveParameters($request, array('size','page','desc', 'key')); + + $result['list'] = $model->findAll($request, $request->get('ref')); + $result['size'] = $model->getCount($request, $request->get('ref')); + return json::encode($result); + } + + /** + * Удаление сторк из таблицы + */ + public function actionDelete(HttpRequest $request) + { + $model = $this->getModel($this->useModel); + // Почему table_item ??? + $list = ($request->get('table_item')) ? $request->get('table_item'): $request->get('id'); + $model->deleteList($list); + + return $this->getJSONList($model, $request); + } + + /** + * Ответ на запрос по поиску + */ + public function actionSearch(HttpRequest $request) + { + $model = $this->getModel($this->useModel); + $model->addFilter($model->requestToSQL($request, $this->formSchema)); + + return $this->getJSONList($model, $request); + } + + /** + * Список элементов + */ + public function actionList(HttpRequest $request) + { + $model = $this->getModel($this->useModel); + return $this->getJSONList($model, $request); + } + + + private function setFormSchema() + { + require_once 'core/mapper/uimapper.php'; + + $model = $this->getModel($this->useModel); + $ui = new UIMapper($model); + + $this->formSchema = $ui->getFormSchema(); + } + + /** + * Сохранение формы + */ + function beforeSave(/*Model*/ $item, Collection $request) + { + if (empty($this->formSchema)) { + $this->setFormSchema(); + } + // Сделать отображение Формы в обьект и обратно <-- Убрать в beforeSave + foreach ($this->formSchema as $key => $conv) { + list($value, $type) = $conv; + $item->$value = call_user_func(array('Cast', 'to_' . $type), $request->get($key)); // Здесть нужно преобразовывать тип значения + } + } + + /** + * Обновление формы + */ + function formUpdate(TForm $form, Collection $request) + { + } + + /** + * Загрузка формы + */ + function beforeLoad(/*Model*/ $item, TForm $form) + { + if (empty($this->formSchema)) { + $this->setFormSchema(); + } + // Вставка значений из данных в форму + // Отображение обьекта в поля формы + $form->fill($item, $this->formSchema); + } + + // Проверка ввода + protected function validate($validator, $request) + { + } + + /** + * Действие для проверки формы + */ + public function actionValidate($request) + { + require_once "core/validator/validator.php"; + $validator = new Validator(); + $validator->addRuleList($this->schema); + + // Действия до проверки формы + $this->validate($validator, $request); // <--| + $validator->validate($request); // --| + // Проверка формы + if (!$validator->isValid()) { + return json::encode($validator->getErrorMsg()); + } + return json::encode(true); + } + + /** + * Инициализация формы + */ + protected function formSetup($form, $id = null, $ref = null) + { + if (empty($this->schema)) { + $model = $this->getModel($this->useModel); + $ui = new UIMapper($model); + $schema = $ui->getEditSchema(); + + $form->addFieldList($schema); + } else { + $form->addFieldList($this->schema); + } + } + + /** + * Добавление пользователя + */ + public function actionAdd(HttpRequest $request) + { + require_once "core/validator/validator.php"; + // {{{ тоже может быть один ref или несколько + $ref = $request->get('ref'); + $this->addParameter('ref', $ref); // Добавляет параметр в url + /// }}} + + if ($this->checkPageId($request, $request->get('page'))) { + // Проверка + $validator = new Validator(); + $validator->addRuleList($this->schema); + + // Действия до проверки формы + $this->validate($validator, $request); // <--| + $validator->validate($request); // --| + // Проверка формы + if (!$validator->isValid()) { + $request->setAction('form'); + $this->getActionPath($request); + + $form = new TForm(); + $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы + + $form->setValues($request); // <-- Убрать в formUpdate + $this->formUpdate($form, $request); + + $form->setError($validator); // Установка ошибок для формы + + $tpl = $this->formPage($form, $request); + $id = $request->get('id'); + if ($id) { // Редактирование + $tpl->action = forceUrl($this->nUrl('add', array('id' => $id, 'page' => $this->getPageId($request)))); // action Совйство формы + } + return $tpl /*->execute()*/; + } + + // Нужен тест для формы + $model = $this->getModel($this->useModel); + $className = $model->className; + $item = new $className(); + + // Сохраняем значение в базе данных + $item->id = $request->get('id'); + // Если таблица связана с другой таблицей + if ($request->get('ref') && $model->reference[1]) { + $ref_id = $model->reference[1]; + $item->$ref_id = $request->get('ref'); + } + + // Подготовка к сохранению + $this->beforeSave($item, $request); // Сюдаже и истрия переходов + // nextId ??? или выход или новая форма для создания новости + $model->saveDB($item, $request); + } + + // Для страницы со списком id -> идентефикатор родительской таблицы !!?? +// $request->set('id', $request->get('ref')); + if ($request->get('apply')) { + $request->setAction('form'); + return $this->forward('actionForm', $request); + } + return $this->forward('actionIndex', $request); + } + + /** + * Заголовок + */ + private function setTitlePath($ref) + { + if ($ref) { + $model = $this->getModel($this->useModel); + if (is_array($model->reference) && $model->reference[0]) { + $refmodel = $this->getModel($model->reference[0]); + try { + $parent = $refmodel->findById($ref); + $this->path->addTitle($parent->getTitle()); // Заголовок к подписям путей + } catch (Exception $e) { + // Не найден заголовок потому что неправильно определен родительский элемент + } + } + } + } + + /** + * Форма для редактирования + */ + public function actionForm(HttpRequest $request) + { + $this->getActionPath($request); + $ref = $request->get('ref'); + $this->addParameter('ref', $ref); // Добавляет параметр в url + $this->setTitlePath($ref); + + $model = $this->getModel($this->useModel); + $form = new TForm(); // Показываем форму + $form->header = 'Редактирование записи'; + $this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы + + $list = $request->get('table_item'); + $id = ($list[0]) ? $list[0] : $request->get('id'); + + $tpl = $this->formPage ($form, $request); + if ($id) { // Редактирование + $form->action = forceUrl($this->nUrl('add', array('id' => $id, 'page' => $this->getPageId($request)))); // action Свойство формы + $item = $model->findById($id); + // Загрузка формы + $this->beforeLoad($item, $form); + /// + } + return $tpl; + } + + /** + */ + function tableSetup($table, $id = null, $ref = null) + { + // FIXME: После замены везде $tableSchema -> table->setHeader удалить! + if ($this->tableSchema) { + $table->setHeader($this->tableSchema); + } else { + // Настройка таблицы отображения по схеме данных + require_once 'core/mapper/uimapper.php'; + $model = $this->getModel($this->useModel); + $ui = new UIMapper($model); + $schema = $ui->getTableSchema(); + $schema[0]['action'] = $table->getFirstItem(); + + $table->setHeader($schema); + } + } + + /** + */ + public function actionIndex(HttpRequest $request) + { + $this->getActionPath($request, 'index'); + // Такое мета действие наверное можно вынести в отдельный класс + return $this->metaActionIndex($request, array($this, 'tableSetup'), $this->aUrl('list')); + } + + /** + * Страница по умолчанию + */ + public function metaActionIndex(HttpRequest $request, $setup, $list) + { + // может быть одно ref или несколько + // {{{ история переходов + $ref = null; + if ($request->get('ref')) { + $ref = $request->get('ref'); + } else if ($request->session()->get('ref')) { + $ref = $request->session()->get('ref'); + } + + $request->session->set('ref', $ref); + $this->addParameter('ref', $ref); + // }}} + $this->setTitlePath($ref); + + $tpl = $this->getView('list'); + + // Помошники действий + $this->callHelpers($request); + // Таблица + if ($request->session()->get(strtolower(get_class($this)))) { + $session = $request->session()->get(strtolower(get_class($this))); + if (isset($session['view'])) { + $this->table->setView($session['view']); + } + $this->table->setData('state', array( + 'page' => $session['page'], + 'size' => $session['size'], + 'desc' => $session['desc'])); + + $this->table->setData('sorter', $session['key']); + if (isset($session['desc'])) { + $this->table->setData('desc', $session['desc']); + } + } + + call_user_func($setup, $this->table, $request->get('id'), $ref);// --> Эквивалент formSetup + $this->table->setAction($list); + // + $tpl->menu_path = $this->path->getItems(); + + // Поиск + $search = new SearchDialog(); + $search->setTitle('Поиск'); + $search->setAction($this->aUrl('search')); + $search->setFriend($this->table); + $search->addFields($this->schemaSearch); + + // Настройки + $setup = new SetupDialog(); + $setup->setTitle('Настройки'); + $setup->setAction($this->nUrl('setup')); + $setup->setFriend($this->table); + + // Меню + $this->menu->addMenuItem('?menu=toggle&id=' . $search->getName(), 'поиск', 'actions/system-search'); // Стандартный размер для иконок 22-24px + $this->menu->addMenuItem('?menu=toggle&id=' . $setup->getName(), 'настройки', 'categories/applications-system'); + // Добавление компонентов + $this->addChild('menu', $this->menu); + $this->addChild('search', $search); + $this->addChild('setup', $setup); + $this->addChild('table', $this->table); + // + return $tpl; + } + + /** + */ + public function actionSetup($request) + { + $left = explode(",", $request->get('left')); + $right = explode(",", $request->get('right')); + + $$request->session()->set(strtolower(get_class($this)), + array('view' => array('left' => $left, 'right' => $right))); + + return $this->forward('actionIndex', $request); + } + + /** + */ + private function formPage($form, $request) + { + $view = $this->getView('form'); + $view->setView('form', $form); + $view->action = forceUrl($this->nUrl('add', array('page' => $this->getPageId($request)))); // Действие для формы + + $view->menu_path = $this->path->getItems(); + $view->back = $this->path->getPrev(); + return $view; + } + + // Тоже убрать в метод Controller_Model + function getActionPath(HttpRequest $request/*, $action = false*/) + { + require_once 'state.php'; + $this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction()); + } +} diff --git a/src/controller/state.php b/src/controller/state.php index 00db7f0..aafff35 100644 --- a/src/controller/state.php +++ b/src/controller/state.php @@ -13,7 +13,7 @@ class Controller_State static function make($action) { - return new State($action); + return new Controller_State($action); } public function addTitle($name, $url = array()) @@ -22,7 +22,7 @@ class Controller_State return $this; } - public function addState(State $state) + public function addState(Controller_State $state) { $this->states [$state->getAction()] = $state; return $this; @@ -49,7 +49,7 @@ class Controller_State return false; } - function makeTitle($module) + function makeTitle(Controller_Action $module) { foreach ($this->titles as $item) { $module->path->addMenuItem($module->nUrl($this->action, $item[1]), $item[0]); @@ -68,12 +68,3 @@ class Controller_State } } } - - -/* -$path = State::make('index') - ->addState(State::make('form')) - ->addState(State::make('view')); - -$path->getPath(0, 'form'); -*/ diff --git a/src/filter/actionlogger.php b/src/filter/actionlogger.php index fce3ef5..c92d37c 100644 --- a/src/filter/actionlogger.php +++ b/src/filter/actionlogger.php @@ -1,7 +1,5 @@ getConnection(); - UserAccess::setUp($db); // Соединение + Filter_UserAccess::setUp($db); // Соединение switch ($request->getAction()) { // Авторизация по постоянному паролю case 'login': $login = $request->get('login'); $password = $request->get('password'); - $result = UserAccess::getUserByLogin($login); // Поиск по логину + $result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину if ($result) { if (md5($password) == $result->getString('password')) { // password $this->enter($db, $result); diff --git a/src/filter/useraccess.php b/src/filter/useraccess.php index 126b21d..8fac5e0 100644 --- a/src/filter/useraccess.php +++ b/src/filter/useraccess.php @@ -1,10 +1,7 @@ {$key}; + } + return $result; +} + function assoc_key_values($key, $value, $array) { $result = array(); foreach ($array as $item) { @@ -245,7 +254,7 @@ function assoc_key($key, $array) { return $result; } -function _get($key, $value, $array) { +function _get($key, /*.any.*/$value, /*.array.*/$array) { foreach ($array as $item) { if ($item[$key] == $value) return $item; } @@ -265,7 +274,7 @@ function _get_key($key, $value, $array) { * @return bool */ function every(array $array, $callback) { - foreach ($array as $key => $value) { + foreach ($array as $value) { if (call_user_func($callback, $value) === false) { return false; } @@ -337,10 +346,33 @@ if (!function_exists('hash_key')) { }; } -function array_merge1($x, $y) { - $result = $x; - foreach ($y as $k => $v) { - $result [$k] = $v; +/** + * Выбирает все сроки из таблицы с уникальными значениями ключа + * @param $name Имя ключа + * @param $table Двухмерный массив + * @example + * key_unique_values ('name', array (array ('name' => 1), array ('name' => 2), array ('name' => 1))) + => array (1, 2) + * @end example + */ +function key_unique_values ($name, $table) { + // Ищем уникальные значения для заданного ключа + $keys = array (); + foreach ($table as $row) { + if (!in_array ($row[$name], $keys)) + $keys[] = $row[$name]; } - return $result; + return $keys; +} + +/** + * Сортировка двумерного массива по заданному ключу + * @param $array Массив + * @param $key Имя ключа по значению которого будет идти сравнение + * @return Отсортированный массив + */ +function sortOn($array, $key, $fn = '__cmp') { + usort ($array, rcurry($fn, $key)); + //usort ($array, create_function ('$x,$y', 'return __cmp ($x, $y, "'.$key.'");')); + return $array; } diff --git a/src/httprequest.php b/src/httprequest.php index 836cc89..7693177 100644 --- a/src/httprequest.php +++ b/src/httprequest.php @@ -10,6 +10,8 @@ class WrongRequestException extends Exception // HTTPRequest = ArrayAccess class HttpRequest extends Collection implements ArrayAccess { + + public $_session; /** * Constructor * Stores "request data" in GPC order. @@ -24,9 +26,8 @@ class HttpRequest extends Collection implements ArrayAccess $ajax = $this->isAjax(); foreach ($list as $key => $value) { - $data = new SafeCollection(); + $data = new Collection(); $data->import($value); - parent::set($key, $data); } @@ -35,50 +36,32 @@ class HttpRequest extends Collection implements ArrayAccess parent::set('files', $data); } - function get($key, $default = null) - { - return parent::get('data')->get($key, $default); - } - - function session($value = false) - { - if ($value) { - $this->session = $value; - } - return $this->session; - } - - function set($key, $value) - { - return parent::get('data')->set($key, $value); - } - - function _get($key) { return parent::get($key); } - function export() + function get($key, $default = null) { - return parent::get('data')->export(); + return parent::get('data')->get($key, $default); + } + + function session(Session $value = null) + { + if ($value) { + $this->_session = $value; + } + return $this->_session; } - /* Array Acces Interface */ - function offsetExists($offset) + function set($key, /*.any.*/$value) { + return parent::get('data')->set($key, $value); } - function offsetGet($offset) - { - } - - function offsetSet($offset, $value) - { - } - - function offsetUnset($offset) + function export($key = 'data') { + return parent::get($key)->export(); } function clear() @@ -125,4 +108,22 @@ class HttpRequest extends Collection implements ArrayAccess { return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'); } + + public function redirect($url) { + header('location: ' . $url); + exit(); + } + + + public function offsetSet($key, $value) { + } + + public function offsetExists($key) { + } + + public function offsetUnset($key) { + } + + public function offsetGet($key) { + } } diff --git a/src/layout/layout.php b/src/layout/manager.php similarity index 82% rename from src/layout/layout.php rename to src/layout/manager.php index 7c13029..5107e36 100644 --- a/src/layout/layout.php +++ b/src/layout/manager.php @@ -1,13 +1,13 @@ 'personal'), 'personal') * addConditionGet(array('module' => 'login'), 'login') */ - public function addConditionGet($get, Filter $layout) + public function addConditionGet($get, Filter_Filter $layout) { $this->addCondition(rcurry(array($this, 'checkGet'), $get), $layout); } @@ -28,7 +28,7 @@ class LayoutManager extends Filter /** * Условие для аякс запросов. Тоже самое что и addConditionGet но еще проверяется является ли запрос ajax */ - public function addConditionXHR($get, Filter $layout) + public function addConditionXHR($get, Filter_Filter $layout) { $this->addCondition(rcurry(array($this, 'checkXHR'), $get), $layout); } @@ -51,11 +51,11 @@ class LayoutManager extends Filter } /** - * Добавляет есловие в общем виде + * Добавляет условие в общем виде * @parma $get function(HttpRequest) Функция * @parma $layout Layout Макет */ - public function addCondition($get, Filter $layout) + public function addCondition($get, Filter_Filter $layout) { $this->condition [] = array($get, $layout); } @@ -81,13 +81,3 @@ class LayoutManager extends Filter } } -/** - * Самый простой макет - */ -class LayoutNone extends Filter -{ - function execute(HttpRequest $request) - { - return $this->processor->execute($request); - } -} diff --git a/src/layout/none.php b/src/layout/none.php new file mode 100644 index 0000000..ed02085 --- /dev/null +++ b/src/layout/none.php @@ -0,0 +1,11 @@ +processor->execute($request); + } +} diff --git a/src/mail.php b/src/mail.php index 3bd2ef1..c1de6fe 100644 --- a/src/mail.php +++ b/src/mail.php @@ -6,14 +6,14 @@ */ class Mail { - public $from; - public $to; - public $subject; + public $_from; + public $_to; + public $_subject; public $content; public $copy; private $encoding; - private $notify= false; + private $_notify = null; protected $attachment = array (); protected $uniqid; @@ -22,8 +22,6 @@ class Mail function __construct() { $this->setEncoding("UTF-8"); $this->uniqid = strtoupper(uniqid(time())); // Идентефикатор разделителя - -// $this->mime } /** @@ -31,7 +29,7 @@ class Mail */ function from($name) { - $this->from = $name; + $this->_from = $name; } /** @@ -39,7 +37,7 @@ class Mail */ function to($name) // recipient { - $this->to = $name; + $this->_to = $name; } /** @@ -52,7 +50,7 @@ class Mail function notify($notify) { - $this->notify = $notify; + $this->_notify = $notify; } /** @@ -60,7 +58,7 @@ class Mail */ function subject($subject) { - $this->subject = $subject; + $this->_subject = $subject; } /** @@ -70,12 +68,7 @@ class Mail { $this->content = $text; } - - function setType($type) - { - $this->type = $type; - } - + /** * Кодировка текста в письме */ @@ -93,11 +86,18 @@ class Mail if(file_exists($filename)) { // assert ?? $file = fopen($filename, "rb"); - $data = fread($file, filesize($filename)); - $this->attachment [] = ($name) ? array($data, $name) : array($data, basename($filename)); + if (is_resource($file)) { + $data = fread($file, filesize($filename)); + $this->attachment [] = ($name) ? array($data, $name) : array($data, basename($filename)); + } } } + function setType($type) + { + $this->type = $type; + } + /** * Добавление вложения из строки с указанием имени файла */ @@ -115,7 +115,7 @@ class Mail /** * Общий формат тегов MIME - * http://tools.ietf.org/html/rfc2045 + * @see http://tools.ietf.org/html/rfc2045 */ function mimeTag($name, $value, array $args = array()) { @@ -127,7 +127,7 @@ class Mail /** * - * http://tools.ietf.org/html/rfc2047 + * @see http://tools.ietf.org/html/rfc2047 */ function encodedWord($text, $encoding = 'B') { @@ -144,16 +144,16 @@ class Mail $message .= $this->mimeTag("Content-Transfer-Encoding", "8bit"); $message .= PHP_EOL . $this->content . PHP_EOL . PHP_EOL; - /** + /* * Вложения * http://tools.ietf.org/html/rfc2046#section-5.1.3 */ foreach ($this->attachment as $value) { list($data, $name) = $value; $message .= "--" . $this->uniqid . PHP_EOL; - $message .= $this->mimeTag("Content-Type", "application/octet-stream", array ('name' => $name)); + $message .= $this->mimeTag("Content-Type", "application/octet-stream", array ('name' => basename($name))); $message .= $this->mimeTag("Content-Transfer-Encoding", "base64"); - $message .= $this->mimeTag("Content-Disposition", "attachment", array ('filename' => $name)); + $message .= $this->mimeTag("Content-Disposition", "attachment", array ('filename' => basename($name))); $message .= PHP_EOL . chunk_split(base64_encode($data)) . PHP_EOL; } @@ -166,11 +166,11 @@ class Mail function getHeader() { $head = $this->mimeTag("MIME-Version", "1.0"); - $head .= $this->mimeTag("From", $this->from); - $head .= $this->mimeTag("X-Mailer", "CIS Tool"); - $head .= $this->mimeTag("Reply-To", $this->from); - if ($this->notify) { - $head .= $this->mimeTag("Disposition-Notification-To", "\"" . $this->notify . "\" <" . $this->from . ">"); + $head .= $this->mimeTag("From", $this->_from); + $head .= $this->mimeTag("X-Mailer", "CMS Tool"); + $head .= $this->mimeTag("Reply-To", $this->_from); + if (is_string($this->_notify)) { + $head .= $this->mimeTag("Disposition-Notification-To", "\"" . $this->_notify . "\" <" . $this->_from . ">"); } $head .= $this->mimeTag("Content-Type", "multipart/mixed", array ("boundary" => $this->uniqid)); if ($this->copy) { @@ -182,7 +182,7 @@ class Mail function getSubject() { - return $this->encodedWord($this->subject); + return $this->encodedWord($this->_subject); } /** @@ -190,7 +190,7 @@ class Mail */ function eml() { - return "To: " . $this->to . PHP_EOL . "Subject: {$this->getSubject()}" . PHP_EOL . $this->getHeader() . $this->getMessage(); + return "To: " . $this->_to . PHP_EOL . "Subject: {$this->getSubject()}" . PHP_EOL . $this->getHeader() . $this->getMessage(); } /** @@ -198,7 +198,7 @@ class Mail */ function send() { - $result = mail($this->to, $this->getSubject(), $this->getMessage(), $this->getHeader()); + $result = mail($this->_to, $this->getSubject(), $this->getMessage(), $this->getHeader()); if(! $result) { throw new Exception('Невозможно отправить почту'); // require_once "core/path.php"; diff --git a/src/markup/simple_bb_code.php b/src/markup/simplebbcode.php similarity index 97% rename from src/markup/simple_bb_code.php rename to src/markup/simplebbcode.php index 3bb16f3..b21a845 100644 --- a/src/markup/simple_bb_code.php +++ b/src/markup/simplebbcode.php @@ -20,7 +20,7 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **/ -class Simple_BB_Code{ +class Markup_SimpleBBCode{ //General Tags var $tags = array('b' => 'strong','i' => 'em','u' => 'span style="text-decoration:underline"','quote' => 'blockquote','s' => 'span style="text-decoration: line-through"', 'list' => 'ul','\*' => 'li'); //Tags that must be mapped to diffierent parts @@ -38,7 +38,7 @@ class Simple_BB_Code{ var $auto_links = true; //Internal Storage var $_code = ''; - function Simple_BB_Code($new=true,$parse=true,$links=true){ + function __construct($new=true,$parse=true,$links=true){ $this->convert_newlines = $new; $this->parse_smilies = $parse; $this->auto_links = $links; diff --git a/src/numbers.php b/src/numbers.php index bd0adea..c0a39c7 100644 --- a/src/numbers.php +++ b/src/numbers.php @@ -12,7 +12,7 @@ class Numbers return $i; } - static function prefix($prefix, array $array) + static function prefix($prefix, array $array, $key = false) { $result = array(); for ($i = 0; $i < count($array); $i++) { diff --git a/src/path.php b/src/path.php index 70e83c0..1a74881 100644 --- a/src/path.php +++ b/src/path.php @@ -1,33 +1,58 @@ path = $this->fromString($path); - $this->optimize(); - } + $this->url = parse_url($path); + + if (isset($this->url['path'])) { + $path = $this->url['path']; +// $path = preg_replace('/\/{2,}/', '/', $path); + $this->path = self::optimize($this->fromString($path)); + } + } static function factory($path) { return new Path($path); } + public function getParts() + { + return $this->path; + } + + public static function normalize($pathName) + { + $path = new Path($pathName); + return $path->__toString(); + } + + /** + * Базовое имя + * @param $path + * @return mixed + */ + public static function basename($path) + { + $list = preg_split('#\\\\|/#s', $path); + return end($list); + } + /** * Возвращает расширение файла * @@ -35,13 +60,22 @@ class Path * * @return string */ - static function getExtension ($fileName) + static function getExtension($fileName) { - assert(is_string($fileName)); + assert(is_string($fileName) || is_null($fileName)); return pathinfo($fileName, PATHINFO_EXTENSION); } + static function isType($fileName, $extension) + { + if (is_array($extension)) { + return in_array(pathinfo($fileName, PATHINFO_EXTENSION), $extension); + } else { + return (pathinfo($fileName, PATHINFO_EXTENSION) == $extension); + } + } + /** * Полное имя файла без расширения * @@ -49,7 +83,7 @@ class Path * * @return string */ - static function skipExtension ($fileName) + static function skipExtension($fileName) { assert(is_string($fileName)); @@ -68,118 +102,13 @@ class Path * * @return string */ - static function getFileName ($fileName) + static function getFileName($fileName) { assert(is_string($fileName)); return pathinfo($fileName, PATHINFO_FILENAME); } - /** - * Список файлов в директории - * - * @param array $allow массив расширений для файлов - * @param array $ignore массив имен пааок которые не нужно обрабатывать - * - * @return array - */ - public function getContent ($allow = null, $ignore = array()) - { - $ignore = array_merge(array (".", "..", $ignore)); - return self::fileList($this->__toString(), $allow, $ignore); - } - - // Использовать SPL ??? - protected function fileList ($base, &$allow, &$ignore) - { - $result = array (); - if ($handle = opendir($base)) { - while (false !== ($file = readdir($handle))) { - if (! in_array ($file, $ignore)) { - $isDir = is_dir (Path::join ($base, $file)); - if ($isDir || ($allow == null) || in_array (self::getExtension($file), $allow)) { - $result[] = $file; - } - } - } - closedir($handle); - } - return $result; - } - - protected function fileListAll (&$result, $base, &$allow, &$ignore) - { - $files = self::fileList($base, $allow, $ignore); - foreach ($files as $name) { - $fullname = self::join($base, $name); - if (is_dir($fullname)) { - self::fileListAll($result, $fullname, $allow, $ignore); - } else { - array_push ($result, $fullname); - } - } - } - - /** - * Список файлов в директориии и ее поддиректорий - * - * @param array $allow массив расширений разрешеных для файлов - * @param array $ignore массив имен пааок которые не нужно обрабатывать - * - * @return array - */ - function getContentRec ($allow = null, $ignore = array()) - { - $result = array (); - $ignore = array_merge(array (".", ".."), $ignore); - self::fileListAll($result, $this->__toString(), $allow, $ignore); - return $result; - } - - - /** - * Рекурсивно копирует директорию - * - * @param string $source Папка из которой копируется - * @param string $target Папка в которую копируется - */ - public static function copy ($source, $target) - { - if (is_dir($source)) { - if (! file_exists($target)) mkdir ($target); - $path = new Path($source); - $files = $path->getContent(); - foreach ($files as $file) { - $entry = self::join($source, $file); - if (is_dir($entry)) { - self::copy($entry, Path::join($target, $file)); - } else { - copy($entry, Path::join($target, $file)); - } - } - } - } - - /** - * Рекурсивно удаляет директорию - * - * @param string $path Папка - */ - public static function delete ($path) - { - assert(is_string($path)); - - if (is_dir($path)) { - foreach(glob($path . '/*') as $sf) { - if (is_dir($sf) && !is_link($sf)) { - self::delete($sf); - } else { - unlink($sf); - } - } - rmdir($path); - } - } /** * Преобразует строку путя в массив @@ -192,28 +121,60 @@ class Path { assert(is_string($path)); - $list = preg_split("/[\/\\\\]/", $path); + $list = preg_split('#\\\\|/#s', $path); + if (isset($this->url['scheme']) && !isset($this->url['host'])) { + $this->absolute = false; + } else if ($list[0] == '' && count($list) > 1) { + $this->absolute = true; + } + return $list; } /** * Преобразует относительный путь в абсолютный */ - public function optimize () + public static function optimize($path) // { - $result = array(current($this->path)); - while (next($this->path) !== false) { - $n = current ($this->path); + $result = array(); + foreach ($path as $n) { switch ($n) { + // Может быть относительным или абсолютным путем case "": break; case ".": break; - case "..": if (count($result) > 0) array_pop($result); break; + case "..": + if (count($result) > 0) { array_pop($result); break; } default: array_push($result, $n); } - } - reset($this->path); - $this->path = $result; + } + return $result; + } + + // Сравнение двух путей на равентство + public function equal(/*.Path.*/ $path) + { + if (count($this->path) == count($path->path)) { + for ($i = 0; $i < count($this->path); $i++) { + if ($this->path[$i] != $path->path[$i]) { + return false; + } + } + return true; + } + return false; + } + + public static function makeUrl($path) + { + return (isset($path['scheme']) ? $path['scheme'] . ':/' : '') + . (isset($path['host']) ? ('/' + . (isset($path['user']) ? $path['user'] . (isset($path['pass']) ? ':' . $path['pass'] : '') . '@' : '') + . $path['host'] + . (isset($path['port']) ? ':' . $path['port'] : '')) : '') + . $path['path'] + . (isset($path['query']) ? '?' . $path['query'] : '') + . (isset($path['fragment']) ? '#' . $path['fragment'] : ''); } /** @@ -221,10 +182,11 @@ class Path * * @return string */ - public function __toString () + public function __toString() { - $result = implode($this->path, self::SEPARATOR); - return $result; + $result = (($this->absolute) ? '/' : '') . implode(self::SEPARATOR, $this->path); + $this->url['path'] = $result; + return self::makeUrl($this->url); } /** @@ -234,8 +196,11 @@ class Path * * @return boolean */ - public function isParent ($path) + public function isParent(/*.Path.*/ $path) { + if (isset($this->url['host']) && isset($path->url['host']) + && ($this->url['host'] != $path->url['host'])) return false; + if (count($path->path) > count($this->path)) { for ($i = 0; $i < count($this->path); $i++) { if ($path->path[$i] != $this->path[$i]) { @@ -246,6 +211,12 @@ class Path } return false; } + + public static function _isParent($path1, $path2) + { + $path = new Path($path1); + return $path->isParent(new Path($path2)); + } /** * Находит путь относительно текущего путя @@ -254,34 +225,97 @@ class Path * * @return string Относительный путь к файлу */ - public function relPath ($name) + public function relPath($name) { - $path = new Path ($name); + $path = new Path($name); + unset($path->url['scheme']); +// $this->absolute = false; + $path->absolute = false; foreach ($this->path as $n) { array_shift($path->path); } return $path->__toString(); } - public function append ($path) + // Вычисляет относительный путь в виде строки + static function relative($rpath, $lpath) { + // Нужно проверять диск!! + $self = new Path($rpath); + $list = new Path($lpath); + $self_path = $self->getParts(); + $list_path = $list->getParts(); + + $result = array(); + for ($i = 0; $i < count($list_path); $i++) { + if (($i >= count($self_path)) || $list_path[$i] != $self_path[$i]) { + break; + } + } + for($j = $i; $j < count($list_path); $j++) { + array_push($result, '..'); + } + for($j = $i; $j < count($self_path); $j++) { + array_push($result, $self_path[$j]); + } + return implode("/", $result); + } + + public function append($path) { $base = $this->__toString(); return self::join($base, $path); - } + } + /** - * Создает недастающие папки для записи файла - * - * @param string $dst Полное имя файла - * - * @return void + * Обьединяет строки в путь соединяя необходимым разделителем + * fixme не обрабатывает параметры урла, решение Path::join(SITE_WWW_PATH) . '?param=pampam' + * @return string */ - static function prepare ($dst) + static function join($_rest) { - $path_dst = pathinfo($dst, PATHINFO_DIRNAME); - if (! file_exists($path_dst)) { - mkdir($path_dst, 0700, true); + $args = func_get_args(); + $result = array(); + $parts0 = new Path(array_shift($args)); + $result [] = $parts0->getParts(); + foreach ($args as $file) { + $parts = new Path($file); + $result [] = $parts->getParts(); } + // При обьединении ссылок можно обьеденить path, query, fragment + $path = implode(self::SEPARATOR, call_user_func_array('array_merge', $result)); + $parts0->url['path'] = ($parts0->isAbsolute()) ? '/' . $path : $path; + return self::makeUrl($parts0->url); + } + + // Проверка структуры имени файла + static function checkName($name, $extension) + { + return (strlen(pathinfo($name, PATHINFO_FILENAME)) > 0) && (pathinfo($name, PATHINFO_EXTENSION) == $extension); + } + + static function isCharName($char) + { + $ch = ord($char); + return ((($ch >= ord('a')) && ($ch <= ord('z'))) || (strpos('-._', $char) !== false) || (($ch >= ord('0')) && ($ch <= ord('9')))); + } + + // Проверка имени файла + static function isName($name) { + if (strlen(trim($name)) == 0) { + return false; + } + for ($i = 0; $i < strlen($name); $i++) { + if (!self::isCharName($name[$i])) { + return false; + } + } + return true; + } + + public function isAbsolute() + { + return $this->absolute; } /** @@ -291,7 +325,7 @@ class Path * * @return string Новое имя файла */ - static function resolveFile ($dst) + static function resolveFile($dst) { $i = 0; $file = self::skipExtension($dst); @@ -304,14 +338,93 @@ class Path return $temp; } + + /** + * Список файлов в директории + * + * @param array $allow массив расширений для файлов + * @param array $ignore массив имен пааок которые не нужно обрабатывать + * + * @returnarray + */ + public function getContent($allow = null, $ignore = array()) + { + $ignore = array_merge(array(".", ".."), $ignore); + return self::fileList($this->__toString(), $allow, $ignore); + } + /** * Обьединяет строки в путь соединяя необходимым разделителем * - * @return string - */ - static function join () + * @param array $allow массив расширений разрешеных для файлов + * @param array $ignore массив имен пааок которые не нужно обрабатывать + * + * @return array + */ + function getContentRec($allow = null, $ignore = array()) { - $args = func_get_args(); - return implode(self::SEPARATOR, $args); + $result = array (); + $ignore = array_merge(array (".", ".."), $ignore); + self::fileListAll($result, $this->__toString(), $allow, $ignore); + return $result; + } + + // Использовать SPL ??? + protected static function fileList($base, &$allow, &$ignore) + { + if ($base == '') $base = '.'; + $result = array (); + $handle = opendir($base); + if (is_resource($handle)) { + while (true) { + $file = readdir($handle); + if (is_string($file)) { + if (! in_array($file, $ignore)) { + $isDir = is_dir(Path::join($base, $file)); + if ($isDir || ($allow == null) || in_array(self::getExtension($file), $allow)) { + $result[] = $file; + } + } + continue; + } + break; + } + closedir($handle); + } + // При обьединении ссылок можно обьеденить path, query, fragment + return $result; + } + + protected static function fileListAll(&$result, $base, &$allow, &$ignore) + { + $files = self::fileList($base, $allow, $ignore); + foreach ($files as $name) { + $fullname = self::join($base, $name); + if (is_dir($fullname)) { + self::fileListAll($result, $fullname, $allow, $ignore); + } else { + array_push($result, $fullname); + } + } + } + + /** + * Создает недастающие папки для записи файла + * + * @param string $dst Полное имя файла + * + * @return void + */ + static function prepare($dst, $filename = true) + { + if ($filename) { + $path_dst = pathinfo($dst, PATHINFO_DIRNAME); + } else { + $path_dst = $dst; + } + if (! file_exists($path_dst)) { + mkdir($path_dst, 0777, true); + } } } + diff --git a/src/registry.php b/src/registry.php index 862a3d4..f2b7673 100644 --- a/src/registry.php +++ b/src/registry.php @@ -1,5 +1,7 @@ + /** * http://www.patternsforphp.com/wiki/Registry * http://www.patternsforphp.com/wiki/Singleton diff --git a/src/session.php b/src/session.php index 2d2b666..43ec665 100644 --- a/src/session.php +++ b/src/session.php @@ -26,7 +26,7 @@ class Session function start() { - session_start(); + @session_start(); } function stop() diff --git a/src/settings.php b/src/settings.php index 3566c89..ee1fc2d 100644 --- a/src/settings.php +++ b/src/settings.php @@ -12,23 +12,31 @@ class Settings extends Collection { protected $file; + protected $format = 'php'; + public function __construct ($file = null) { + $this->format = pathinfo($file, PATHINFO_EXTENSION); $this->file = $file; } /** * Чтение настроек из файла - * - * @param File $file - * * @return Boolean */ public function read() { - if ( !file_exists ($this->file)) return false; + if (!file_exists ($this->file)) { + return false; + } // Не include_once т.к читать настройки можно несколько раз - include($this->file); + $settings = array(); + if ($this->format == 'json') { + $settings = json_decode(file_get_contents($this->file), true); + } else { + include ($this->file); + } + if (!is_array($settings)) { throw new Exception($this->file); } @@ -51,7 +59,9 @@ class Settings extends Collection // assert(count($key) == 1); $name = array_shift($key); if (is_array($value)) { - if (! isset($data[$name])) $data[$name] = array(); + if (!isset($data[$name])) { + $data[$name] = array(); + } $this->merge($data[$name], $value); } else { $data[$name] = $value; @@ -107,7 +117,7 @@ class Settings extends Collection * Чтение ключа из реестра (Собирает все ключи с определенным значением во всех модулях) * @param $key Путь к значению ключа внутри модуля */ - public function readKeyList() + public function readKeyList($_rest) { $key = func_get_args(); $result = array(); @@ -149,10 +159,15 @@ class Settings extends Collection * * @return void */ - public function write($file = false) + public function write($file = null) { - $result = var_export ($this->data, true); - file_put_contents (($file) ? $file : $this->file, ""); + if ($this->format == 'json') { + $result = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + } else { + $result = var_export($this->data, true); + $result = ""; + } + file_put_contents (($file) ? $file : $this->file, $result); } /** diff --git a/src/setup.php b/src/setup.php index a925103..c3c754c 100644 --- a/src/setup.php +++ b/src/setup.php @@ -1,54 +1,212 @@ + * $setup = new Setup('test.xml'); + * $setup->set('target', 'dst'); + * $setup->executeActions('install'); + * + */ class Setup { - /** - * Содержимое PHP файла - */ - static function fileContent($file, array $tpl) + protected $actions = array(); + public $context = array(); + protected $file; + protected $action; + protected $node; + protected $stack = array(); + + public $zip; + public $target; + + public function __construct($file) { - ob_start(); - include $file; - $result = ob_get_contents(); - ob_clean(); - return $result; + $this->file = $file; + $this->node = simplexml_load_file($file); + + $this->target = ''; + $this->zip = new ZipArchive(); + $this->zip->open(strtr($file, array('.xml' => '.zip'))); + + + array_push($this->stack, $this->node); + + $this->registerAction('copy', array($this, 'copyFile')); + $this->registerAction('make-directory', array($this, 'makeDirectory')); + $this->registerAction('make-link', array($this, 'makeLink')); + $this->registerAction('include', array($this, 'includeFile')); + $this->registerAction('when', array($this, 'testWhen')); } /** - * Копирует файлы шаблонной директории + * Регистрация новых действия для установки */ - static function copyTemplatePath($srcPath, $dstPath, array $tpl, $tplFile = 'tpl') + public function registerAction($name, $action) { - $out = new Path($srcPath); - $path = new Path($dstPath); - $files = $path->getContentRec(null, array(".svn")); + $this->actions[$name] = $action; + } - foreach ($files as $file) { - if (Path::getExtension($file) == $tplFile) { - // Шаблон - $dst = $out->append($path->relPath (Path::skipExtension($file))); - Path::prepare($dst); - file_put_contents($dst, self::fileContent($file, $tpl)); - } else { - // Обычный файл - $dst = $out->append($path->relPath ($file)); - Path::prepare($dst); - copy($file, $dst); - } + /** + * Установка переменных для шаблона + */ + public function set($name, $value) + { + $this->context[$name] = $value; + } + + function replaceFn($matches) { + if (isset($this->context[$matches[2]])) { + $v = $this->context[$matches[2]]; + } else { + $v = $matches[2]; + } + + if ($matches[1] == '*') { + return addslashes($v); + } + return $v; + } + + public function fileContent($file, array $tpl) + { + $result = $this->zip->getFromName($file); + $result = preg_replace_callback('/\{\{\s*(\*?)(\w+)\s*\}\}/', array($this, 'replaceFn'), $result); + return $result; + } + + function callAction($name, array $attributes) + { + if(isset($this->actions[$name])) { + call_user_func_array($this->actions[$name], $attributes); + } + } + + /** + * Заменяет переменные на их значения в строке + */ + function replaceVariable(array $match) + { + if (isset($this->context[$match[1]])) { + return $this->context[$match[1]]; + } + return $match[0]; + } + + /** + * Для всех аттрибутов заменяет переменные на их значения + */ + function resolve($attributes) + { + $result = array(); + foreach ($attributes as $key => $value) { + $result [$key] = preg_replace_callback("/\\\${(\w+)}/", array($this, 'replaceVariable'), $value); + } + return $result; + } + + /** + * Выполняет список действий если для действия не указан аттрибут when то оно выполняется всегда + * + * @param $action специальное действие + */ + function executeActions($action = "install") + { + $this->action = $action; + if ($this->stack[count($this->stack) - 1] === false) { + return; + } + + /*.SimpleXMLElement.*/$item = $this->stack[count($this->stack) - 1]; + $root = $item->children(); + foreach ($root as $node) + { + $attributes = $node->attributes(); + array_push($this->stack, $node); + $this->callAction($node->getName(), array($this->resolve($attributes))); + array_pop($this->stack); + } + } + + /** + * Копирования файла + * @param preserve Не переписывать файл если он существует + * @param template Файл является шаблоном подставить параметры до копирования + * @param src Исходный файл + * @param dst Новый файл + */ + public function copyFile(array $attributes) + { + $path = $this->targetPath($attributes['dst']); + + if (!(file_exists($path) && isset($attributes['preserve']))) { + file_put_contents($path, $this->fileContent($attributes['src'], $this->context)); + } + } + + /** + * Создает символическую ссылку на папку/файл + * @param dst Имя папки + */ + public function makeLink(array $attributes) + { + if (function_exists('symlink')) { + symlink($attributes['target'], $attributes['link']); + } + } + + /** + * Подключение файла установки + * @param file Имя подключаемого файла + */ + public function includeFile(array $attributes) + { + $file = basename($this->file) . "/" . $attributes['file']; + + $setup = new Setup($file); + $setup->context = $this->context; + $setup->executeActions(); + } + + function targetPath($s) { + return $this->target . '/' . $s; + } + + /** + * Создает новую папку + * @param dst Имя папки + */ + public function makeDirectory(array $attributes) + { + $path = $this->targetPath($attributes['dst']); + if (!file_exists($path)) { + mkdir($path); + } + } + + function testWhen(array $attributes) + { + if (!isset($attributes['test']) || $attributes['test'] == $this->action) { + $this->executeActions($this->action); } } /** * Выполнение Списка SQL команд */ - static function batchSQL(Connection $conn, $file) + function batchSQLZip(/*.Database.*/ $conn, $file) { - $stmtList = SQLStatementExtractor::extractFile ($file); + $stmtList = Tools_SQLStatementExtractor::extract($this->zip->getFromName($file)); + foreach ($stmtList as $stmt) { + $conn->executeQuery ($stmt); + } + } + + static function batchSQL(/*.Database.*/ $conn, $file) + { + $stmtList = Utils_SQLStatementExtractor::extractFile($file); foreach ($stmtList as $stmt) { $conn->executeQuery ($stmt); } } } + diff --git a/src/shortcut.php b/src/shortcut.php index a80e5f5..4e24046 100644 --- a/src/shortcut.php +++ b/src/shortcut.php @@ -10,7 +10,7 @@ class Shortcut public $list = array(); // Singleton pattern - static public function getInstance () + static public function getInstance() { if (self::$instance == null) { self::$instance = new Shortcut(); @@ -24,7 +24,7 @@ class Shortcut */ public function addUrl($prefix, $path) { - $this->list [$prefix] = $path; + $this->list[$prefix] = $path; } /** @@ -38,9 +38,10 @@ class Shortcut /** * Возвращает путь по имени ярлыка */ - static function getUrl ($prefix, $name = null, $name1 = false) + static function getUrl($prefix, $name = null, $name1 = null) { $shortcut = self::getInstance(); + $names = $shortcut->variables; if ($name) { $names['$name'] = $name; @@ -48,10 +49,18 @@ class Shortcut if ($name1) { $names['$name1'] = $name1; } + if (isset($shortcut->list[$prefix])) { return strtr($shortcut->list[$prefix], $names); } - return false; + return null; } -} + static function expand($path) + { + $shortcut = self::getInstance(); + $names = $shortcut->variables; + return strtr($path, $names); + } + +} diff --git a/src/tales.php b/src/tales.php index e474ad6..2b411f7 100644 --- a/src/tales.php +++ b/src/tales.php @@ -2,33 +2,61 @@ /** * Расширения для PHPTAL для отображения времени и даты - * package utils */ class DateTime_Tales implements PHPTAL_Tales { - static public function date ($expression, $nothrow = false) + static public function date($expression, $nothrow = false) { - return "phptal_date(".PHPTAL_TalesInternal::path ($expression).")"; + return "phptal_date(".PHPTAL_Php_TalesInternal::path ($expression).")"; } - static public function time ($expression, $nothrow = false) + static public function time($expression, $nothrow = false) { - return "phptal_time(".PHPTAL_TalesInternal::path ($expression).")"; + return "phptal_time(".PHPTAL_Php_TalesInternal::path ($expression).")"; } } -/* Регистрация нового префикса для подключения компонента */ -$registry = PHPTAL_TalesRegistry::getInstance(); -$registry->registerPrefix('date', array('DateTime_Tales', 'date')); -$registry->registerPrefix('time', array('DateTime_Tales', 'time')); + +/** + * TALES для подключения компонентов + * component:name?param1=value1¶m2=value2 + */ +class Component_Tales implements PHPTAL_Tales +{ + static public function component($expression, $nothrow = false) + { + $s = PHPTAL_Php_TalesInternal::string($expression); + return "phptal_component(" . $s . ")"; + } +} function phptal_date ($e) { - return date ("d.m.Y", $e); + return date("d.m.Y", $e); } function phptal_time ($e) { - return date ("H:i", $e); + return date("H:i", $e); } + +/** + * Функция подключения компонента + */ +function phptal_component ($expression) { + global $db, $registry; // Нужно как-то передавать параметры + + $component = Controller_Component::loadComponent($expression, $db, $registry); + $req = new HttpRequest(); + + return $component->execute($req); +} + + +/* Регистрация нового префикса для подключения компонента */ +$tales = PHPTAL_TalesRegistry::getInstance(); +$tales->registerPrefix('component', array('Component_Tales', 'component')); +$tales->registerPrefix('date', array('DateTime_Tales', 'date')); +$tales->registerPrefix('time', array('DateTime_Tales', 'time')); + diff --git a/src/tools/drawing.php b/src/tools/drawing.php index b0cf247..85cbdfa 100644 --- a/src/tools/drawing.php +++ b/src/tools/drawing.php @@ -2,7 +2,6 @@ class Drawing { - const ALIGN_LEFT = "left"; const ALIGN_TOP = "top"; const ALIGN_BOTTOM = "bottom"; @@ -26,7 +25,6 @@ class Drawing static function imagettftextbox(&$image, $size, $angle, $left, $top, $color, $font, $text, $max_width, $max_height, $align, $valign) { -// echo var_dump($font); // echo $left,"\n", $top, "\n"; // echo $max_width,"\n", $max_height, "\n"; // self::drawrectnagle($image, $left, $top, $max_width, $max_height, array(0xFF,0,0)); @@ -44,7 +42,6 @@ class Drawing $last_width = 0; for ($i = 0; $i < count($words); $i++) { $item = $words[$i]; -// echo "->", $font, "\n"; $dimensions = imagettfbbox($size, $angle, $font, $current_line . ($first_word ? '' : ' ') . $item); $line_width = $dimensions[2] - $dimensions[0]; $line_height = $dimensions[1] - $dimensions[7]; @@ -75,6 +72,7 @@ class Drawing } // vertical align + $top_offset = 0; if ($valign == self::ALIGN_CENTER) { $top_offset = ($max_height - $largest_line_height * count($lines)) / 2; } elseif ($valign == self::ALIGN_BOTTOM) { @@ -84,17 +82,15 @@ class Drawing $top += $largest_line_height + $top_offset; $i = 0; - fb($lines); - fb($line_widths); foreach ($lines as $line) { // horizontal align + $left_offset = 0; if ($align == self::ALIGN_CENTER) { $left_offset = ($max_width - $line_widths[$i]) / 2; } elseif ($align == self::ALIGN_RIGHT) { $left_offset = ($max_width - $line_widths[$i]); } -// echo $font, "\n"; imagettftext($image, $size, $angle, $left + $left_offset, $top + ($largest_line_height * $i), $color, $font, $line); $i++; } diff --git a/src/view/composite.php b/src/view/composite.php new file mode 100644 index 0000000..e9427a6 --- /dev/null +++ b/src/view/composite.php @@ -0,0 +1,40 @@ +tal = new PHPTAL($file); + $this->tal->stripComments(true); + } + + function set($key, $val) + { + if ($key == 'title') { + $this->setTitle($val); + } + $this->tal->set($key, $val); + } + + function __set($key, $val) + { + $this->tal->set($key, $val); + } + + function setTranslator($tr) + { + $this->tal->setTranslator($tr); + } + + function execute() + { + parent::execute(); + // postProcess + return $this->tal->execute(); + } +} diff --git a/src/view/compositeview.php b/src/view/top.php similarity index 89% rename from src/view/compositeview.php rename to src/view/top.php index 890fed2..5e3477f 100644 --- a/src/view/compositeview.php +++ b/src/view/top.php @@ -1,6 +1,6 @@ tal = new PHPTAL($file); - $this->tal->setEncoding('WINDOWS-1251'); // PHP_TAL_DEFAULT_ENCODING !! - $this->tal->stripComments(true); - } - - function set($key, $val) - { - if ($key == 'title') { - $this->setTitle($val); - } - $this->tal->set($key, $val); - } - - function __set($key, $val) - { - $this->tal->set($key, $val); - } - - function setTranslator($tr) - { - $this->tal->setTranslator($tr); - } - - function execute() - { - parent::execute(); - // postProcess - return $this->tal->execute(); - } -} diff --git a/src/zipfile.php b/src/zipfile.php index e55c100..49c4ddd 100644 --- a/src/zipfile.php +++ b/src/zipfile.php @@ -5,21 +5,28 @@ */ class ZipFile extends ZipArchive { + private $ignore = array('.', '..'); + + public function addIgnore($name) + { + $this->ignore [] = $name; + } + private function addDirDo($location, $name) { assert(is_string($location) && is_string($name)); $name .= '/'; $location .= '/'; + $file = null; // Read all Files in Dir $dir = opendir($location); while (($file = readdir($dir)) !== false) { - if ($file === '.' || $file === '..') continue; - + if (in_array($file, $this->ignore)) continue; // Rekursiv, If dir: FlxZipArchive::addDir(), else ::File(); - $call = (is_dir($file)) ? 'addDir' : 'addFile'; + $call = (is_dir($location . $file)) ? 'addDir' : 'addFile'; call_user_func(array($this, $call), $location . $file, $name . $file); } }