Синхронизировал частично с CMS2

This commit is contained in:
origami11 2017-02-09 17:14:11 +03:00
parent 6b412f5d6f
commit f2938b1353
30 changed files with 1447 additions and 1099 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.bak

View file

@ -1,8 +1,7 @@
<?php <?php
/** /**
* Коллекция * Коллекция
* *
* package core
*/ */
class Collection implements ArrayAccess class Collection implements ArrayAccess
{ {
@ -40,7 +39,7 @@ class Collection implements ArrayAccess
* *
* @return void * @return void
*/ */
public function set($key, $value) public function set(/*.string.*/$key, /*.any.*/$value)
{ {
$this->data[$key] = $value; $this->data[$key] = $value;
} }
@ -54,7 +53,7 @@ class Collection implements ArrayAccess
*/ */
public function get($key, $default = null) 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) public function getInt($key, $default = 0)

View file

@ -1,423 +1,339 @@
<?php <?php
/**
* require_once __DIR__ . '/../functions.php';
* @package Core
*/
/** function forceUrl($name)
* Переименовать контроллер !! (StubController, CrudController, PageController, BaseController) ModelController
* Возможно нужен еще класс с мета действиями как для actionIndex <= metaActionIndex либо с классам для этих действий
* Есть класс для управлениями действиями а есть сами действия в виде классов или функций !!
*/
class Controller_Model extends Controller_Action
{ {
public $schema = array(); if (is_callable($name)) {
public $schemaSearch = array(); return call_user_func($name);
}
return $name;
}
/** /**
* FIXME: Лучше $this->table->setHeader * Контроллер страниц
*/ */
public $tableSchema = null; class Controller_Action
public $formSchema = array(); {
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 $path;
public $table;
public function __construct() public function __construct ()
{ {
$this->path = new PathMenu(); //
$this->menu = new PageMenu();
$this->table = new ListTable();
} }
/** public function setUp ()
*/
function setUp()
{ {
$this->table->addMenuItem($this->aUrl('delete'), 'удалить', false, 'all', 'warning'); // override this
//$this->table->addMenuItem($this->nUrl('form'), 'редактировать', 'edit-24.png');
} }
function saveParameters($args, $list) public function loadConfig($name) {
{ $filename = Shortcut::getUrl('config', $name);
foreach ($list as $item) { if (file_exists($filename)) {
$args->session()->set(array($this, $item), $args->get($item)); include($filename);
}
}
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 { } 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");
} }
} }
/** function findIcon($icon, $size)
* Добавление пользователя
*/
public function actionAdd(HttpRequest $request)
{ {
require_once "core/validator/validator.php"; return Path::join($this->iconPath, $size . 'x' . $size, $icon . '.png');
// {{{ тоже может быть один 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);
}
/** /**
* Заголовок * Создает представление
* @param string $file
* @return template
*/ */
private function setTitlePath($ref) public function getView($name)
{ {
if ($ref) { $file = $name . self::TEMPLATE_EXTENSION;
$model = $this->getModel($this->useModel); // Список возможных директорий для поиска файла шаблона
if (is_array($model->reference) && $model->reference[0]) { $theme = $this->_registry->readKey(array('system', 'theme'));
$refmodel = $this->getModel($model->reference[0]); $icon_theme = $this->_registry->readKey(array('system', 'icon_theme'));
try { $list = array(
$parent = $refmodel->findById($ref); Path::join($this->viewPath, TEMPLATES) => Path::join(WWW_PATH, "modules", $this->name, TEMPLATES),
$this->path->addTitle($parent->getTitle()); // Заголовок к подписям путей PHPTAL_TEMPLATE_REPOSITORY => "");
} catch (Exception $e) {
// Не найден заголовок потому что неправильно определен родительский элемент
} // Поиск файла для шаблона
} 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); $tpl = new View_Composite($template);
$form = new TForm(); // Показываем форму $tpl->icons = $this->iconPath; // Путь к файлам текущей темы
$form->header = 'Редактирование записи'; $tpl->media = $this->themePath; // Путь к файлам текущей темы
$this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы $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'); $tpl->loadImports(Path::skipExtension($template) . ".import");
$id = ($list[0]) ? $list[0] : $request->get('id');
$tpl = $this->formPage ($form, $request); $this->addSuggest($tpl, $name);
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; return $tpl;
} }
/** public function getModel($name)
*/
function tableSetup($table, $id = null, $ref = null)
{ {
// FIXME: После замены везде $tableSchema -> table->setHeader удалить! if (!$this->factory) {
if ($this->tableSchema) { $this->factory = new ModelFactory($this->db, $this->_registry, $this->_shortcut);
$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);
} }
return $this->factory->getModel($name);
} }
/** /**
* Выбор действия
* Т.к действия являются методами класса то
* 1. Можно переопределить действия
* 2. Использовать наследование чтобы добавить к старому обработчику новое поведение
* @param $request Обьект запроса
*/ */
public function actionIndex(HttpRequest $request) public function execute1(HTTPRequest $request)
{ {
$this->getActionPath($request, 'index'); $action = self::ACTION_PREFIX . ucfirst($request->getAction());
// Такое мета действие наверное можно вынести в отдельный класс if (method_exists($this, $action)) {
return $this->metaActionIndex($request, array($this, 'tableSetup'), $this->aUrl('list')); 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 или несколько return "";
// {{{ история переходов }
$ref = null;
if ($request->get('ref')) { public function postUrl($name, $param)
$ref = $request->get('ref'); {
} else if ($request->session()->get('ref')) { return "?" . http_build_query(
$ref = $request->session()->get('ref'); 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); public function fUrl($name, array $param = array())
$this->addParameter('ref', $ref); {
// }}} return forceUrl($this->nUrl($name, $param));
$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;
} }
/** /**
* Добавляет параметр для всех ссылок создаваемых функцией nUrl, aUrl
*/ */
public function actionSetup($request) public function addParameter($name, $value)
{ {
$left = explode(",", $request->get('left')); if ($value) {
$right = explode(",", $request->get('right')); $this->param [$name] = $value;
}
$$request->session()->set(strtolower(get_class($this)),
array('view' => array('left' => $left, 'right' => $right)));
return $this->forward('actionIndex', $request);
} }
/** /**
* Генерация ссылки на действие контроллера
* Ajax определяется автоматически mode = ajax используется для смены layout
*/ */
private function formPage($form, $request) public function aUrl($name, array $param = array())
{ {
$view = $this->getView('form'); return $this->nUrl($name, array_merge(array('mode' => 'ajax'), $param)); // FIXME
$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*/) * Добавление помошника контроллера
*/
public function addHelper($class)
{ {
require_once 'state.php'; $this->helpers [] = $class;
$this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction()); }
}
/**
* Вызов помошников контроллера
*/
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();
}
} }

View file

@ -1,341 +0,0 @@
<?php
require_once 'core/functions.php';
function forceUrl($name)
{
if (is_callable($name)) {
return call_user_func($name);
}
return $name;
}
/**
* Контроллер страниц
* @package core
*/
class Controller_Controller
{
const TEMPLATE_EXTENSION = ".html"; // Расширение для шаблонов
const ACTION_PREFIX = "action"; // Префикс для функций действий
public $jsPath; // Глобальный путь к скриптам
public $themePath; // Глобальный путь к текущей теме
// Параметры устанавливаются при создании контроллера
public $name; // Имя модуля
public $viewPath = null; // Путь к шаблонам контроллера
public $db; // Соединение с базой данных
// Фильтры
public $access; // Обьект хранит параметры доступа
public $logger; // Обьект для ведения лога
private $factory; // Ссылка на обьект создания модели
private $helpers = array(); // Помошники для действий
public $param = array(); // Параметры для ссылки
public $_registry; // Ссылка на реестр
public $_shortcut;
public function __construct ()
{
//
}
public function setUp ()
{
// override this
}
public function loadConfig($name) {
$filename = Shortcut::getUrl('config', $name);
if (file_exists($filename)) {
include($filename);
} else {
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");
}
}
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 {}

View file

@ -1,30 +1,24 @@
<?php <?php
require_once 'core/controller/controller.php';
require_once 'core/controller/installer.php';
/** /**
* Первичный контроллер контроллер страниц * Первичный контроллер контроллер страниц
* @package core * @package core
*/ */
class Controller_Front extends Controller class Controller_Front extends Controller_Action
{ {
protected $shortcut; // Ярлык к модулю protected $shortcut; // Ярлык к модулю
protected $_param; // Параметр по которому выбирается модуль protected $_param; // Параметр по которому выбирается модуль
protected $default; // Значение параметра по умолчанию protected $default; // Значение параметра по умолчанию
protected $installer;
public function __construct(Settings $_registry, $_shortcut) public function __construct(Settings $_registry, $_shortcut)
{ {
require_once 'core/database_pdo.php';
parent::__construct(); parent::__construct();
$registry = $_registry; $registry = $_registry;
$this->_registry = $_registry; $this->_registry = $_registry;
$this->_shortcut = $_shortcut; $this->_shortcut = $_shortcut;
$this->db = Database::getConnection($registry->readKey(array('system', 'dsn'))); $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) 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) $moduleFile = Shortcut::getUrl($this->shortcut, $name); // ModuleLoader (2)
$module = $this->loadClass($moduleFile); $module = $this->loadClass($moduleFile);
@ -59,10 +51,10 @@ class Controller_Front extends Controller
$module->db = $this->db; $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)); $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->access->access = $this->loadSettings(Shortcut::getUrl('access', $name));
$module->setUp(); $module->setUp();

426
src/controller/model.php Normal file
View file

@ -0,0 +1,426 @@
<?php
/**
* Переименовать контроллер !! (StubController, CrudController, PageController, BaseController) ModelController
* Возможно нужен еще класс с мета действиями как для actionIndex <= metaActionIndex либо с классам для этих действий
* Есть класс для управлениями действиями а есть сами действия в виде классов или функций !!
*
* @class Controller_Model в котором определены основные действия для редактирования, вывода списка, сохранения, поиска и т.д
* В модуле определяется только способ отображения этих данных
*/
class Controller_Model extends Controller_Action
{
public /*.array.*/$schema = array();
public /*.array.*/$schemaSearch = array();
/**
* FIXME: Лучше $this->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());
}
}

View file

@ -13,7 +13,7 @@ class Controller_State
static function make($action) static function make($action)
{ {
return new State($action); return new Controller_State($action);
} }
public function addTitle($name, $url = array()) public function addTitle($name, $url = array())
@ -22,7 +22,7 @@ class Controller_State
return $this; return $this;
} }
public function addState(State $state) public function addState(Controller_State $state)
{ {
$this->states [$state->getAction()] = $state; $this->states [$state->getAction()] = $state;
return $this; return $this;
@ -49,7 +49,7 @@ class Controller_State
return false; return false;
} }
function makeTitle($module) function makeTitle(Controller_Action $module)
{ {
foreach ($this->titles as $item) { foreach ($this->titles as $item) {
$module->path->addMenuItem($module->nUrl($this->action, $item[1]), $item[0]); $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');
*/

View file

@ -1,7 +1,5 @@
<?php <?php
require_once 'core/path.php';
class ActionLogger class ActionLogger
{ {
public $before = array (); public $before = array ();

View file

@ -8,7 +8,7 @@
*/ */
// В класс авторизации передавать обьект для управления пользователем // В класс авторизации передавать обьект для управления пользователем
// Вынести в отдельный файл // Вынести в отдельный файл
class Filter_LoginFilter extends Filter_Filter class Filter_Login extends Filter_Filter
{ {
const SESSION_BROWSER_SIGN_SECRET = '@w3dsju45Msk#'; const SESSION_BROWSER_SIGN_SECRET = '@w3dsju45Msk#';
const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign'; const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign';
@ -20,16 +20,16 @@ class Filter_LoginFilter extends Filter_Filter
public function isLoggin(HttpRequest $request) public function isLoggin(HttpRequest $request)
{ {
// Авторизация // Авторизация
session_start(); // session_start();
$db = $this->getConnection(); $db = $this->getConnection();
UserAccess::setUp($db); // Соединение Filter_UserAccess::setUp($db); // Соединение
switch ($request->getAction()) { switch ($request->getAction()) {
// Авторизация по постоянному паролю // Авторизация по постоянному паролю
case 'login': case 'login':
$login = $request->get('login'); $login = $request->get('login');
$password = $request->get('password'); $password = $request->get('password');
$result = UserAccess::getUserByLogin($login); // Поиск по логину $result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину
if ($result) { if ($result) {
if (md5($password) == $result->getString('password')) { // password if (md5($password) == $result->getString('password')) { // password
$this->enter($db, $result); $this->enter($db, $result);

View file

@ -1,10 +1,7 @@
<?php <?php
require_once 'filterbase.php';
require_once 'filterlogin.php';
// Класс должен быть в библиотеке приложения // Класс должен быть в библиотеке приложения
class UserAccess class Filter_UserAccess
{ {
const LIFE_TIME = 1800; // = 30min * 60sec; const LIFE_TIME = 1800; // = 30min * 60sec;

View file

@ -2,17 +2,23 @@
/** /**
* Элемент формы * Элемент формы
* @package core
*/ */
class TField class TField
{ {
public $hidden = false;
public $name; public $name;
public $label; // Метка поля public $label; // Метка поля
public $value; // Значение поля public $value; // Значение поля
public $type; // Каждому типу элемента соответствует макрос TAL public $type = ""; // Каждому типу элемента соответствует макрос TAL
public $error_msg = null; public $error_msg = null;
public $default = null;
public $error = false; public $error = false;
public $require = false; public $require = false;
public $hint = null;
// Блоки (Убрать в отдельный класс!!!)
public $_title = array();
public $description = "";
public $alias = array();
public function __construct ($input) public function __construct ($input)
{ {

View file

@ -107,7 +107,7 @@ function compose() {
* *
* @return array[int]mixed * @return array[int]mixed
*/ */
function rcurry() { function rcurry($_rest) {
$closure = new __right(func_get_args ()); $closure = new __right(func_get_args ());
return array($closure, 'apply'); return array($closure, 'apply');
} }
@ -117,7 +117,7 @@ function rcurry() {
* *
* @return array[int]mixed * @return array[int]mixed
*/ */
function lcurry() { function lcurry($_rest) {
$closure = new __left(func_get_args ()); $closure = new __left(func_get_args ());
return array($closure, 'apply'); return array($closure, 'apply');
} }
@ -192,7 +192,7 @@ function __self($name, $o) {
function concat(/* $args ...*/) { function concat(/* $args ...*/) {
$args = func_get_args(); $args = func_get_args();
return implode($args); return implode("", $args);
} }
function __empty($x) { function __empty($x) {
@ -229,6 +229,15 @@ function key_values($key, /*array|ArrayIterator*/ $array) {
return $result; return $result;
} }
function key_values_object($key, /*array|ArrayIterator*/ $array) {
$result = array();
foreach($array as $item) {
$result[] = $item->{$key};
}
return $result;
}
function assoc_key_values($key, $value, $array) { function assoc_key_values($key, $value, $array) {
$result = array(); $result = array();
foreach ($array as $item) { foreach ($array as $item) {
@ -245,7 +254,7 @@ function assoc_key($key, $array) {
return $result; return $result;
} }
function _get($key, $value, $array) { function _get($key, /*.any.*/$value, /*.array.*/$array) {
foreach ($array as $item) { foreach ($array as $item) {
if ($item[$key] == $value) return $item; if ($item[$key] == $value) return $item;
} }
@ -265,7 +274,7 @@ function _get_key($key, $value, $array) {
* @return bool * @return bool
*/ */
function every(array $array, $callback) { function every(array $array, $callback) {
foreach ($array as $key => $value) { foreach ($array as $value) {
if (call_user_func($callback, $value) === false) { if (call_user_func($callback, $value) === false) {
return false; return false;
} }
@ -337,10 +346,33 @@ if (!function_exists('hash_key')) {
}; };
} }
function array_merge1($x, $y) { /**
$result = $x; * Выбирает все сроки из таблицы с уникальными значениями ключа
foreach ($y as $k => $v) { * @param $name Имя ключа
$result [$k] = $v; * @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;
} }

View file

@ -10,6 +10,8 @@ class WrongRequestException extends Exception
// HTTPRequest = ArrayAccess // HTTPRequest = ArrayAccess
class HttpRequest extends Collection implements ArrayAccess class HttpRequest extends Collection implements ArrayAccess
{ {
public $_session;
/** /**
* Constructor * Constructor
* Stores "request data" in GPC order. * Stores "request data" in GPC order.
@ -24,9 +26,8 @@ class HttpRequest extends Collection implements ArrayAccess
$ajax = $this->isAjax(); $ajax = $this->isAjax();
foreach ($list as $key => $value) { foreach ($list as $key => $value) {
$data = new SafeCollection(); $data = new Collection();
$data->import($value); $data->import($value);
parent::set($key, $data); parent::set($key, $data);
} }
@ -35,50 +36,32 @@ class HttpRequest extends Collection implements ArrayAccess
parent::set('files', $data); 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) function _get($key)
{ {
return parent::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 set($key, /*.any.*/$value)
function offsetExists($offset)
{ {
return parent::get('data')->set($key, $value);
} }
function offsetGet($offset) function export($key = 'data')
{
}
function offsetSet($offset, $value)
{
}
function offsetUnset($offset)
{ {
return parent::get($key)->export();
} }
function clear() 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'); 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) {
}
} }

View file

@ -1,13 +1,13 @@
<?php <?php
require_once 'core/functions.php'; require_once __DIR__ . '/../functions.php';
// Переместить в фильтры!! // Переместить в фильтры!!
/** /**
* Выбор макета страницы. * Выбор макета страницы.
* Выбор оформления страницы осуществляется если было совпадение с каким либо условием * Выбор оформления страницы осуществляется если было совпадение с каким либо условием
*/ */
class LayoutManager extends Filter class Layout_Manager extends Filter_Filter
{ {
// Массив условий с их макетами // Массив условий с их макетами
protected $condition = array(); protected $condition = array();
@ -20,7 +20,7 @@ class LayoutManager extends Filter
* addConditionGet(array('module' => 'personal'), 'personal') * addConditionGet(array('module' => 'personal'), 'personal')
* addConditionGet(array('module' => 'login'), 'login') * 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); $this->addCondition(rcurry(array($this, 'checkGet'), $get), $layout);
} }
@ -28,7 +28,7 @@ class LayoutManager extends Filter
/** /**
* Условие для аякс запросов. Тоже самое что и addConditionGet но еще проверяется является ли запрос ajax * Условие для аякс запросов. Тоже самое что и addConditionGet но еще проверяется является ли запрос ajax
*/ */
public function addConditionXHR($get, Filter $layout) public function addConditionXHR($get, Filter_Filter $layout)
{ {
$this->addCondition(rcurry(array($this, 'checkXHR'), $get), $layout); $this->addCondition(rcurry(array($this, 'checkXHR'), $get), $layout);
} }
@ -51,11 +51,11 @@ class LayoutManager extends Filter
} }
/** /**
* Добавляет есловие в общем виде * Добавляет условие в общем виде
* @parma $get function(HttpRequest) Функция * @parma $get function(HttpRequest) Функция
* @parma $layout Layout Макет * @parma $layout Layout Макет
*/ */
public function addCondition($get, Filter $layout) public function addCondition($get, Filter_Filter $layout)
{ {
$this->condition [] = array($get, $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);
}
}

11
src/layout/none.php Normal file
View file

@ -0,0 +1,11 @@
<?php
/**
* Самый простой макет
*/
class Layout_None extends Filter_Filter
{
function execute(HttpRequest $request)
{
return $this->processor->execute($request);
}
}

View file

@ -6,14 +6,14 @@
*/ */
class Mail class Mail
{ {
public $from; public $_from;
public $to; public $_to;
public $subject; public $_subject;
public $content; public $content;
public $copy; public $copy;
private $encoding; private $encoding;
private $notify= false; private $_notify = null;
protected $attachment = array (); protected $attachment = array ();
protected $uniqid; protected $uniqid;
@ -22,8 +22,6 @@ class Mail
function __construct() { function __construct() {
$this->setEncoding("UTF-8"); $this->setEncoding("UTF-8");
$this->uniqid = strtoupper(uniqid(time())); // Идентефикатор разделителя $this->uniqid = strtoupper(uniqid(time())); // Идентефикатор разделителя
// $this->mime
} }
/** /**
@ -31,7 +29,7 @@ class Mail
*/ */
function from($name) function from($name)
{ {
$this->from = $name; $this->_from = $name;
} }
/** /**
@ -39,7 +37,7 @@ class Mail
*/ */
function to($name) // recipient function to($name) // recipient
{ {
$this->to = $name; $this->_to = $name;
} }
/** /**
@ -52,7 +50,7 @@ class Mail
function notify($notify) function notify($notify)
{ {
$this->notify = $notify; $this->_notify = $notify;
} }
/** /**
@ -60,7 +58,7 @@ class Mail
*/ */
function subject($subject) function subject($subject)
{ {
$this->subject = $subject; $this->_subject = $subject;
} }
/** /**
@ -70,12 +68,7 @@ class Mail
{ {
$this->content = $text; $this->content = $text;
} }
function setType($type)
{
$this->type = $type;
}
/** /**
* Кодировка текста в письме * Кодировка текста в письме
*/ */
@ -93,11 +86,18 @@ class Mail
if(file_exists($filename)) { // assert ?? if(file_exists($filename)) { // assert ??
$file = fopen($filename, "rb"); $file = fopen($filename, "rb");
$data = fread($file, filesize($filename)); if (is_resource($file)) {
$this->attachment [] = ($name) ? array($data, $name) : array($data, basename($filename)); $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 * Общий формат тегов MIME
* http://tools.ietf.org/html/rfc2045 * @see http://tools.ietf.org/html/rfc2045
*/ */
function mimeTag($name, $value, array $args = array()) 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') function encodedWord($text, $encoding = 'B')
{ {
@ -144,16 +144,16 @@ class Mail
$message .= $this->mimeTag("Content-Transfer-Encoding", "8bit"); $message .= $this->mimeTag("Content-Transfer-Encoding", "8bit");
$message .= PHP_EOL . $this->content . PHP_EOL . PHP_EOL; $message .= PHP_EOL . $this->content . PHP_EOL . PHP_EOL;
/** /*
* Вложения * Вложения
* http://tools.ietf.org/html/rfc2046#section-5.1.3 * http://tools.ietf.org/html/rfc2046#section-5.1.3
*/ */
foreach ($this->attachment as $value) { foreach ($this->attachment as $value) {
list($data, $name) = $value; list($data, $name) = $value;
$message .= "--" . $this->uniqid . PHP_EOL; $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-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; $message .= PHP_EOL . chunk_split(base64_encode($data)) . PHP_EOL;
} }
@ -166,11 +166,11 @@ class Mail
function getHeader() function getHeader()
{ {
$head = $this->mimeTag("MIME-Version", "1.0"); $head = $this->mimeTag("MIME-Version", "1.0");
$head .= $this->mimeTag("From", $this->from); $head .= $this->mimeTag("From", $this->_from);
$head .= $this->mimeTag("X-Mailer", "CIS Tool"); $head .= $this->mimeTag("X-Mailer", "CMS Tool");
$head .= $this->mimeTag("Reply-To", $this->from); $head .= $this->mimeTag("Reply-To", $this->_from);
if ($this->notify) { if (is_string($this->_notify)) {
$head .= $this->mimeTag("Disposition-Notification-To", "\"" . $this->notify . "\" <" . $this->from . ">"); $head .= $this->mimeTag("Disposition-Notification-To", "\"" . $this->_notify . "\" <" . $this->_from . ">");
} }
$head .= $this->mimeTag("Content-Type", "multipart/mixed", array ("boundary" => $this->uniqid)); $head .= $this->mimeTag("Content-Type", "multipart/mixed", array ("boundary" => $this->uniqid));
if ($this->copy) { if ($this->copy) {
@ -182,7 +182,7 @@ class Mail
function getSubject() function getSubject()
{ {
return $this->encodedWord($this->subject); return $this->encodedWord($this->_subject);
} }
/** /**
@ -190,7 +190,7 @@ class Mail
*/ */
function eml() 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() function send()
{ {
$result = mail($this->to, $this->getSubject(), $this->getMessage(), $this->getHeader()); $result = mail($this->_to, $this->getSubject(), $this->getMessage(), $this->getHeader());
if(! $result) { if(! $result) {
throw new Exception('Невозможно отправить почту'); throw new Exception('Невозможно отправить почту');
// require_once "core/path.php"; // require_once "core/path.php";

View file

@ -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 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**/ **/
class Simple_BB_Code{ class Markup_SimpleBBCode{
//General Tags //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'); 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 //Tags that must be mapped to diffierent parts
@ -38,7 +38,7 @@ class Simple_BB_Code{
var $auto_links = true; var $auto_links = true;
//Internal Storage //Internal Storage
var $_code = ''; 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->convert_newlines = $new;
$this->parse_smilies = $parse; $this->parse_smilies = $parse;
$this->auto_links = $links; $this->auto_links = $links;

View file

@ -12,7 +12,7 @@ class Numbers
return $i; return $i;
} }
static function prefix($prefix, array $array) static function prefix($prefix, array $array, $key = false)
{ {
$result = array(); $result = array();
for ($i = 0; $i < count($array); $i++) { for ($i = 0; $i < count($array); $i++) {

View file

@ -1,33 +1,58 @@
<?php <?php
/*.
require_module 'standard';
.*/
/** /**
* Класс для работы с папками и путями * Класс для работы с папками и путями
* Для итерации над файлами возможно лучше использовать SPL * Для итерации над файлами возможно лучше использовать SPL
* *
* @package utils
*/ */
class Path
class Path
{ {
const SEPARATOR = "/"; const SEPARATOR = "/";
protected $path; protected $path = array();
protected $url = array();
protected $absolute = false;
public function __construct ($path) public function __construct($path)
{ {
assert(is_string($path)); // assert(is_string($path));
$this->path = $this->fromString($path); $this->url = parse_url($path);
$this->optimize();
} 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) { static function factory($path) {
return new Path($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 * @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); 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 * @return string
*/ */
static function skipExtension ($fileName) static function skipExtension($fileName)
{ {
assert(is_string($fileName)); assert(is_string($fileName));
@ -68,118 +102,13 @@ class Path
* *
* @return string * @return string
*/ */
static function getFileName ($fileName) static function getFileName($fileName)
{ {
assert(is_string($fileName)); assert(is_string($fileName));
return pathinfo($fileName, PATHINFO_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)); 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; return $list;
} }
/** /**
* Преобразует относительный путь в абсолютный * Преобразует относительный путь в абсолютный
*/ */
public function optimize () public static function optimize($path) //
{ {
$result = array(current($this->path)); $result = array();
while (next($this->path) !== false) { foreach ($path as $n) {
$n = current ($this->path);
switch ($n) { switch ($n) {
// Может быть относительным или абсолютным путем
case "": break; case "": break;
case ".": break; case ".": break;
case "..": if (count($result) > 0) array_pop($result); break; case "..":
if (count($result) > 0) { array_pop($result); break; }
default: default:
array_push($result, $n); array_push($result, $n);
} }
} }
reset($this->path); return $result;
$this->path = $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 * @return string
*/ */
public function __toString () public function __toString()
{ {
$result = implode($this->path, self::SEPARATOR); $result = (($this->absolute) ? '/' : '') . implode(self::SEPARATOR, $this->path);
return $result; $this->url['path'] = $result;
return self::makeUrl($this->url);
} }
/** /**
@ -234,8 +196,11 @@ class Path
* *
* @return boolean * @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)) { if (count($path->path) > count($this->path)) {
for ($i = 0; $i < count($this->path); $i++) { for ($i = 0; $i < count($this->path); $i++) {
if ($path->path[$i] != $this->path[$i]) { if ($path->path[$i] != $this->path[$i]) {
@ -246,6 +211,12 @@ class Path
} }
return false; 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 Относительный путь к файлу * @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) { foreach ($this->path as $n) {
array_shift($path->path); array_shift($path->path);
} }
return $path->__toString(); 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(); $base = $this->__toString();
return self::join($base, $path); return self::join($base, $path);
} }
/** /**
* Создает недастающие папки для записи файла * Обьединяет строки в путь соединяя необходимым разделителем
* * fixme не обрабатывает параметры урла, решение Path::join(SITE_WWW_PATH) . '?param=pampam'
* @param string $dst Полное имя файла * @return string
*
* @return void
*/ */
static function prepare ($dst) static function join($_rest)
{ {
$path_dst = pathinfo($dst, PATHINFO_DIRNAME); $args = func_get_args();
if (! file_exists($path_dst)) { $result = array();
mkdir($path_dst, 0700, true); $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 Новое имя файла * @return string Новое имя файла
*/ */
static function resolveFile ($dst) static function resolveFile($dst)
{ {
$i = 0; $i = 0;
$file = self::skipExtension($dst); $file = self::skipExtension($dst);
@ -304,14 +338,93 @@ class Path
return $temp; 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 * @param array $allow массив расширений разрешеных для файлов
*/ * @param array $ignore массив имен пааок которые не нужно обрабатывать
static function join () *
* @return array
*/
function getContentRec($allow = null, $ignore = array())
{ {
$args = func_get_args(); $result = array ();
return implode(self::SEPARATOR, $args); $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);
}
} }
} }

View file

@ -1,5 +1,7 @@
<?php <?php
///<reference path="settings.php" />
/** /**
* http://www.patternsforphp.com/wiki/Registry * http://www.patternsforphp.com/wiki/Registry
* http://www.patternsforphp.com/wiki/Singleton * http://www.patternsforphp.com/wiki/Singleton

View file

@ -26,7 +26,7 @@ class Session
function start() function start()
{ {
session_start(); @session_start();
} }
function stop() function stop()

View file

@ -12,23 +12,31 @@
class Settings extends Collection class Settings extends Collection
{ {
protected $file; protected $file;
protected $format = 'php';
public function __construct ($file = null) public function __construct ($file = null)
{ {
$this->format = pathinfo($file, PATHINFO_EXTENSION);
$this->file = $file; $this->file = $file;
} }
/** /**
* Чтение настроек из файла * Чтение настроек из файла
*
* @param File $file
*
* @return Boolean * @return Boolean
*/ */
public function read() public function read()
{ {
if ( !file_exists ($this->file)) return false; if (!file_exists ($this->file)) {
return false;
}
// Не include_once т.к читать настройки можно несколько раз // Не 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)) { if (!is_array($settings)) {
throw new Exception($this->file); throw new Exception($this->file);
} }
@ -51,7 +59,9 @@ class Settings extends Collection
// assert(count($key) == 1); // assert(count($key) == 1);
$name = array_shift($key); $name = array_shift($key);
if (is_array($value)) { if (is_array($value)) {
if (! isset($data[$name])) $data[$name] = array(); if (!isset($data[$name])) {
$data[$name] = array();
}
$this->merge($data[$name], $value); $this->merge($data[$name], $value);
} else { } else {
$data[$name] = $value; $data[$name] = $value;
@ -107,7 +117,7 @@ class Settings extends Collection
* Чтение ключа из реестра (Собирает все ключи с определенным значением во всех модулях) * Чтение ключа из реестра (Собирает все ключи с определенным значением во всех модулях)
* @param $key Путь к значению ключа внутри модуля * @param $key Путь к значению ключа внутри модуля
*/ */
public function readKeyList() public function readKeyList($_rest)
{ {
$key = func_get_args(); $key = func_get_args();
$result = array(); $result = array();
@ -149,10 +159,15 @@ class Settings extends Collection
* *
* @return void * @return void
*/ */
public function write($file = false) public function write($file = null)
{ {
$result = var_export ($this->data, true); if ($this->format == 'json') {
file_put_contents (($file) ? $file : $this->file, "<?php\n\$settings = ".$result.";\n?>"); $result = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
} else {
$result = var_export($this->data, true);
$result = "<?php\n\$settings = ".$result.";\n?>";
}
file_put_contents (($file) ? $file : $this->file, $result);
} }
/** /**

View file

@ -1,54 +1,212 @@
<?php <?php
/** /**
* Обработка файлов для установки * <code>
*/ * $setup = new Setup('test.xml');
* $setup->set('target', 'dst');
* $setup->executeActions('install');
* </code>
*/
class Setup class Setup
{ {
/** protected $actions = array();
* Содержимое PHP файла public $context = array();
*/ protected $file;
static function fileContent($file, array $tpl) protected $action;
protected $node;
protected $stack = array();
public $zip;
public $target;
public function __construct($file)
{ {
ob_start(); $this->file = $file;
include $file; $this->node = simplexml_load_file($file);
$result = ob_get_contents();
ob_clean(); $this->target = '';
return $result; $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); $this->actions[$name] = $action;
$path = new Path($dstPath); }
$files = $path->getContentRec(null, array(".svn"));
foreach ($files as $file) { /**
if (Path::getExtension($file) == $tplFile) { * Установка переменных для шаблона
// Шаблон */
$dst = $out->append($path->relPath (Path::skipExtension($file))); public function set($name, $value)
Path::prepare($dst); {
file_put_contents($dst, self::fileContent($file, $tpl)); $this->context[$name] = $value;
} else { }
// Обычный файл
$dst = $out->append($path->relPath ($file)); function replaceFn($matches) {
Path::prepare($dst); if (isset($this->context[$matches[2]])) {
copy($file, $dst); $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 команд * Выполнение Списка 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) { foreach ($stmtList as $stmt) {
$conn->executeQuery ($stmt); $conn->executeQuery ($stmt);
} }
} }
} }

View file

@ -10,7 +10,7 @@ class Shortcut
public $list = array(); public $list = array();
// Singleton pattern // Singleton pattern
static public function getInstance () static public function getInstance()
{ {
if (self::$instance == null) { if (self::$instance == null) {
self::$instance = new Shortcut(); self::$instance = new Shortcut();
@ -24,7 +24,7 @@ class Shortcut
*/ */
public function addUrl($prefix, $path) 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(); $shortcut = self::getInstance();
$names = $shortcut->variables; $names = $shortcut->variables;
if ($name) { if ($name) {
$names['$name'] = $name; $names['$name'] = $name;
@ -48,10 +49,18 @@ class Shortcut
if ($name1) { if ($name1) {
$names['$name1'] = $name1; $names['$name1'] = $name1;
} }
if (isset($shortcut->list[$prefix])) { if (isset($shortcut->list[$prefix])) {
return strtr($shortcut->list[$prefix], $names); return strtr($shortcut->list[$prefix], $names);
} }
return false; return null;
} }
}
static function expand($path)
{
$shortcut = self::getInstance();
$names = $shortcut->variables;
return strtr($path, $names);
}
}

View file

@ -2,33 +2,61 @@
/** /**
* Расширения для PHPTAL для отображения времени и даты * Расширения для PHPTAL для отображения времени и даты
* package utils
*/ */
class DateTime_Tales implements PHPTAL_Tales 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')); * TALES для подключения компонентов
$registry->registerPrefix('time', array('DateTime_Tales', 'time')); * component:name?param1=value1&param2=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) function phptal_date ($e)
{ {
return date ("d.m.Y", $e); return date("d.m.Y", $e);
} }
function phptal_time ($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'));

View file

@ -2,7 +2,6 @@
class Drawing class Drawing
{ {
const ALIGN_LEFT = "left"; const ALIGN_LEFT = "left";
const ALIGN_TOP = "top"; const ALIGN_TOP = "top";
const ALIGN_BOTTOM = "bottom"; const ALIGN_BOTTOM = "bottom";
@ -26,7 +25,6 @@ class Drawing
static function imagettftextbox(&$image, $size, $angle, $left, $top, $color, $font, $text, static function imagettftextbox(&$image, $size, $angle, $left, $top, $color, $font, $text,
$max_width, $max_height, $align, $valign) $max_width, $max_height, $align, $valign)
{ {
// echo var_dump($font);
// echo $left,"\n", $top, "\n"; // echo $left,"\n", $top, "\n";
// echo $max_width,"\n", $max_height, "\n"; // echo $max_width,"\n", $max_height, "\n";
// self::drawrectnagle($image, $left, $top, $max_width, $max_height, array(0xFF,0,0)); // self::drawrectnagle($image, $left, $top, $max_width, $max_height, array(0xFF,0,0));
@ -44,7 +42,6 @@ class Drawing
$last_width = 0; $last_width = 0;
for ($i = 0; $i < count($words); $i++) { for ($i = 0; $i < count($words); $i++) {
$item = $words[$i]; $item = $words[$i];
// echo "->", $font, "\n";
$dimensions = imagettfbbox($size, $angle, $font, $current_line . ($first_word ? '' : ' ') . $item); $dimensions = imagettfbbox($size, $angle, $font, $current_line . ($first_word ? '' : ' ') . $item);
$line_width = $dimensions[2] - $dimensions[0]; $line_width = $dimensions[2] - $dimensions[0];
$line_height = $dimensions[1] - $dimensions[7]; $line_height = $dimensions[1] - $dimensions[7];
@ -75,6 +72,7 @@ class Drawing
} }
// vertical align // vertical align
$top_offset = 0;
if ($valign == self::ALIGN_CENTER) { if ($valign == self::ALIGN_CENTER) {
$top_offset = ($max_height - $largest_line_height * count($lines)) / 2; $top_offset = ($max_height - $largest_line_height * count($lines)) / 2;
} elseif ($valign == self::ALIGN_BOTTOM) { } elseif ($valign == self::ALIGN_BOTTOM) {
@ -84,17 +82,15 @@ class Drawing
$top += $largest_line_height + $top_offset; $top += $largest_line_height + $top_offset;
$i = 0; $i = 0;
fb($lines);
fb($line_widths);
foreach ($lines as $line) { foreach ($lines as $line) {
// horizontal align // horizontal align
$left_offset = 0;
if ($align == self::ALIGN_CENTER) { if ($align == self::ALIGN_CENTER) {
$left_offset = ($max_width - $line_widths[$i]) / 2; $left_offset = ($max_width - $line_widths[$i]) / 2;
} elseif ($align == self::ALIGN_RIGHT) { } elseif ($align == self::ALIGN_RIGHT) {
$left_offset = ($max_width - $line_widths[$i]); $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); imagettftext($image, $size, $angle, $left + $left_offset, $top + ($largest_line_height * $i), $color, $font, $line);
$i++; $i++;
} }

40
src/view/composite.php Normal file
View file

@ -0,0 +1,40 @@
<?php
// CompositeView+PHPTAL
class View_Composite extends View_Top
{
private $tal;
function __construct($file)
{
parent::__construct($file);
$this->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();
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
class _View_Composite // AbstractCompositeView class View_Top // AbstractCompositeView
{ {
protected $_section = array(); // Вложенные шаблоны protected $_section = array(); // Вложенные шаблоны
// Блоки // Блоки
@ -257,42 +257,3 @@ class _View_Composite // AbstractCompositeView
} }
} }
// CompositeView+PHPTAL
class View_Composite extends _View_Composite
{
private $tal;
function __construct($file)
{
parent::__construct($file);
$this->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();
}
}

View file

@ -5,21 +5,28 @@
*/ */
class ZipFile extends ZipArchive class ZipFile extends ZipArchive
{ {
private $ignore = array('.', '..');
public function addIgnore($name)
{
$this->ignore [] = $name;
}
private function addDirDo($location, $name) private function addDirDo($location, $name)
{ {
assert(is_string($location) && is_string($name)); assert(is_string($location) && is_string($name));
$name .= '/'; $name .= '/';
$location .= '/'; $location .= '/';
$file = null;
// Read all Files in Dir // Read all Files in Dir
$dir = opendir($location); $dir = opendir($location);
while (($file = readdir($dir)) !== false) while (($file = readdir($dir)) !== false)
{ {
if ($file === '.' || $file === '..') continue; if (in_array($file, $this->ignore)) continue;
// Rekursiv, If dir: FlxZipArchive::addDir(), else ::File(); // 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); call_user_func(array($this, $call), $location . $file, $name . $file);
} }
} }