commit
3defa8f38b
136 changed files with 5015 additions and 9243 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
*.bak
|
||||||
|
|
@ -7,5 +7,9 @@
|
||||||
"email": "phedor@edu.yar.ru"
|
"email": "phedor@edu.yar.ru"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {}
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<?php
|
|
||||||
foreach (glob(dirname(__FILE__) . "/*.php") as $file)
|
|
||||||
require_once $file;
|
|
||||||
?>
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,433 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @package Core
|
|
||||||
*/
|
|
||||||
require_once 'core/json.php';
|
|
||||||
require_once 'core/form/form.php';
|
|
||||||
require_once 'core/controller/controller.php';
|
|
||||||
|
|
||||||
require_once 'core/widgets/pagemenu.php';
|
|
||||||
require_once 'core/widgets/menu.php';
|
|
||||||
require_once 'core/widgets/search.php';
|
|
||||||
require_once 'core/widgets/setup.php';
|
|
||||||
require_once 'core/widgets/listtable.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Переименовать контроллер !! (StubController, CrudController, PageController, BaseController) ModelController
|
|
||||||
* Возможно нужен еще класс с мета действиями как для actionIndex <= metaActionIndex либо с классам для этих действий
|
|
||||||
* Есть класс для управлениями действиями а есть сами действия в виде классов или функций !!
|
|
||||||
*/
|
|
||||||
class Controller_Model extends Controller_Action
|
|
||||||
{
|
|
||||||
public $schema = array();
|
|
||||||
public $schemaSearch = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FIXME: Лучше $this->table->setHeader
|
|
||||||
*/
|
|
||||||
public $tableSchema = null;
|
|
||||||
public $formSchema = array();
|
|
||||||
|
|
||||||
public $menu;
|
|
||||||
public $path;
|
|
||||||
public $table;
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/path.php';
|
|
||||||
|
|
||||||
class FileNotFountException extends Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс компонента
|
|
||||||
*/
|
|
||||||
class Component
|
|
||||||
{
|
|
||||||
static $_uid = 1;
|
|
||||||
public $uid; // UID компонента создается при создании страницы, вставки компонента, или это статическое свойство
|
|
||||||
public $viewPath;
|
|
||||||
public $registry; // Registry->getInstance
|
|
||||||
public $template;
|
|
||||||
|
|
||||||
function __construct()
|
|
||||||
{
|
|
||||||
self::$_uid ++;
|
|
||||||
$this->uid = self::$_uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUID()
|
|
||||||
{
|
|
||||||
return 'component:'. $this->uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getView($name)
|
|
||||||
{
|
|
||||||
require_once "core/view/compositeview.php";
|
|
||||||
//
|
|
||||||
$template = ($this->template) ? $this->template : $this->_registry->readKey(array('system', 'template'));
|
|
||||||
// Загружать шаблон по умолчанию если не найден текущий
|
|
||||||
if (is_dir(Path::join($this->viewPath, 'templates', $template))) {
|
|
||||||
$template_file = Path::join($this->viewPath, 'templates', $template, $name);
|
|
||||||
} else {
|
|
||||||
$template_file = Path::join($this->viewPath, 'templates', 'modern', $name);
|
|
||||||
}
|
|
||||||
$tpl = new View_Composite($template_file);
|
|
||||||
|
|
||||||
$tpl->script = $_script = Path::join(WWW_PATH, 'js');
|
|
||||||
$tpl->media = $_media = Path::join(TEMPLATE_WEB, $template);
|
|
||||||
$tpl->component = $_template = Path::join(COMPONENTS_WEB, strtolower(get_class($this)), 'templates', 'modern');
|
|
||||||
$tpl->setAlias(array(
|
|
||||||
'${media}' => $_media,
|
|
||||||
'${script}' => $_script,
|
|
||||||
'${template}' => $_template));
|
|
||||||
|
|
||||||
$tpl->loadImports(Path::skipExtension($template_file) . ".import");
|
|
||||||
|
|
||||||
return $tpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setParameters($view)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $name Имя модели
|
|
||||||
*/
|
|
||||||
private function getModelPath($name)
|
|
||||||
{
|
|
||||||
return Path::join (CMS_PATH, "model", $name . ".php");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает модель
|
|
||||||
* @param string $name
|
|
||||||
* @return model
|
|
||||||
*/
|
|
||||||
public function getModel($name)
|
|
||||||
{
|
|
||||||
require_once 'core/mapper/mapper.php';
|
|
||||||
|
|
||||||
require_once ($this->getModelPath ($name));
|
|
||||||
$modelName = $name . "Mapper";
|
|
||||||
$model = new $modelName ();
|
|
||||||
$model->db = $this->db;
|
|
||||||
return $model;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function options($key, $val, $res) {
|
|
||||||
$result = array();
|
|
||||||
while($res->next()) {
|
|
||||||
$result[] = array('value' => $res->getInt($key), 'name' => $res->getString($val));
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function optionsPair($list) {
|
|
||||||
$result = array();
|
|
||||||
foreach ($list as $key => $value) {
|
|
||||||
$result [] = array('value' => $key, 'name' => $value);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* В дальнейшем нужно зменить на методы
|
|
||||||
+ Методы могут быть и javascript
|
|
||||||
*/
|
|
||||||
protected $editUrl;
|
|
||||||
|
|
||||||
function setEditUrl($url)
|
|
||||||
{
|
|
||||||
$this->editUrl = $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEditUrl()
|
|
||||||
{
|
|
||||||
return $this->editUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TALES для подключения компонентов
|
|
||||||
* component:name?param1=value1¶m2=value2
|
|
||||||
*/
|
|
||||||
class Component_Tales implements PHPTAL_Tales
|
|
||||||
{
|
|
||||||
static public function component($expression, $nothrow = false)
|
|
||||||
{
|
|
||||||
return "phptal_component('" . $expression . "')";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadComponent($name, $db, $registry)
|
|
||||||
{
|
|
||||||
$path = Path::join(COMPONENTS, $name, $name . ".php");
|
|
||||||
// echo COMPONENTS, '<br />';
|
|
||||||
// echo $path;
|
|
||||||
if (file_exists($path)) {
|
|
||||||
require_once ($path);
|
|
||||||
$component = new $name();
|
|
||||||
$component->db = $db;
|
|
||||||
$component->_registry = $registry;
|
|
||||||
$component->viewPath = COMPONENTS."/".$name."/";
|
|
||||||
return $component;
|
|
||||||
}
|
|
||||||
throw new FileNotFountException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Функция подключения компонента
|
|
||||||
*/
|
|
||||||
global $componentList;
|
|
||||||
$componentList = array();
|
|
||||||
|
|
||||||
function phptal_component ($real_expression, $offset = 0) {
|
|
||||||
global $db, $registry, $componentList; // Нужно както передавать параметры
|
|
||||||
|
|
||||||
$expression = htmlspecialchars_decode($real_expression);
|
|
||||||
$url = parse_url($expression);
|
|
||||||
parse_str($url['query'], $arguments);
|
|
||||||
$name = $url['path'];
|
|
||||||
|
|
||||||
$component = loadComponent($name, $db, $registry);
|
|
||||||
$req = new HttpRequest();
|
|
||||||
$params = new Collection();
|
|
||||||
$params->import(array_merge($_GET, $arguments));
|
|
||||||
$component->params = $params;
|
|
||||||
|
|
||||||
$componentList [] = array(
|
|
||||||
'uid' => $component->getUID(), 'params' => $expression, 'name' => $name, 'offset' => $offset,
|
|
||||||
'size' => strlen($real_expression),
|
|
||||||
/* Вместо ссылки на редактирование нужно передавать список методов для работы с компонентом
|
|
||||||
edit (редактирование содержание), new (новое содержание), шаблон коменнента ... вместе с иконками этих методов
|
|
||||||
! Компоненты могут содержать другие компоненты
|
|
||||||
*/
|
|
||||||
'editurl' => $component->getEditUrl(),
|
|
||||||
'newurl' => ''
|
|
||||||
);
|
|
||||||
|
|
||||||
unset($req['active_page']);
|
|
||||||
$component->template = $params->get('template', false);
|
|
||||||
|
|
||||||
return $component->execute($params, $req);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Регистрация нового префикса для подключения компонента */
|
|
||||||
$registry = PHPTAL_TalesRegistry::getInstance();
|
|
||||||
$registry->registerPrefix('component', array('Component_Tales', 'component'));
|
|
||||||
|
|
||||||
|
|
@ -1,343 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/path.php';
|
|
||||||
require_once 'core/mapper/factory.php';
|
|
||||||
require_once 'core/functions.php';
|
|
||||||
|
|
||||||
|
|
||||||
function forceUrl($name)
|
|
||||||
{
|
|
||||||
if (is_callable($name)) {
|
|
||||||
return call_user_func($name);
|
|
||||||
}
|
|
||||||
return $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер страниц
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class 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 {}
|
|
||||||
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
$settings = array
|
|
||||||
(
|
|
||||||
0 => '',
|
|
||||||
1 => 'Город Ярославль',
|
|
||||||
2 => 'Большесельский район',
|
|
||||||
3 => 'Борисоглебский район',
|
|
||||||
4 => 'Брейтовский район',
|
|
||||||
5 => 'Гаврилов-Ямский район',
|
|
||||||
6 => 'Даниловский район',
|
|
||||||
7 => 'Любимский район',
|
|
||||||
8 => 'Мышкинский район',
|
|
||||||
9 => 'Некоузский район',
|
|
||||||
10 => 'Некрасовский район',
|
|
||||||
11 => 'Переславский район',
|
|
||||||
12 => 'Первомайский район',
|
|
||||||
13 => 'Пошехонский район',
|
|
||||||
14 => 'Ростовский район',
|
|
||||||
15 => 'Рыбинский район',
|
|
||||||
16 => 'Тутаевский район',
|
|
||||||
17 => 'Угличский район',
|
|
||||||
18 => 'Ярославский район',
|
|
||||||
19 => 'Город Переславль',
|
|
||||||
20 => 'Город Рыбинск'
|
|
||||||
);
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
$settings = array(
|
|
||||||
0 => '',
|
|
||||||
1 => 'г.',
|
|
||||||
2 => 'с.',
|
|
||||||
3 => 'п.',
|
|
||||||
4 => 'д.',
|
|
||||||
5 => 'пгт.',
|
|
||||||
6 => 'р.п.',
|
|
||||||
7 => 'ст.',
|
|
||||||
8 => 'а.'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// Массив типов поселений
|
|
||||||
$settings = array(
|
|
||||||
// 0 => '',
|
|
||||||
1 => 'город',
|
|
||||||
2 => 'село',
|
|
||||||
3 => 'поселок',
|
|
||||||
4 => 'деревня',
|
|
||||||
5 => 'поселок городского типа',
|
|
||||||
6 => 'рабочий поселок',
|
|
||||||
7 => 'станица',
|
|
||||||
8 => 'аул'
|
|
||||||
);
|
|
||||||
|
|
@ -1,196 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* http://www.w3schools.com/media/media_mimeref.asp
|
|
||||||
*/
|
|
||||||
|
|
||||||
$settings = array (
|
|
||||||
"" => "application/octet-stream",
|
|
||||||
"323" => "text/h323",
|
|
||||||
"acx" => "application/internet-property-stream",
|
|
||||||
"ai" => "application/postscript",
|
|
||||||
"aif" => "audio/x-aiff",
|
|
||||||
"aifc" => "audio/x-aiff",
|
|
||||||
"aiff" => "audio/x-aiff",
|
|
||||||
"asf" => "video/x-ms-asf",
|
|
||||||
"asr" => "video/x-ms-asf",
|
|
||||||
"asx" => "video/x-ms-asf",
|
|
||||||
"au" => "audio/basic",
|
|
||||||
"avi" => "video/x-msvideo",
|
|
||||||
"axs" => "application/olescript",
|
|
||||||
"bas" => "text/plain",
|
|
||||||
"bcpio" => "application/x-bcpio",
|
|
||||||
"bin" => "application/octet-stream",
|
|
||||||
"bmp" => "image/bmp",
|
|
||||||
"c" => "text/plain",
|
|
||||||
"cat" => "application/vnd.ms-pkiseccat",
|
|
||||||
"cdf" => "application/x-cdf",
|
|
||||||
"cer" => "application/x-x509-ca-cert",
|
|
||||||
"class" => "application/octet-stream",
|
|
||||||
"clp" => "application/x-msclip",
|
|
||||||
"cmx" => "image/x-cmx",
|
|
||||||
"cod" => "image/cis-cod",
|
|
||||||
"cpio" => "application/x-cpio",
|
|
||||||
"crd" => "application/x-mscardfile",
|
|
||||||
"crl" => "application/pkix-crl",
|
|
||||||
"crt" => "application/x-x509-ca-cert",
|
|
||||||
"csh" => "application/x-csh",
|
|
||||||
"css" => "text/css",
|
|
||||||
"dcr" => "application/x-director",
|
|
||||||
"der" => "application/x-x509-ca-cert",
|
|
||||||
"dir" => "application/x-director",
|
|
||||||
"dll" => "application/x-msdownload",
|
|
||||||
"dms" => "application/octet-stream",
|
|
||||||
"doc" => "application/msword",
|
|
||||||
"dot" => "application/msword",
|
|
||||||
"dvi" => "application/x-dvi",
|
|
||||||
"dxr" => "application/x-director",
|
|
||||||
"eps" => "application/postscript",
|
|
||||||
"etx" => "text/x-setext",
|
|
||||||
"evy" => "application/envoy",
|
|
||||||
"exe" => "application/octet-stream",
|
|
||||||
"fif" => "application/fractals",
|
|
||||||
"flr" => "x-world/x-vrml",
|
|
||||||
"gif" => "image/gif",
|
|
||||||
"gtar" => "application/x-gtar",
|
|
||||||
"gz" => "application/x-gzip",
|
|
||||||
"h" => "text/plain",
|
|
||||||
"hdf" => "application/x-hdf",
|
|
||||||
"hlp" => "application/winhlp",
|
|
||||||
"hqx" => "application/mac-binhex40",
|
|
||||||
"hta" => "application/hta",
|
|
||||||
"htc" => "text/x-component",
|
|
||||||
"htm" => "text/html",
|
|
||||||
"html" => "text/html",
|
|
||||||
"htt" => "text/webviewhtml",
|
|
||||||
"ico" => "image/x-icon",
|
|
||||||
"ief" => "image/ief",
|
|
||||||
"iii" => "application/x-iphone",
|
|
||||||
"ins" => "application/x-internet-signup",
|
|
||||||
"isp" => "application/x-internet-signup",
|
|
||||||
"jfif" => "image/pipeg",
|
|
||||||
"jpe" => "image/jpeg",
|
|
||||||
"jpeg" => "image/jpeg",
|
|
||||||
"jpg" => "image/jpeg",
|
|
||||||
"js" => "application/x-javascript",
|
|
||||||
"latex" => "application/x-latex",
|
|
||||||
"lha" => "application/octet-stream",
|
|
||||||
"lsf" => "video/x-la-asf",
|
|
||||||
"lsx" => "video/x-la-asf",
|
|
||||||
"lzh" => "application/octet-stream",
|
|
||||||
"m13" => "application/x-msmediaview",
|
|
||||||
"m14" => "application/x-msmediaview",
|
|
||||||
"m3u" => "audio/x-mpegurl",
|
|
||||||
"man" => "application/x-troff-man",
|
|
||||||
"mdb" => "application/x-msaccess",
|
|
||||||
"me" => "application/x-troff-me",
|
|
||||||
"mht" => "message/rfc822",
|
|
||||||
"mhtml" => "message/rfc822",
|
|
||||||
"mid" => "audio/mid",
|
|
||||||
"mny" => "application/x-msmoney",
|
|
||||||
"mov" => "video/quicktime",
|
|
||||||
"movie" => "video/x-sgi-movie",
|
|
||||||
"mp2" => "video/mpeg",
|
|
||||||
"mp3" => "audio/mpeg",
|
|
||||||
"mpa" => "video/mpeg",
|
|
||||||
"mpe" => "video/mpeg",
|
|
||||||
"mpeg" => "video/mpeg",
|
|
||||||
"mpg" => "video/mpeg",
|
|
||||||
"mpp" => "application/vnd.ms-project",
|
|
||||||
"mpv2" => "video/mpeg",
|
|
||||||
"ms" => "application/x-troff-ms",
|
|
||||||
"mvb" => "application/x-msmediaview",
|
|
||||||
"nws" => "message/rfc822",
|
|
||||||
"oda" => "application/oda",
|
|
||||||
"p10" => "application/pkcs10",
|
|
||||||
"p12" => "application/x-pkcs12",
|
|
||||||
"p7b" => "application/x-pkcs7-certificates",
|
|
||||||
"p7c" => "application/x-pkcs7-mime",
|
|
||||||
"p7m" => "application/x-pkcs7-mime",
|
|
||||||
"p7r" => "application/x-pkcs7-certreqresp",
|
|
||||||
"p7s" => "application/x-pkcs7-signature",
|
|
||||||
"pbm" => "image/x-portable-bitmap",
|
|
||||||
"pdf" => "application/pdf",
|
|
||||||
"pfx" => "application/x-pkcs12",
|
|
||||||
"pgm" => "image/x-portable-graymap",
|
|
||||||
"pko" => "application/ynd.ms-pkipko",
|
|
||||||
"pma" => "application/x-perfmon",
|
|
||||||
"pmc" => "application/x-perfmon",
|
|
||||||
"pml" => "application/x-perfmon",
|
|
||||||
"pmr" => "application/x-perfmon",
|
|
||||||
"pmw" => "application/x-perfmon",
|
|
||||||
"pnm" => "image/x-portable-anymap",
|
|
||||||
"pot," => "application/vnd.ms-powerpoint",
|
|
||||||
"ppm" => "image/x-portable-pixmap",
|
|
||||||
"pps" => "application/vnd.ms-powerpoint",
|
|
||||||
"ppt" => "application/vnd.ms-powerpoint",
|
|
||||||
"prf" => "application/pics-rules",
|
|
||||||
"ps" => "application/postscript",
|
|
||||||
"pub" => "application/x-mspublisher",
|
|
||||||
"qt" => "video/quicktime",
|
|
||||||
"ra" => "audio/x-pn-realaudio",
|
|
||||||
"ram" => "audio/x-pn-realaudio",
|
|
||||||
"ras" => "image/x-cmu-raster",
|
|
||||||
"rgb" => "image/x-rgb",
|
|
||||||
"rmi" => "audio/mid",
|
|
||||||
"roff" => "application/x-troff",
|
|
||||||
"rtf" => "application/rtf",
|
|
||||||
"rtx" => "text/richtext",
|
|
||||||
"scd" => "application/x-msschedule",
|
|
||||||
"sct" => "text/scriptlet",
|
|
||||||
"setpay" => "application/set-payment-initiation",
|
|
||||||
"setreg" => "application/set-registration-initiation",
|
|
||||||
"sh" => "application/x-sh",
|
|
||||||
"shar" => "application/x-shar",
|
|
||||||
"sit" => "application/x-stuffit",
|
|
||||||
"snd" => "audio/basic",
|
|
||||||
"spc" => "application/x-pkcs7-certificates",
|
|
||||||
"spl" => "application/futuresplash",
|
|
||||||
"src" => "application/x-wais-source",
|
|
||||||
"sst" => "application/vnd.ms-pkicertstore",
|
|
||||||
"stl" => "application/vnd.ms-pkistl",
|
|
||||||
"stm" => "text/html",
|
|
||||||
"svg" => "image/svg+xml",
|
|
||||||
"sv4cpio" => "application/x-sv4cpio",
|
|
||||||
"sv4crc" => "application/x-sv4crc",
|
|
||||||
"swf" => "application/x-shockwave-flash",
|
|
||||||
"t" => "application/x-troff",
|
|
||||||
"tar" => "application/x-tar",
|
|
||||||
"tcl" => "application/x-tcl",
|
|
||||||
"tex" => "application/x-tex",
|
|
||||||
"texi" => "application/x-texinfo",
|
|
||||||
"texinfo" => "application/x-texinfo",
|
|
||||||
"tgz" => "application/x-compressed",
|
|
||||||
"tif" => "image/tiff",
|
|
||||||
"tiff" => "image/tiff",
|
|
||||||
"tr" => "application/x-troff",
|
|
||||||
"trm" => "application/x-msterminal",
|
|
||||||
"tsv" => "text/tab-separated-values",
|
|
||||||
"txt" => "text/plain",
|
|
||||||
"uls" => "text/iuls",
|
|
||||||
"ustar" => "application/x-ustar",
|
|
||||||
"vcf" => "text/x-vcard",
|
|
||||||
"vrml" => "x-world/x-vrml",
|
|
||||||
"wav" => "audio/x-wav",
|
|
||||||
"wcm" => "application/vnd.ms-works",
|
|
||||||
"wdb" => "application/vnd.ms-works",
|
|
||||||
"wks" => "application/vnd.ms-works",
|
|
||||||
"wmf" => "application/x-msmetafile",
|
|
||||||
"wps" => "application/vnd.ms-works",
|
|
||||||
"wri" => "application/x-mswrite",
|
|
||||||
"wrl" => "x-world/x-vrml",
|
|
||||||
"wrz" => "x-world/x-vrml",
|
|
||||||
"xaf" => "x-world/x-vrml",
|
|
||||||
"xbm" => "image/x-xbitmap",
|
|
||||||
"xla" => "application/vnd.ms-excel",
|
|
||||||
"xlc" => "application/vnd.ms-excel",
|
|
||||||
"xlm" => "application/vnd.ms-excel",
|
|
||||||
"xls" => "application/vnd.ms-excel",
|
|
||||||
"xlt" => "application/vnd.ms-excel",
|
|
||||||
"xlw" => "application/vnd.ms-excel",
|
|
||||||
"xof" => "x-world/x-vrml",
|
|
||||||
"xpm" => "image/x-xpixmap",
|
|
||||||
"xwd" => "image/x-xwindowdump",
|
|
||||||
"z" => "application/x-compress",
|
|
||||||
"zip" => "application/zip",
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
// В ОКАТО приняты следующие сокращения:
|
|
||||||
// http://www.consultant.ru/online/base/?req=doc;base=LAW;n=62484
|
|
||||||
|
|
||||||
$settings = array (
|
|
||||||
"р-н" => "район",
|
|
||||||
"г" => "город",
|
|
||||||
"пгт" => "поселок городского типа",
|
|
||||||
"рп" => "рабочий поселок",
|
|
||||||
"кп" => "курортный поселок",
|
|
||||||
"к" => "кишлак",
|
|
||||||
"пс" => "поселковый совет",
|
|
||||||
"сс" => "сельсовет",
|
|
||||||
"смн" => "сомон",
|
|
||||||
"вл" => "волость",
|
|
||||||
"дп" => "дачный поселковый совет",
|
|
||||||
"п" => "поселок сельского типа",
|
|
||||||
"нп" => "населенный пункт",
|
|
||||||
"п. ст" => "поселок при станции",
|
|
||||||
"ж/д ст" => "железнодорожная станция",
|
|
||||||
"с" => "село",
|
|
||||||
"м" => "местечко",
|
|
||||||
"д" => "деревня",
|
|
||||||
"сл" => "слобода",
|
|
||||||
"ст" => "станция",
|
|
||||||
"ст-ца" => "станица",
|
|
||||||
"х" => "хутор",
|
|
||||||
"у" => "улус",
|
|
||||||
"рзд" => "разъезд",
|
|
||||||
"клх" => "колхоз",
|
|
||||||
"им" => "имени",
|
|
||||||
"свх" => "совхоз",
|
|
||||||
"зим" => "зимовье",
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
$settings = array (
|
|
||||||
0 => '',
|
|
||||||
2 => 'Алтайский край',
|
|
||||||
3 => 'Амурская область',
|
|
||||||
4 => 'Архангельская область',
|
|
||||||
5 => 'Астраханская область',
|
|
||||||
6 => 'Белгородская область',
|
|
||||||
7 => 'Брянская область',
|
|
||||||
8 => 'Владимирская область',
|
|
||||||
9 => 'Волгоградская область',
|
|
||||||
10 => 'Вологодская область',
|
|
||||||
11 => 'Воронежская область',
|
|
||||||
12 => 'г. Москва',
|
|
||||||
13 => 'г. Санкт-Петербург',
|
|
||||||
14 => 'Еврейская автономная область',
|
|
||||||
84 => 'Забайкальский край',
|
|
||||||
15 => 'Ивановская область',
|
|
||||||
16 => 'Иркутская область',
|
|
||||||
17 => 'Кабардино-Балкарская Республика',
|
|
||||||
18 => 'Калининградская область',
|
|
||||||
19 => 'Калужская область',
|
|
||||||
20 => 'Камчатский край',
|
|
||||||
21 => 'Карачаево-Черкесская Республика',
|
|
||||||
22 => 'Кемеровская область',
|
|
||||||
23 => 'Кировская область',
|
|
||||||
28 => 'Костромская область',
|
|
||||||
29 => 'Краснодарский край',
|
|
||||||
30 => 'Красноярский край',
|
|
||||||
31 => 'Курганская область',
|
|
||||||
32 => 'Курская область',
|
|
||||||
33 => 'Ленинградская область',
|
|
||||||
34 => 'Липецкая область',
|
|
||||||
35 => 'Магаданская область',
|
|
||||||
36 => 'Московская область',
|
|
||||||
37 => 'Мурманская область',
|
|
||||||
38 => 'Ненецкий автономный округ',
|
|
||||||
39 => 'Нижегородская область',
|
|
||||||
40 => 'Новгородская область',
|
|
||||||
41 => 'Новосибирская область',
|
|
||||||
42 => 'Омская область',
|
|
||||||
43 => 'Оренбургская область',
|
|
||||||
44 => 'Орловская область',
|
|
||||||
45 => 'Пензенская область',
|
|
||||||
46 => 'Пермский край',
|
|
||||||
47 => 'Приморский край',
|
|
||||||
48 => 'Псковская область',
|
|
||||||
49 => 'Республика Адыгея',
|
|
||||||
50 => 'Республика Алтай',
|
|
||||||
51 => 'Республика Башкортостан',
|
|
||||||
52 => 'Республика Бурятия',
|
|
||||||
25 => 'Республика Дагестан',
|
|
||||||
26 => 'Республика Ингушетия',
|
|
||||||
53 => 'Республика Калмыкия',
|
|
||||||
54 => 'Республика Карелия',
|
|
||||||
55 => 'Республика Коми',
|
|
||||||
56 => 'Республика Марий Эл',
|
|
||||||
57 => 'Республика Мордовия',
|
|
||||||
58 => 'Республика Саха(Якутия)',
|
|
||||||
59 => 'Республика Северная Осетия-Алания',
|
|
||||||
60 => 'Республика Татарстан',
|
|
||||||
61 => 'Республика Тыва',
|
|
||||||
62 => 'Республика Хакасия',
|
|
||||||
63 => 'Ростовская область',
|
|
||||||
64 => 'Рязанская область',
|
|
||||||
65 => 'Самарская область',
|
|
||||||
66 => 'Саратовская область',
|
|
||||||
67 => 'Сахалинская область',
|
|
||||||
68 => 'Свердловская область',
|
|
||||||
69 => 'Смоленская область',
|
|
||||||
70 => 'Ставропольский край',
|
|
||||||
71 => 'Таймырский (Долгано-Ненецкий) автономный округ',
|
|
||||||
72 => 'Тамбовская область',
|
|
||||||
73 => 'Тверская область',
|
|
||||||
74 => 'Томская область',
|
|
||||||
75 => 'Тульская область',
|
|
||||||
76 => 'Тюменская область',
|
|
||||||
77 => 'Удмуртская Республика',
|
|
||||||
78 => 'Ульяновская область',
|
|
||||||
80 => 'Хабаровский край',
|
|
||||||
81 => 'Ханты-Мансийский автономный округ',
|
|
||||||
82 => 'Челябинская область',
|
|
||||||
83 => 'Чеченская Республика',
|
|
||||||
85 => 'Чувашская Республика',
|
|
||||||
86 => 'Чукотский автономный округ',
|
|
||||||
87 => 'Эвенкийский автономный округ',
|
|
||||||
88 => 'Ямало-Ненецкий автономный округ',
|
|
||||||
89 => 'Ярославская область'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
$settings = array (
|
|
||||||
0 => array('title' => ''),
|
|
||||||
1 => array(
|
|
||||||
'title' => 'Центральный федеральный округ',
|
|
||||||
'short' => 'ЦФО',
|
|
||||||
'regions' => array(6, 7, 8, 11, 12, 15, 19, 28, 32, 34, 36, 44, 64, 69, 72, 73, 75, 89)),
|
|
||||||
2 => array(
|
|
||||||
'title' => 'Южный федеральный округ',
|
|
||||||
'short' => 'ЮФО',
|
|
||||||
'regions' => array(5, 9, 17, 21, 29, 49, 25, 26, 53, 59, 63, 70, 83)),
|
|
||||||
3 => array(
|
|
||||||
'title' => 'Северо-западный федеральный округ',
|
|
||||||
'short' => 'СЗФО',
|
|
||||||
'regions' => array(4, 10, 13, 18, 33, 37, 38, 40, 48, 54, 55)),
|
|
||||||
4 => array(
|
|
||||||
'title' => 'Дальневосточный федеральный округ',
|
|
||||||
'short' => 'ДФО',
|
|
||||||
'regions' => array(3, 14, 20, 35, 47, 58, 67, 80, 86)),
|
|
||||||
5 => array(
|
|
||||||
'title' => 'Сибирский федеральный округ',
|
|
||||||
'short' => 'СФО',
|
|
||||||
'regions' => array(2, 16, 22, 30, 41, 42, 50, 52, 61, 62, 71, 74, 84, 86, 87)),
|
|
||||||
6 => array(
|
|
||||||
'title' => 'Уральский федеральный округ',
|
|
||||||
'short' => 'УФО',
|
|
||||||
'regions' => array(31, 68, 76, 81, 82, 88)),
|
|
||||||
7 => array(
|
|
||||||
'title' => 'Приволжский федеральный округ',
|
|
||||||
'short' => 'ПФО',
|
|
||||||
'regions' => array(23, 39, 43, 45, 46, 51, 56, 57, 60, 65, 66, 77, 78, 85)));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Простой класс(Factory) для работы с базами данных
|
|
||||||
*/
|
|
||||||
class Database
|
|
||||||
{
|
|
||||||
static function getConnection (array $dsn)
|
|
||||||
{
|
|
||||||
require_once "core/drivers/database." . strtolower($dsn['phptype']) . ".php";
|
|
||||||
$name = "Database_" . strtoupper($dsn['phptype']);
|
|
||||||
$database = new $name();
|
|
||||||
$database->connect($dsn);
|
|
||||||
return $database;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,407 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package system.db
|
|
||||||
* Класс оболочка для PDO для замены Creole
|
|
||||||
*/
|
|
||||||
class Database extends PDO
|
|
||||||
{
|
|
||||||
public function __construct($dsn, $username = false, $password = false)
|
|
||||||
{
|
|
||||||
parent::__construct($dsn, $username, $password);
|
|
||||||
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
||||||
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDODatabaseStatement', array()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDSN()
|
|
||||||
{
|
|
||||||
return $this->dsn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isPostgres(){
|
|
||||||
return ($this->dsn["phptype"] == "pgsql");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Создает соединение с базой данных
|
|
||||||
*/
|
|
||||||
static function getConnection(array $dsn)
|
|
||||||
{
|
|
||||||
if ($dsn['phptype'] == 'pgsql' || $dsn['phptype'] == 'mysql') {
|
|
||||||
$port = (isset($dsn['port'])) ? "port={$dsn['port']};" : "";
|
|
||||||
$connection = new Database("{$dsn['phptype']}:host={$dsn['hostspec']}; $port dbname={$dsn['database']}", $dsn['username'], $dsn['password']);
|
|
||||||
$connection->query('SET client_encoding = "UTF-8"');
|
|
||||||
}
|
|
||||||
if ($dsn['phptype'] == 'sqlite') {
|
|
||||||
$connection = new Database("{$dsn['phptype']}:{$dsn['database']}");
|
|
||||||
}
|
|
||||||
$connection->dsn = $dsn;
|
|
||||||
return $connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function executeQuery($query)
|
|
||||||
{
|
|
||||||
$stmt = $this->prepare($query);
|
|
||||||
$stmt->setFetchMode(PDO::FETCH_ASSOC);
|
|
||||||
$stmt->execute();
|
|
||||||
$stmt->cache = $stmt->fetchAll();
|
|
||||||
return $stmt;//$sth->fetchAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareStatement($query)
|
|
||||||
{
|
|
||||||
return new DatabaseStatement($query, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Для совместимости со старым представлением баз данных CIS
|
|
||||||
/**
|
|
||||||
* Извлекает из базы все элементы по запросу
|
|
||||||
*/
|
|
||||||
public function fetchAllArray($query,$values=null)
|
|
||||||
{
|
|
||||||
$sth = $this->prepare($query);
|
|
||||||
$prep = $this->prepareValues($values);
|
|
||||||
$sth->execute($prep);
|
|
||||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Извлекает из базы первый элемент по запросу
|
|
||||||
*/
|
|
||||||
public function fetchOneArray($query,$values=null)
|
|
||||||
{
|
|
||||||
$sth = $this->prepare($query);
|
|
||||||
$prep = $this->prepareValues($values);
|
|
||||||
$sth->execute($prep);
|
|
||||||
return $sth->fetch(PDO::FETCH_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assignQuote($x, $y)
|
|
||||||
{
|
|
||||||
return $x . "=" . $this->quote($y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function prepareValues($values)
|
|
||||||
{
|
|
||||||
if (!$values) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$pg = $this->isPostgres();
|
|
||||||
$prep = array();
|
|
||||||
foreach ($values as $key => $value) {
|
|
||||||
$result = null;
|
|
||||||
if(is_bool($value)) {
|
|
||||||
if ($pg) {
|
|
||||||
$result = $value ? 'true' : 'false';
|
|
||||||
} else {
|
|
||||||
$result = $value ? 1 : 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$result = $value;
|
|
||||||
}
|
|
||||||
$prep[":" . $key] = $result;
|
|
||||||
}
|
|
||||||
return $prep;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Создает INSERT запрос
|
|
||||||
*/
|
|
||||||
function insertQuery($table, array $values, $return_id = false, $index = null)
|
|
||||||
{
|
|
||||||
$prep = $this->prepareValues($values);
|
|
||||||
|
|
||||||
$sql = "INSERT INTO $table (" . implode(",", array_keys($values))
|
|
||||||
. ") VALUES (" . implode(",", array_keys($prep)). ")";
|
|
||||||
|
|
||||||
if($return_id){
|
|
||||||
if ($this->isPostgres()){
|
|
||||||
$sql = $sql." RETURNING $index";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$stmt = $this->prepare($sql);
|
|
||||||
$stmt->setFetchMode(PDO::FETCH_ASSOC);
|
|
||||||
$stmt->execute($prep);
|
|
||||||
$result = $stmt->fetch();
|
|
||||||
if ($return_id) {
|
|
||||||
if ($this->isPostgres()) {
|
|
||||||
return $result[$index];
|
|
||||||
} else {
|
|
||||||
$result = $this->fetchOneArray("SELECT $index AS lastid FROM $table WHERE OID = last_insert_rowid()");
|
|
||||||
return $result['lastid'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает UPDATE запрос
|
|
||||||
*/
|
|
||||||
function updateQuery($table, array $values, $cond)
|
|
||||||
{
|
|
||||||
return $this->query("UPDATE $table SET " . implode(",",
|
|
||||||
array_map(array($this, 'assignQuote'), array_keys($values), array_values($values))) . " WHERE $cond");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIdGenerator() {
|
|
||||||
return new IdGenerator($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Замечание: Только для Postgres SQL
|
|
||||||
* @param string $seq Имя последовательности для ключа таблицы
|
|
||||||
* @return int Идентефикатор следующей записи
|
|
||||||
*/
|
|
||||||
function getNextId($seq)
|
|
||||||
{
|
|
||||||
$result = $this->fetchOneArray("SELECT nextval('$seq')");
|
|
||||||
return $result['nextval'];
|
|
||||||
}
|
|
||||||
|
|
||||||
function close()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IdGenerator {
|
|
||||||
private $db;
|
|
||||||
|
|
||||||
function __construct($db) {
|
|
||||||
$this->db = $db;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBeforeInsert() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAfterInsert() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getId($seq) {
|
|
||||||
$result = $this->db->fetchOneArray("SELECT nextval('$seq')");
|
|
||||||
return $result['nextval'];
|
|
||||||
// $result = $this->db->fetchOneArray("SELECT last_insert_rowid() AS nextval");
|
|
||||||
// return $result['nextval'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PDODatabaseStatementIterator implements Iterator
|
|
||||||
{
|
|
||||||
|
|
||||||
private $result;
|
|
||||||
private $pos = 0;
|
|
||||||
private $fetchmode;
|
|
||||||
private $row_count;
|
|
||||||
private $rs;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct the iterator.
|
|
||||||
* @param PgSQLResultSet $rs
|
|
||||||
*/
|
|
||||||
public function __construct($rs)
|
|
||||||
{
|
|
||||||
$this->result = $rs;
|
|
||||||
$this->row_count = $rs->getRecordCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
function rewind()
|
|
||||||
{
|
|
||||||
$this->pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function valid()
|
|
||||||
{
|
|
||||||
return ($this->pos < $this->row_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
function key()
|
|
||||||
{
|
|
||||||
return $this->pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
function current()
|
|
||||||
{
|
|
||||||
if (!isset($this->result->cache[$this->pos])) {
|
|
||||||
$this->result->cache[$this->pos] = $this->result->fetch(PDO::FETCH_ASSOC);
|
|
||||||
}
|
|
||||||
return $this->result->cache[$this->pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
function next()
|
|
||||||
{
|
|
||||||
$this->pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
function seek ( $index )
|
|
||||||
{
|
|
||||||
$this->pos = $index;
|
|
||||||
}
|
|
||||||
|
|
||||||
function count ( ) {
|
|
||||||
return $this->row_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PDODatabaseStatement extends PDOStatement implements IteratorAggregate
|
|
||||||
{
|
|
||||||
protected $cursorPos = 0;
|
|
||||||
public $cache = array();
|
|
||||||
|
|
||||||
function getIterator()
|
|
||||||
{
|
|
||||||
return new PDODatabaseStatementIterator($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function __construct() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function rewind()
|
|
||||||
{
|
|
||||||
$this->cursorPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function seek($rownum)
|
|
||||||
{
|
|
||||||
if ($rownum < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PostgreSQL rows start w/ 0, but this works, because we are
|
|
||||||
// looking to move the position _before_ the next desired position
|
|
||||||
$this->cursorPos = $rownum;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function valid()
|
|
||||||
{
|
|
||||||
return ( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function first()
|
|
||||||
{
|
|
||||||
if($this->cursorPos !== 0) { $this->seek(0); }
|
|
||||||
return $this->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
function next()
|
|
||||||
{
|
|
||||||
if ($this->getRecordCount() > $this->cursorPos) {
|
|
||||||
if (!isset($this->cache[$this->cursorPos])) {
|
|
||||||
$this->cache[$this->cursorPos] = $this->fetch(PDO::FETCH_ASSOC);
|
|
||||||
}
|
|
||||||
$this->fields = $this->cache[$this->cursorPos];
|
|
||||||
|
|
||||||
$this->cursorPos++;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
$this->fields = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function key() {
|
|
||||||
return $this->cursorPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
function current()
|
|
||||||
{
|
|
||||||
return $this->result->fetch(PDO::FETCH_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRow()
|
|
||||||
{
|
|
||||||
return $this->fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getInt($name)
|
|
||||||
{
|
|
||||||
return intval($this->fields[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBlob($name)
|
|
||||||
{
|
|
||||||
return $this->fields[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getString($name)
|
|
||||||
{
|
|
||||||
return $this->fields[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBoolean($name)
|
|
||||||
{
|
|
||||||
return (bool)$this->fields[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($name)
|
|
||||||
{
|
|
||||||
return $this->fields[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRecordCount()
|
|
||||||
{
|
|
||||||
return count($this->cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс оболочка для PDOStatement для замены Creole
|
|
||||||
*/
|
|
||||||
class DatabaseStatement
|
|
||||||
{
|
|
||||||
protected $limit = null;
|
|
||||||
protected $offset = null;
|
|
||||||
protected $statement = null;
|
|
||||||
protected $binds = array();
|
|
||||||
protected $conn;
|
|
||||||
protected $query;
|
|
||||||
|
|
||||||
function __construct($query, $conn) {
|
|
||||||
$this->query = $query;
|
|
||||||
$this->conn = $conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setInt($n, $value)
|
|
||||||
{
|
|
||||||
$this->binds [] = array($n, $value, PDO::PARAM_INT);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setString($n, $value)
|
|
||||||
{
|
|
||||||
$this->binds [] = array($n, $value, PDO::PARAM_STR);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setBlob($n, $value)
|
|
||||||
{
|
|
||||||
$this->binds [] = array($n, $value, PDO::PARAM_LOB);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLimit($limit)
|
|
||||||
{
|
|
||||||
$this->limit = $limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOffset($offset)
|
|
||||||
{
|
|
||||||
$this->offset = $offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeQuery()
|
|
||||||
{
|
|
||||||
if ($this->limit) {
|
|
||||||
$this->query .= " LIMIT {$this->limit} OFFSET {$this->offset}";
|
|
||||||
}
|
|
||||||
$stmt = $this->conn->prepare($this->query);
|
|
||||||
foreach ($this->binds as $bind) {
|
|
||||||
list($n, $value, $type) = $bind;
|
|
||||||
$stmt->bindValue($n, $value, $type);
|
|
||||||
}
|
|
||||||
$stmt->setFetchMode(PDO::FETCH_ASSOC);
|
|
||||||
$stmt->execute();
|
|
||||||
$stmt->cache = $stmt->fetchAll();
|
|
||||||
|
|
||||||
return $stmt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/drivers/db.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Простой класс для работы с базами данных
|
|
||||||
*/
|
|
||||||
class Database_MYSQL extends DB implements IDatabase
|
|
||||||
{
|
|
||||||
public function connect(array $dsn)
|
|
||||||
{
|
|
||||||
$db = @mysql_pconnect($dsn['hostspec'], $dsn['username'], $dsn['password'])
|
|
||||||
or die("Unable connect to database!");
|
|
||||||
|
|
||||||
mysql_select_db($dsn['database']);
|
|
||||||
return ($this->db = $db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close()
|
|
||||||
{
|
|
||||||
return mysql_close($this->db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function query($query)
|
|
||||||
{
|
|
||||||
$res = mysql_query($this->db, $query)
|
|
||||||
or die("Error: wrong SQL query #$query#");
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchAllArray($query)
|
|
||||||
{
|
|
||||||
$res = $this->query($query);
|
|
||||||
|
|
||||||
while ($row = mysql_fetch_array ($res))
|
|
||||||
$rows[] = $row;
|
|
||||||
mysql_free_result($res);
|
|
||||||
return ($rows) ? $rows : array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchOneArray($query)
|
|
||||||
{
|
|
||||||
$res = $this->query($query);
|
|
||||||
$row = mysql_fetch_array($res);
|
|
||||||
mysql_free_result($res);
|
|
||||||
return ($row) ? $row : array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/drivers/db.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Простой класс для работы с базами данных
|
|
||||||
*/
|
|
||||||
class Database_ODBC extends DB implements IDatabase
|
|
||||||
{
|
|
||||||
public function connect(array $dsn)
|
|
||||||
{
|
|
||||||
$db = @odbc_connect($dsn['database'], $dsn['username'], $dsn['password'])
|
|
||||||
or die("Unable connect to database!");
|
|
||||||
return ($this->db = $db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close()
|
|
||||||
{
|
|
||||||
return odbc_close($this->db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function query($query)
|
|
||||||
{
|
|
||||||
$res = odbc_exec($this->db, $query)
|
|
||||||
or die("Error: wrong SQL query #$query#");
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchAllArray($query)
|
|
||||||
{
|
|
||||||
$res = $this->query($query);
|
|
||||||
$to = odbc_num_fields($res);
|
|
||||||
while (odbc_fetch_row($res)) {
|
|
||||||
for ($i = 1; $i <= $to; $i++) {
|
|
||||||
$row [odbc_field_name($res, $i)] = trim(odbc_result($res, $i));
|
|
||||||
}
|
|
||||||
$rows[] = $row;
|
|
||||||
}
|
|
||||||
return ($rows)? $rows : array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchOneArray($query)
|
|
||||||
{
|
|
||||||
$res = $this->query($query);
|
|
||||||
if (!odbc_fetch_row($res)) return array ();
|
|
||||||
$to = odbc_num_fields($res);
|
|
||||||
for ($i = 1; $i <= $to; $i++) {
|
|
||||||
$row [odbc_field_name($res, $i)] = trim(odbc_result($res, $i));
|
|
||||||
}
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/drivers/db.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Простой класс для работы с базами данных
|
|
||||||
*/
|
|
||||||
class Database_PGSQL extends DB implements IDatabase
|
|
||||||
{
|
|
||||||
public function connect(array $dsn)
|
|
||||||
{
|
|
||||||
if (isset($dsn['port'])) {
|
|
||||||
$port = "port={$dsn['port']}";
|
|
||||||
} else {
|
|
||||||
$port = "port=5432";
|
|
||||||
}
|
|
||||||
$str = "host={$dsn['hostspec']} $port dbname={$dsn['database']} user={$dsn['username']} password={$dsn['password']}";
|
|
||||||
$db = @pg_connect($str)
|
|
||||||
or die("Unable connect to database!");
|
|
||||||
|
|
||||||
return ($this->db = $db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close()
|
|
||||||
{
|
|
||||||
return pg_close($this->db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function query($query)
|
|
||||||
{
|
|
||||||
$res = pg_query($this->db, $query)
|
|
||||||
or die("Error: wrong SQL query #$query#");
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchAllArray($query, $type = PGSQL_ASSOC)
|
|
||||||
{
|
|
||||||
$res = $this->query($query);
|
|
||||||
|
|
||||||
$rows = array();
|
|
||||||
while ($row = pg_fetch_array($res, NULL, $type)) {
|
|
||||||
$rows[] = $this->clean($row);
|
|
||||||
}
|
|
||||||
pg_free_result($res);
|
|
||||||
return ($rows) ? $rows : array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function affectedRows()
|
|
||||||
{
|
|
||||||
return pg_affected_rows($this->db);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function clean($row)
|
|
||||||
{
|
|
||||||
foreach ($row as $key => $value) {
|
|
||||||
$row[$key] = trim($value);
|
|
||||||
}
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchOneArray($query, $type = PGSQL_ASSOC)
|
|
||||||
{
|
|
||||||
$res = $this->query($query);
|
|
||||||
$row = pg_fetch_array($res, NULL, $type);
|
|
||||||
pg_free_result($res);
|
|
||||||
return ($row) ? $this->clean($row) : array();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNextId($seq)
|
|
||||||
{
|
|
||||||
$result = $this->fetchOneArray("SELECT nextval('$seq')");
|
|
||||||
return $result['nextval'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Интерфейс драйвера класса баз данных
|
|
||||||
*/
|
|
||||||
interface IDatabase
|
|
||||||
{
|
|
||||||
public function connect(array $dsn);
|
|
||||||
public function close();
|
|
||||||
public function query($query);
|
|
||||||
public function fetchAllArray($query);
|
|
||||||
public function fetchOneArray($query);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class DB implements IDatabase
|
|
||||||
{
|
|
||||||
const limit = 1024;
|
|
||||||
protected $db;
|
|
||||||
|
|
||||||
public static function quote($x)
|
|
||||||
{
|
|
||||||
return "'" . $x . "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function assign_quote($x, $y)
|
|
||||||
{
|
|
||||||
return $x . "='" . $y . "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
function insert($table, array $values)
|
|
||||||
{
|
|
||||||
return $this->query("INSERT INTO $table (" . implode(",", array_keys($values))
|
|
||||||
. ") VALUES (" . implode(",", array_map(array('self', 'quote'), array_values($values))) . ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
function update($table, array $values, $cond)
|
|
||||||
{
|
|
||||||
return $this->query("UPDATE $table SET " . implode(",",
|
|
||||||
array_map(array('self', 'assign_quote'), array_keys($values), array_values($values))) . " WHERE $cond");
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_text($text)
|
|
||||||
{
|
|
||||||
if(strlen($text) > self::limit) $text = substr($text, 0, self::limit);
|
|
||||||
$text = htmlspecialchars(trim($text));
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// Report simple running errors
|
|
||||||
define('ERROR_FILE', 'phedor@edu.yar.ru');
|
|
||||||
define('ERROR_TYPE', 1);
|
|
||||||
|
|
||||||
ini_set('error_reporting', 0);
|
|
||||||
ini_set('display_errors', 0);
|
|
||||||
error_reporting(0);
|
|
||||||
|
|
||||||
function get_error_name($id) {
|
|
||||||
$names = array(1 => 'E_ERROR',
|
|
||||||
2 => 'E_WARNING',
|
|
||||||
4 => 'E_PARSE',
|
|
||||||
8 => 'E_NOTICE',
|
|
||||||
16 => 'E_CORE_ERROR',
|
|
||||||
32 => 'E_CORE_WARNING',
|
|
||||||
64 => 'E_COMPILE_ERROR',
|
|
||||||
128 => 'E_COMPILE_WARNING',
|
|
||||||
256 => 'E_USER_ERROR',
|
|
||||||
512 => 'E_USER_WARNING',
|
|
||||||
1024 => 'E_USER_NOTICE',
|
|
||||||
2048 => 'E_STRICT',
|
|
||||||
4096 => 'E_RECOVERABLE_ERROR',
|
|
||||||
8192 => 'E_DEPRECATED',
|
|
||||||
16384 => 'E_USER_DEPRECATED',
|
|
||||||
30719 => 'E_ALL');
|
|
||||||
return $names[$id];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function send_error($description) {
|
|
||||||
$message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n";
|
|
||||||
$message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n";
|
|
||||||
if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n";
|
|
||||||
$message .= "post:" . var_export($_POST, true) . "\n";
|
|
||||||
$message .= "description: " . $description;
|
|
||||||
|
|
||||||
// error_log($message, ERROR_TYPE, ERROR_FILE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function error_handler($errno, $errstr, $errfile, $errline) {
|
|
||||||
$message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n";
|
|
||||||
$message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n";
|
|
||||||
if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n";
|
|
||||||
$message .= "post:" . var_export($_POST, true) . "\n";
|
|
||||||
$message .= "type: " . get_error_name($errno) . "\n"
|
|
||||||
. "error: " . $errstr . "\n"
|
|
||||||
. "line: " . $errline . "\n"
|
|
||||||
. "file: " . $errfile;
|
|
||||||
|
|
||||||
// error_log($message, ERROR_TYPE, ERROR_FILE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shutdown() {
|
|
||||||
$error = error_get_last();
|
|
||||||
$message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n";
|
|
||||||
$message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n";
|
|
||||||
if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n";
|
|
||||||
if (is_array($error)) {
|
|
||||||
foreach ($error as $info => $string) {
|
|
||||||
$message .= "{$info}: {$string}\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
error_log($message, ERROR_TYPE, ERROR_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
function exception_handler($exception) {
|
|
||||||
$message = "request: " . "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] . "\n";
|
|
||||||
$message .= "from: " . $_SERVER['REMOTE_ADDR'] . "\n";
|
|
||||||
if(isset($_SERVER['HTTP_REFERER'])) $message .= "referer: " . $_SERVER['HTTP_REFERER'] . "\n";
|
|
||||||
$message .=
|
|
||||||
"file: " . $exception->getFile() . "\n"
|
|
||||||
. "line: " . $exception->getLine() . "\n"
|
|
||||||
. "message: " . $exception->getMessage() . "\n"
|
|
||||||
. "trace: " . $exception->getTraceAsString();
|
|
||||||
error_log($message, ERROR_TYPE, ERROR_FILE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_exception_handler('exception_handler');
|
|
||||||
set_error_handler("error_handler");
|
|
||||||
//register_shutdown_function('shutdown');
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/sort.php';
|
|
||||||
|
|
||||||
//Становиться похоже на работу файлов через SPL возможно стоит реализовать на базе его
|
|
||||||
class FileRecord
|
|
||||||
{
|
|
||||||
public $file;
|
|
||||||
protected $src;
|
|
||||||
protected $parent;
|
|
||||||
|
|
||||||
function __construct(array $file, $src, $parent = false)
|
|
||||||
{
|
|
||||||
$this->file = $file;
|
|
||||||
$this->filename = $src;
|
|
||||||
$this->parent = $parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($name) {
|
|
||||||
return isset($this->file[$name]) ? $this->file[$name] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileStat()
|
|
||||||
{
|
|
||||||
$type = is_dir($this->filename);
|
|
||||||
return array(
|
|
||||||
'name' => ($this->parent) ? ".." : $this->getName(),
|
|
||||||
'type' => $type,
|
|
||||||
'extension' => ($type) ? 'folder' : pathinfo($this->filename, PATHINFO_EXTENSION),
|
|
||||||
'date' => date("d.m.Y H:i", $this->getTime()),
|
|
||||||
'access' => 0,
|
|
||||||
'size' => ($type) ? "" : $this->getSizeString(),
|
|
||||||
'state' => isset($this->file['state']) ? $this->file['state'] : 'unknown',
|
|
||||||
'title' => $this->getTitle(),
|
|
||||||
/*'author' => $this->file['author'],
|
|
||||||
'description' => $this->file['description'],
|
|
||||||
'keywords' => $this->file['keywords'],*/
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isExpected()
|
|
||||||
{
|
|
||||||
if (isset($this->file['state'])) {
|
|
||||||
return ($this->file['state'] == 'expected');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSizeString()
|
|
||||||
{
|
|
||||||
$size = $this->getSize();
|
|
||||||
foreach (array('б ', 'Kб', 'Mб') as $suffix) {
|
|
||||||
if (($size / 1024) <= 1) {
|
|
||||||
return round($size, 0) . ' ' . $suffix;
|
|
||||||
}
|
|
||||||
$size /= 1024;
|
|
||||||
}
|
|
||||||
return round($size, 0) . ' GB';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSize()
|
|
||||||
{
|
|
||||||
return ($this->isExpected()) ? 0 : filesize($this->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTime()
|
|
||||||
{
|
|
||||||
return ($this->isExpected()) ? 0 : filemtime($this->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getName()
|
|
||||||
{
|
|
||||||
return pathinfo($this->filename, PATHINFO_BASENAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTitle()
|
|
||||||
{
|
|
||||||
return isset($this->file['title']) ? $this->file['title'] : $this->getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Фильтр для проверки авторизации
|
|
||||||
*
|
|
||||||
* action: login(password, login)
|
|
||||||
* action: logout()
|
|
||||||
*/
|
|
||||||
// В класс авторизации передавать обьект для управления пользователем
|
|
||||||
// Вынести в отдельный файл
|
|
||||||
class LoginFilter extends Filter
|
|
||||||
{
|
|
||||||
const SESSION_BROWSER_SIGN_SECRET = '@w3dsju45Msk#';
|
|
||||||
const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign';
|
|
||||||
public $mode = 'ajax';
|
|
||||||
/**
|
|
||||||
* Проверка авторизации
|
|
||||||
* @return Boolean Авторизовани пользователь или нет
|
|
||||||
*/
|
|
||||||
public function isLoggin(HttpRequest $request)
|
|
||||||
{
|
|
||||||
// Авторизация
|
|
||||||
session_start();
|
|
||||||
$db = $this->getConnection();
|
|
||||||
UserAccess::setUp($db); // Соединение
|
|
||||||
switch ($request->getAction()) {
|
|
||||||
// Авторизация по постоянному паролю
|
|
||||||
case 'login':
|
|
||||||
$login = $request->get('login');
|
|
||||||
$password = $request->get('password');
|
|
||||||
|
|
||||||
$result = UserAccess::getUserByLogin($login); // Поиск по логину
|
|
||||||
if ($result) {
|
|
||||||
if (md5($password) == $result->getString('password')) { // password
|
|
||||||
$this->enter($db, $result);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$request->set('error', true);
|
|
||||||
break;
|
|
||||||
case 'logout': // Выход
|
|
||||||
session_destroy();
|
|
||||||
break;
|
|
||||||
// Вход по временному паролю
|
|
||||||
case 'enter':
|
|
||||||
$login = $request->get('login');
|
|
||||||
$password = $request->get('sid');
|
|
||||||
$result = UserAccess::getUserByLogin($login); // Поиск по логину
|
|
||||||
if ($result) {
|
|
||||||
$temp = md5($result->getString('password') . $result->getString('login') . $result->getString('sid'));
|
|
||||||
if ($password == $temp) {
|
|
||||||
$this->enter($db, $result);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$hash = $this->getBrowserSign();
|
|
||||||
// Если $hash не совпадает $_SESSION['hash'] то удаляем сессию
|
|
||||||
if (isset($_SESSION ['access']) && isset($_SESSION[self::SESSION_BROWSER_SIGN_SECRET])) {
|
|
||||||
if ($hash == $_SESSION[self::SESSION_BROWSER_SIGN_SECRET]) {
|
|
||||||
UserAccess::getUserById($_SESSION ['access']); // Поиск по идентификатору
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
session_destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getBrowserSign()
|
|
||||||
{
|
|
||||||
$rawSign = self::SESSION_BROWSER_SIGN_SECRET;
|
|
||||||
$signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING');
|
|
||||||
|
|
||||||
$rawSign = '';
|
|
||||||
foreach ($signParts as $signPart) {
|
|
||||||
$rawSign .= '::' . (isset($_SERVER[$signPart]) ? $_SERVER[$signPart] : 'none');
|
|
||||||
}
|
|
||||||
return md5($rawSign);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function enter($db, $result)
|
|
||||||
{
|
|
||||||
$db->executeQuery("UPDATE users SET sid = '' WHERE id_user = " . $result->getInt('id_user'));
|
|
||||||
|
|
||||||
$_SESSION ["group"] = $result->getInt('access');
|
|
||||||
$_SESSION ["access"] = $result->getInt('id_user'); // id_user
|
|
||||||
$_SESSION [self::SESSION_BROWSER_SIGN_SECRET] = $this->getBrowserSign();
|
|
||||||
$_SESSION ["time"] = time();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(HttpRequest $request)
|
|
||||||
{
|
|
||||||
if (!$this->isLoggin($request)) {
|
|
||||||
// Параметры при неправильной авторизации
|
|
||||||
// Действия по умолчанию !! Возможно переход на форму регистрации
|
|
||||||
$request->set('module', 'login');
|
|
||||||
$request->set('mode', $this->mode);
|
|
||||||
}
|
|
||||||
return $this->processor->execute($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,178 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Элемент формы
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class TField
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $label; // Метка поля
|
|
||||||
public $value; // Значение поля
|
|
||||||
public $type; // Каждому типу элемента соответствует макрос TAL
|
|
||||||
public $error_msg = null;
|
|
||||||
public $error = false;
|
|
||||||
public $require = false;
|
|
||||||
|
|
||||||
public function __construct ($input)
|
|
||||||
{
|
|
||||||
$this->deafult = null;
|
|
||||||
if (isset($input['validate'])) {
|
|
||||||
$this->require = strpos($input['validate'], 'require') !== false;
|
|
||||||
}
|
|
||||||
// Инициализация свойст обьетка
|
|
||||||
foreach (array('label', 'name', 'type') as $name) {
|
|
||||||
$this->$name = $input[$name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setValue($value)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поле ввода Input
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class TInput extends TField {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Выбор из одного элемента
|
|
||||||
*/
|
|
||||||
class TSelect1 extends TField
|
|
||||||
{
|
|
||||||
public $options = array ();
|
|
||||||
public function __construct ($input) {
|
|
||||||
parent::__construct($input);
|
|
||||||
$this->options = $input['options'];
|
|
||||||
}
|
|
||||||
|
|
||||||
function setValue($value)
|
|
||||||
{
|
|
||||||
// Установить selected у options
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поле с датой
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class TDate extends TField
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* Текстовое поле
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class TTextArea extends TField
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поле для ввода пароля
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class TSecret extends TField
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
class TUpload extends TField
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Форма для ввода
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class TForm
|
|
||||||
{
|
|
||||||
public $field = array ();
|
|
||||||
public $action = "";
|
|
||||||
public $method = 'post';
|
|
||||||
protected $replace;
|
|
||||||
protected $before;
|
|
||||||
|
|
||||||
public function __construct ()
|
|
||||||
{
|
|
||||||
$this->constructor = array (
|
|
||||||
'input' => 'TInput',
|
|
||||||
'date' => 'TDate',
|
|
||||||
'textarea' => 'TTextArea',
|
|
||||||
'select' => 'TSelect',
|
|
||||||
'select1' => 'TSelect1',
|
|
||||||
'secret' => 'TSecret',
|
|
||||||
'upload' => 'TUpload'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет одно поле ввода на форму
|
|
||||||
*/
|
|
||||||
public function addField (array $init)
|
|
||||||
{
|
|
||||||
assert (isset($init['type']));
|
|
||||||
assert (isset($init['name']));
|
|
||||||
|
|
||||||
$constructor = $this->constructor[$init['type']];
|
|
||||||
$el = new $constructor ($init);
|
|
||||||
$el->type = $init['type'];
|
|
||||||
|
|
||||||
$this->field [$init['name']] = $el;
|
|
||||||
return $el;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет спсок полей для формы
|
|
||||||
* @param array $list
|
|
||||||
*/
|
|
||||||
public function addFieldList (array $list)
|
|
||||||
{
|
|
||||||
foreach ($list as $init) {
|
|
||||||
$this->addField ($init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает ошибки после проверки
|
|
||||||
*/
|
|
||||||
function setError (Validator $validator)
|
|
||||||
{
|
|
||||||
foreach ($validator->getErrorMsg() as $name => $error)
|
|
||||||
{
|
|
||||||
$this->field[$name]->error = true;
|
|
||||||
$this->field[$name]->error_msg = $error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает значения из масива
|
|
||||||
*/
|
|
||||||
function setValues (Collection $request) {
|
|
||||||
foreach ($this->field as $key => $el) {
|
|
||||||
$value = $request->getRawData ($this->method, $key);
|
|
||||||
$this->field[$key]->setValue($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Заполняет форму данными из обьекта
|
|
||||||
* @param object $data
|
|
||||||
* @param array $schema Связь между элементами формы и свойствами обьекта
|
|
||||||
*/
|
|
||||||
public function fill ($data, array $schema)
|
|
||||||
{
|
|
||||||
foreach ($schema as $key => $value) {
|
|
||||||
$this->field [$value]->setValue($data->$value->getString ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function set($name, $value)
|
|
||||||
{
|
|
||||||
$this->field[$name]->setValue($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Генерация файлов Grpahviz dot
|
|
||||||
*/
|
|
||||||
class Dot
|
|
||||||
{
|
|
||||||
static function getHeader ()
|
|
||||||
{
|
|
||||||
$header =
|
|
||||||
"digraph G {\n"
|
|
||||||
. "\toverlap=false; splines=true;\n"
|
|
||||||
. "\tfontname = \"Verdana\"\n"
|
|
||||||
. "\tfontsize = 8\n"
|
|
||||||
. "\tnode [\n"
|
|
||||||
. "\t\tfontname = \"Verdana\"\n"
|
|
||||||
. "\t\tfontsize = 8\n"
|
|
||||||
. "\t\tshape = \"record\"\n"
|
|
||||||
. "\t]\n"
|
|
||||||
. "\tedge [\n"
|
|
||||||
. "\t\tfontname = \"Verdana\"\n"
|
|
||||||
. "\t\tfontsize = 8\n"
|
|
||||||
. "\t]\n";
|
|
||||||
|
|
||||||
return $header;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function getFooter ()
|
|
||||||
{
|
|
||||||
$footer = "}\n";
|
|
||||||
return $footer;
|
|
||||||
}
|
|
||||||
|
|
||||||
function assocToDot (array $array, array $label)
|
|
||||||
{
|
|
||||||
$result = array (self::getHeader());
|
|
||||||
// Метки
|
|
||||||
foreach ($label as $value) {
|
|
||||||
$result [] = "\t\"{$value[0]}\" [ label = \"{$value[1]}\" ] \n";
|
|
||||||
}
|
|
||||||
// Ассоциации
|
|
||||||
foreach ($array as $key => $value) {
|
|
||||||
foreach ($value as $n) {
|
|
||||||
$result [] = "\t\"$key\" -> \"$n\"\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$result [] = self::getFooter();
|
|
||||||
return implode("", $result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
define ('URL_CLIP', 0);
|
|
||||||
define ('URL_DIRECTORY', 1);
|
|
||||||
|
|
||||||
class HAuthorize {
|
|
||||||
public $password;
|
|
||||||
public $uuid;
|
|
||||||
public $uuid_writeable;
|
|
||||||
|
|
||||||
public function __construct () {
|
|
||||||
$this->uuid = "*";
|
|
||||||
$this->uuid_writeable = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getString () {
|
|
||||||
return "{$this->password};{$this->uuid};{$this->uuid_writeable}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPassword ($username, $realm, $password) {
|
|
||||||
$this->password = md5 ("$username:$realm:$password");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HPermission {
|
|
||||||
public $url;
|
|
||||||
public $url_type;
|
|
||||||
public $permission_type;
|
|
||||||
public $expires;
|
|
||||||
public $debitted_time;
|
|
||||||
|
|
||||||
public function __construct ($url, $url_type) {
|
|
||||||
$this->url = $url;
|
|
||||||
$this->url_type = $url_type;
|
|
||||||
$this->expires = "*"; // MM/DD/YYYY:HH:MM:SS
|
|
||||||
$this->permission_type = 0;
|
|
||||||
$this->debitted_time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getString () {
|
|
||||||
return "{$this->url};{$this->url_type};{$this->permission_type};{$this->expires};{$this->debitted_time}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HFile {
|
|
||||||
public $authorize;
|
|
||||||
public $permission = array ();
|
|
||||||
|
|
||||||
public function addAuthorize ($name, $realm, $password) {
|
|
||||||
$this->authorize = new HAuthorize ();
|
|
||||||
$this->authorize->setPassword ($name, $realm, $password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addPermission ($url, $url_type) {
|
|
||||||
$this->permission[] = new HPermission ($url, $url_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function write ($name) {
|
|
||||||
$file = fopen ($name, 'w');
|
|
||||||
fwrite ($file, $this->getString ());
|
|
||||||
fclose ($file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function writeFTP ($ftp, $path) {
|
|
||||||
$file = tmpfile ();
|
|
||||||
fwrite ($file, $this->getString ());
|
|
||||||
fseek ($file, 0);
|
|
||||||
|
|
||||||
ftp_fput ($ftp, $path, $file, FTP_BINARY);
|
|
||||||
|
|
||||||
fclose ($file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getString () {
|
|
||||||
$result = array ();
|
|
||||||
$result[] = $this->authorize->getString ();
|
|
||||||
$result[] = "\n";
|
|
||||||
foreach ($this->permission as $p) {
|
|
||||||
$result[] = $p->getString ();
|
|
||||||
$result[] = "\n";
|
|
||||||
}
|
|
||||||
return implode ("", $result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class Point
|
|
||||||
{
|
|
||||||
public $left, $top;
|
|
||||||
function __construct ($left = 0, $top = 0)
|
|
||||||
{
|
|
||||||
$this->left = $left;
|
|
||||||
$this->top = $top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once "core/geometry/point.php";
|
|
||||||
|
|
||||||
class Rectangle
|
|
||||||
{
|
|
||||||
public $left, $top, $width, $height;
|
|
||||||
|
|
||||||
function __construct($left = 0, $top = 0, $width = 0, $height = 0)
|
|
||||||
{
|
|
||||||
$this->left = $left;
|
|
||||||
$this->top = $top;
|
|
||||||
$this->width = $width;
|
|
||||||
$this->height = $height;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __get($name)
|
|
||||||
{
|
|
||||||
switch ($name) {
|
|
||||||
case 'right': return $this->left + $this->width;
|
|
||||||
case 'bottom': return $this->top + $this->height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function __set($name, $value)
|
|
||||||
{
|
|
||||||
switch ($name) {
|
|
||||||
case 'right': $this->width = $value - $this->left;
|
|
||||||
case 'bottom': $this->height = $value - $this->top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Смещает прямоугольник на заданное положение
|
|
||||||
*/
|
|
||||||
function addPoint(Point $point)
|
|
||||||
{
|
|
||||||
$result = clone $this;
|
|
||||||
$result->left += $point->left;
|
|
||||||
$result->top += $point->top;
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Координаты точки при выравнивании прямоугольника относительно текущего
|
|
||||||
*/
|
|
||||||
function alignment(Rectangle $base)
|
|
||||||
{
|
|
||||||
return new Point((($base->left + $base->right) - ($this->left + $this->right)) / 2, $base->bottom - $this->height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class ModelFactory
|
|
||||||
{
|
|
||||||
static $shortcut = "model";
|
|
||||||
|
|
||||||
public function __construct (Connection $db)
|
|
||||||
{
|
|
||||||
$this->db = $db;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает модель
|
|
||||||
* @param string $name
|
|
||||||
* @return model
|
|
||||||
*/
|
|
||||||
public function getModel ($name)
|
|
||||||
{
|
|
||||||
require_once 'core/mapper/mapper.php'; // ????
|
|
||||||
|
|
||||||
require_once (Shortcut::getUrl(self::$shortcut, $name));
|
|
||||||
$modelName = $name . "Mapper";
|
|
||||||
$model = new $modelName();
|
|
||||||
$model->db = $this->db;
|
|
||||||
$model->factory = $this;
|
|
||||||
return $model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,267 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/primitive.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Использовать интерфейсы чтобы определить какие действия можно совершать с обьектом и таким образом
|
|
||||||
* Строить набор действий Action и отображений View для обьекта
|
|
||||||
* Т.к отображение данных может быть не только на таблицу баз данных
|
|
||||||
* И возможно реализованны все интерфейсы
|
|
||||||
*/
|
|
||||||
interface IDataList
|
|
||||||
{
|
|
||||||
function findAll (Collection $request, $id = null);
|
|
||||||
function findById ($id);
|
|
||||||
function getCount (Collection $request, $id);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IDataSave
|
|
||||||
{
|
|
||||||
function saveTo ($o);
|
|
||||||
function updateTo ($o);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Отображение таблицы базы данных в обьекты
|
|
||||||
* Mapper -> DataMapper implements IDataList, IDataSave, IDataSort, IDataDelete ...
|
|
||||||
*
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class DataMapper implements IDataList
|
|
||||||
{
|
|
||||||
/* Хранить метаданные в статическом свойстве класса для ототбражения ?!, + Скрипт для генерации метаданных!!
|
|
||||||
*/
|
|
||||||
public $factory;
|
|
||||||
public $className; /* Класс на который будет отображаться строчка таблицы */
|
|
||||||
public $filter = ""; /* */
|
|
||||||
public $schema = array (); /* Соответствие между свойством обьекта и столбцом, добавить тип для записей !! */
|
|
||||||
public $database; /* Таблица */
|
|
||||||
public $index; /* Индексный столбец */
|
|
||||||
public $db; /* Соединение с базой данных */
|
|
||||||
public $reference = array (null, null);
|
|
||||||
|
|
||||||
public function __construct ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setRange ($stmt, $page, $size)
|
|
||||||
{
|
|
||||||
$stmt->setLimit ($size);
|
|
||||||
$stmt->setOffset (($page-1) * $size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function listSQL (array $list)
|
|
||||||
{
|
|
||||||
return implode ($list, ",");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск строки в таблице по идентификатору
|
|
||||||
* @param $id Значение идентификатора
|
|
||||||
* @return Обьект класса $className
|
|
||||||
*/
|
|
||||||
public function findById ($id)
|
|
||||||
{
|
|
||||||
// Строки запроса преобразовать в методы (getSQLSelect ...)
|
|
||||||
// Query::from($this->database)->where ($this->index, "=", $id)->select();
|
|
||||||
$stmt = $this->db->prepareStatement ("SELECT * FROM ".$this->database." WHERE ".$this->index." = ?");
|
|
||||||
$stmt->setInt (1, $id);
|
|
||||||
$rs = $stmt->executeQuery ();
|
|
||||||
$rs->next ();
|
|
||||||
return $this->mapOne ($rs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразует parseResult в обьект
|
|
||||||
*/
|
|
||||||
public /* private */ function mapOne ($rs)
|
|
||||||
{
|
|
||||||
$result = new $this->className ();
|
|
||||||
foreach ($this->schema as $key => $value) {
|
|
||||||
list($value) = $value;
|
|
||||||
$result->$value->setRes($rs, $key);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public /* private */ function mapAll ($rs)
|
|
||||||
{
|
|
||||||
$result = array ();
|
|
||||||
// Преобразование SQL в обьект
|
|
||||||
while ($rs->next ()) {
|
|
||||||
$result[] = $this->mapOne ($rs);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function clean ($value) {
|
|
||||||
return strtolower(trim(iconv('utf-8', 'cp1251', $value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразует параметры формы в SQL запрос WHERE
|
|
||||||
* @param array $params
|
|
||||||
* @param array $schema
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function requestToSQL (Collection $request, array $schema)
|
|
||||||
{
|
|
||||||
$result = array ();
|
|
||||||
foreach ($schema as $key => $value) {
|
|
||||||
$param = $request->get ($key);
|
|
||||||
if ($param) {
|
|
||||||
array_push ($result, "lower (".$value.") LIKE '".$this->clean ($param)."%'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (empty ($result)) return null;
|
|
||||||
return implode ($result, " AND ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Удаление строк из таблицы с заданными индексами
|
|
||||||
* @param $list array Массив идентефикаторов
|
|
||||||
*/
|
|
||||||
public function deleteList (array $list)
|
|
||||||
{
|
|
||||||
// Query::from($this->database)->where($this->index, "in", $list)->delete();
|
|
||||||
$sql = "DELETE FROM " . $this->database . " WHERE " . $this->index . " IN (" . $this->listSQL ($list) . ")";
|
|
||||||
return $this->db->executeQuery ($sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findKey (array $schema, $sort)
|
|
||||||
{
|
|
||||||
foreach ($schema as $key => $item) {
|
|
||||||
list($item) = $item;
|
|
||||||
if ($item == $sort) {
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $sort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOrder (Collection $request)
|
|
||||||
{
|
|
||||||
$order = "";
|
|
||||||
$sort = $request->get('key');
|
|
||||||
$desc = ($request->get('desc') == 0)? 'DESC' : 'ASC';
|
|
||||||
if ($sort) {
|
|
||||||
$sort = self::findKey ($this->schema, $sort);
|
|
||||||
$order = " ORDER BY $sort $desc";
|
|
||||||
}
|
|
||||||
return $order;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Извлекает список записей из базы данных
|
|
||||||
*/
|
|
||||||
public function findAll (Collection $request, $id = null)
|
|
||||||
{
|
|
||||||
$name0 = $this->database;
|
|
||||||
$foreign = $this->reference[1];
|
|
||||||
// Переписать используя Query !!!
|
|
||||||
if ($foreign && $id) {
|
|
||||||
$filter = ($this->filter)?$filter = " AND ".$this->filter: "";
|
|
||||||
$sql = "SELECT t1.* FROM $name0 as t1 WHERE t1.$foreign = $id " . $filter.self::getOrder($request);
|
|
||||||
} else {
|
|
||||||
$filter = ($this->filter)?$filter = " WHERE " . $this->filter: "";
|
|
||||||
$sql = "SELECT * FROM $name0 " . $filter . self::getOrder($request);
|
|
||||||
}
|
|
||||||
$stmt = $this->db->prepareStatement ($sql);
|
|
||||||
|
|
||||||
$page = $request->get('page');
|
|
||||||
$limit = $request->get('size');
|
|
||||||
if ($page && $limit) {
|
|
||||||
$this->setRange($stmt, $page, $limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->mapAll($stmt->executeQuery());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCount (Collection $request, $id)
|
|
||||||
{
|
|
||||||
$name0 = $this->database;
|
|
||||||
$foreign = $this->reference[1];
|
|
||||||
// Переписать используя Query !!!
|
|
||||||
if ($foreign && $id) {
|
|
||||||
$filter = ($this->filter)?$filter = " AND " . $this->filter: "";
|
|
||||||
$sql = "SELECT count(t1.*) as length FROM $name0 as t1 WHERE t1.$foreign = $id " . $filter;
|
|
||||||
} else {
|
|
||||||
$filter = ($this->filter)?$filter = " WHERE " . $this->filter: "";
|
|
||||||
$sql = "SELECT count(*) as length FROM $name0 " . $filter;
|
|
||||||
}
|
|
||||||
$rs = $this->db->executeQuery($sql);
|
|
||||||
$rs->next();
|
|
||||||
return $rs->getInt('length');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавление записи в базу данных
|
|
||||||
* @param $o Обьект для записи в базу данных
|
|
||||||
*/
|
|
||||||
public function saveTo (Model $o)
|
|
||||||
{
|
|
||||||
$keys = array ();
|
|
||||||
$values = array ();
|
|
||||||
foreach ($this->schema as $key => $value) {
|
|
||||||
list($value) = $value;
|
|
||||||
if ($key != $this->index) {
|
|
||||||
$keys[] = $key;
|
|
||||||
$values[] = "'".$o->$value."'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$stmt = $this->db->prepareStatement ("INSERT INTO ".$this->database." (".implode ($keys, ",").") VALUES (".implode ($values, ",").")");
|
|
||||||
$stmt->executeQuery ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обновляет запись в базе данных
|
|
||||||
* @param $o Обьект для обновления
|
|
||||||
*/
|
|
||||||
public function updateTo (Model $o)
|
|
||||||
{
|
|
||||||
$keys_values = array ();
|
|
||||||
foreach ($this->schema as $key => $value) {
|
|
||||||
list($value) = $value;
|
|
||||||
if ($key != $this->index && !($o->$value instanceof FKey)) {
|
|
||||||
$keys_values[] = $key." = '".$o->$value."'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Для всех должен быть идентефикатор id
|
|
||||||
$stmt = $this->db->prepareStatement ("UPDATE ".$this->database." SET ".implode($keys_values, ",")." WHERE ".$this->index." = ".$o->id);
|
|
||||||
$stmt->executeQuery ();
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveDB (Model $o)
|
|
||||||
{
|
|
||||||
if ($o->id) {
|
|
||||||
$this->updateTo($o);
|
|
||||||
} else {
|
|
||||||
$this->saveTo($o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getModel($name)
|
|
||||||
{
|
|
||||||
require_once 'core/Mapper/Factory.php';
|
|
||||||
if (!$this->factory) {
|
|
||||||
$this->factory = new ModelFactory($this->db);
|
|
||||||
}
|
|
||||||
return $this->factory->getModel($name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class Model
|
|
||||||
{
|
|
||||||
public function __construct ()
|
|
||||||
{
|
|
||||||
foreach (get_class_vars (get_class ($this)) as $key => $value) {
|
|
||||||
$this->$key = new Primitive ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// __get, __set методы. В метаданных хранится тип свойств, проверять при присваивании!!
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Отображение списка папок с настройками на обьект
|
|
||||||
*/
|
|
||||||
class PathMapper
|
|
||||||
{
|
|
||||||
private $count;
|
|
||||||
private $base = null;
|
|
||||||
public $reference = null;
|
|
||||||
|
|
||||||
function plane (&$target, Collection $array)
|
|
||||||
{
|
|
||||||
$vars = get_class_vars(get_class($target));
|
|
||||||
foreach ($vars as $name => $value) {
|
|
||||||
$target->$name = $array->get($name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function basePath ()
|
|
||||||
{
|
|
||||||
if ( ! $this->base) $this->base = $this->getBasePath();
|
|
||||||
return $this->base;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findAll (Collection $request, $id = null)
|
|
||||||
{
|
|
||||||
require_once "core/settings.php";
|
|
||||||
require_once "core/path.php";
|
|
||||||
|
|
||||||
$this->reference = $id;
|
|
||||||
|
|
||||||
$base = $this->basePath ();
|
|
||||||
$path = new Path($base);
|
|
||||||
$list = $path->getContent();
|
|
||||||
|
|
||||||
$result = array ();
|
|
||||||
$this->count = 0;
|
|
||||||
foreach ($list as $name) {
|
|
||||||
if (is_dir (Path::join($this->basePath (), $name))
|
|
||||||
&& $module = $this->findById ($name)) {
|
|
||||||
$this->count++;
|
|
||||||
$result [] = $module;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findById ($name)
|
|
||||||
{
|
|
||||||
$file = Path::join($this->basePath(), $this->getSettingsFile ($name));
|
|
||||||
if (file_exists($file)) {
|
|
||||||
$settings = new Settings($file);
|
|
||||||
$settings->read();
|
|
||||||
return $this->settingsMap($name, $settings);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Число папок
|
|
||||||
*/
|
|
||||||
function getCount ()
|
|
||||||
{
|
|
||||||
return $this->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Удаление списка папок
|
|
||||||
*/
|
|
||||||
function deleteList(array $list)
|
|
||||||
{
|
|
||||||
foreach ($list as $name)
|
|
||||||
Path::delete(Path::join($this->getBasePath(), $name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
Copyright (c) 2007 Brady Mulhollem
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
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{
|
|
||||||
//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
|
|
||||||
var $mapped = array('url' => array('a','href',true),'img' => array('img','src',false));
|
|
||||||
//Tags with atributes
|
|
||||||
var $tags_with_att = array('color' => array('font','color'),'size' => array('font','size'),'url' => array('a','href'));
|
|
||||||
//Gotta have smilies
|
|
||||||
var $smilies = array(':)' => 'smile.gif',':(' => 'frown.gif');
|
|
||||||
//Config Variables
|
|
||||||
//Convert new line charactes to linebreaks?
|
|
||||||
var $convert_newlines = true;
|
|
||||||
//Parse For smilies?
|
|
||||||
var $parse_smilies = true;
|
|
||||||
//auto link urls(http and ftp), and email addresses?
|
|
||||||
var $auto_links = true;
|
|
||||||
//Internal Storage
|
|
||||||
var $_code = '';
|
|
||||||
function Simple_BB_Code($new=true,$parse=true,$links=true){
|
|
||||||
$this->convert_newlines = $new;
|
|
||||||
$this->parse_smilies = $parse;
|
|
||||||
$this->auto_links = $links;
|
|
||||||
}
|
|
||||||
function parse($code){
|
|
||||||
$this->_code = $code;
|
|
||||||
$this->_strip_html();
|
|
||||||
$this->_parse_tags();
|
|
||||||
$this->_parse_mapped();
|
|
||||||
$this->_parse_tags_with_att();
|
|
||||||
$this->_parse_smilies();
|
|
||||||
$this->_parse_links();
|
|
||||||
$this->_convert_nl();
|
|
||||||
return $this->_code;
|
|
||||||
}
|
|
||||||
function _strip_html(){
|
|
||||||
$this->_code = strip_tags($this->_code);
|
|
||||||
}
|
|
||||||
function _convert_nl(){
|
|
||||||
if($this->convert_newlines){
|
|
||||||
$this->_code = nl2br($this->_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function _parse_tags(){
|
|
||||||
foreach($this->tags as $old=>$new){
|
|
||||||
$ex = explode(' ',$new);
|
|
||||||
$this->_code = preg_replace('/\['.$old.'\](.+?)\[\/'.$old.'\]/is','<'.$new.'>$1</'.$ex[0].'>',$this->_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function _parse_mapped(){
|
|
||||||
foreach($this->mapped as $tag=>$data){
|
|
||||||
$reg = '/\['.$tag.'\](.+?)\[\/'.$tag.'\]/is';
|
|
||||||
if($data[2]){
|
|
||||||
$this->_code = preg_replace($reg,'<'.$data[0].' '.$data[1].'="$1">$1</'.$data[0].'>',$this->_code);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$this->_code = preg_replace($reg,'<'.$data[0].' '.$data[1].'="$1">',$this->_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function _parse_tags_with_att(){
|
|
||||||
foreach($this->tags_with_att as $tag=>$data){
|
|
||||||
$this->_code = preg_replace('/\['.$tag.'=(.+?)\](.+?)\[\/'.$tag.'\]/is','<'.$data[0].' '.$data[1].'="$1">$2</'.$data[0].'>',$this->_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function _parse_smilies(){
|
|
||||||
if($this->parse_smilies){
|
|
||||||
foreach($this->smilies as $s=>$im){
|
|
||||||
$this->_code = str_replace($s,'<img src="'.$im.'">',$this->_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function _parse_links(){
|
|
||||||
if($this->auto_links){
|
|
||||||
$this->_code = preg_replace('/([^"])(http:\/\/|ftp:\/\/)([^\s,]*)/i','$1<a href="$2$3">$2$3</a>',$this->_code);
|
|
||||||
$this->_code = preg_replace('/([^"])([A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4})/i','$1<a href="mailto:$2">$2</a>',$this->_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function addTag($old,$new){
|
|
||||||
$this->tags[$old] = $new;
|
|
||||||
}
|
|
||||||
function addMapped($bb,$html,$att,$end=true){
|
|
||||||
$this->mapped[$bb] = array($html,$att,$end);
|
|
||||||
}
|
|
||||||
function addTagWithAttribute($bb,$html,$att){
|
|
||||||
$this->tags_with_att[$bb] = array($html,$att);
|
|
||||||
}
|
|
||||||
function addSmiley($code,$src){
|
|
||||||
$this->smilies[$code] = $src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
317
core/path.php
317
core/path.php
|
|
@ -1,317 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*.
|
|
||||||
require_module 'standard';
|
|
||||||
.*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс для работы с папками и путями
|
|
||||||
* Для итерации над файлами возможно лучше использовать SPL
|
|
||||||
*
|
|
||||||
* @package utils
|
|
||||||
*/
|
|
||||||
class Path
|
|
||||||
{
|
|
||||||
const SEPARATOR = "/";
|
|
||||||
|
|
||||||
protected $path;
|
|
||||||
|
|
||||||
public function __construct ($path)
|
|
||||||
{
|
|
||||||
assert(is_string($path));
|
|
||||||
|
|
||||||
$this->path = $this->fromString($path);
|
|
||||||
$this->optimize();
|
|
||||||
}
|
|
||||||
|
|
||||||
static function factory($path) {
|
|
||||||
return new Path($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает расширение файла
|
|
||||||
*
|
|
||||||
* @param string $fileName Полное имя файла
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function getExtension ($fileName)
|
|
||||||
{
|
|
||||||
assert(is_string($fileName));
|
|
||||||
|
|
||||||
return pathinfo($fileName, PATHINFO_EXTENSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Полное имя файла без расширения
|
|
||||||
*
|
|
||||||
* @param string $fileName Имя файла
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function skipExtension ($fileName)
|
|
||||||
{
|
|
||||||
assert(is_string($fileName));
|
|
||||||
|
|
||||||
$path = pathinfo($fileName);
|
|
||||||
if ($path['dirname'] == ".") {
|
|
||||||
return $path['filename'];
|
|
||||||
} else {
|
|
||||||
return self::join($path['dirname'], $path['filename']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает имя файла без расширения
|
|
||||||
*
|
|
||||||
* @param string $fileName Полное имя файла
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразует строку путя в массив
|
|
||||||
*
|
|
||||||
* @param string $path Путь
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function fromString ($path)
|
|
||||||
{
|
|
||||||
assert(is_string($path));
|
|
||||||
|
|
||||||
$list = preg_split("/[\/\\\\]/", $path);
|
|
||||||
return $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразует относительный путь в абсолютный
|
|
||||||
*/
|
|
||||||
public function optimize ()
|
|
||||||
{
|
|
||||||
$result = array(current($this->path));
|
|
||||||
while (next($this->path) !== false) {
|
|
||||||
$n = current ($this->path);
|
|
||||||
switch ($n) {
|
|
||||||
case "": break;
|
|
||||||
case ".": break;
|
|
||||||
case "..": if (count($result) > 0) array_pop($result); break;
|
|
||||||
default:
|
|
||||||
array_push($result, $n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reset($this->path);
|
|
||||||
$this->path = $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразует путь в строку
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString ()
|
|
||||||
{
|
|
||||||
$result = implode($this->path, self::SEPARATOR);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет является ли папка родительской для другой папки
|
|
||||||
*
|
|
||||||
* @parma Path $path
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function isParent ($path)
|
|
||||||
{
|
|
||||||
if (count($path->path) > count($this->path)) {
|
|
||||||
for ($i = 0; $i < count($this->path); $i++) {
|
|
||||||
if ($path->path[$i] != $this->path[$i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Находит путь относительно текущего путя
|
|
||||||
*
|
|
||||||
* @param string $name Полный путь к файлу
|
|
||||||
*
|
|
||||||
* @return string Относительный путь к файлу
|
|
||||||
*/
|
|
||||||
public function relPath ($name)
|
|
||||||
{
|
|
||||||
$path = new Path ($name);
|
|
||||||
foreach ($this->path as $n) {
|
|
||||||
array_shift($path->path);
|
|
||||||
}
|
|
||||||
return $path->__toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function append ($path)
|
|
||||||
{
|
|
||||||
$base = $this->__toString();
|
|
||||||
return self::join($base, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает недастающие папки для записи файла
|
|
||||||
*
|
|
||||||
* @param string $dst Полное имя файла
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
static function prepare ($dst)
|
|
||||||
{
|
|
||||||
$path_dst = pathinfo($dst, PATHINFO_DIRNAME);
|
|
||||||
if (! file_exists($path_dst)) {
|
|
||||||
mkdir($path_dst, 0700, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Подбирает новое временное имя для файла
|
|
||||||
*
|
|
||||||
* @param string $dst Предпологаемое имя файла
|
|
||||||
*
|
|
||||||
* @return string Новое имя файла
|
|
||||||
*/
|
|
||||||
static function resolveFile ($dst)
|
|
||||||
{
|
|
||||||
$i = 0;
|
|
||||||
$file = self::skipExtension($dst);
|
|
||||||
$suffix = self::getExtension($dst);
|
|
||||||
$temp = $dst;
|
|
||||||
while (file_exists($temp)) {
|
|
||||||
$i ++;
|
|
||||||
$temp = $file . "." . $i . "." . $suffix;
|
|
||||||
}
|
|
||||||
return $temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обьединяет строки в путь соединяя необходимым разделителем
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function join ()
|
|
||||||
{
|
|
||||||
$args = func_get_args();
|
|
||||||
return implode(self::SEPARATOR, $args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Класс преобразования типа значения поля класса в тип поля таблицы
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class Primitive
|
|
||||||
{
|
|
||||||
public $value;
|
|
||||||
public $name;
|
|
||||||
public function __construct ($name = "")
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Преобразование из внешнего вормата
|
|
||||||
public function setString ($value)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Преобразование из формата базы данных
|
|
||||||
public function setRes ($res, $key)
|
|
||||||
{
|
|
||||||
$this->value = $res->getString ($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString ()
|
|
||||||
{
|
|
||||||
return ((string) $this->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Преобразование во внешний формат
|
|
||||||
public function getString ()
|
|
||||||
{
|
|
||||||
return $this->__toString ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Отображение поля таблицы в целое число
|
|
||||||
* @package core
|
|
||||||
*/
|
|
||||||
class Int4 extends Primitive {
|
|
||||||
public function setRes ($res, $key) {
|
|
||||||
$this->value = $res->getInt ($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setString ($value) {
|
|
||||||
$this->value = ((int) $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Foreign key */
|
|
||||||
class FKey extends Int4 {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Отображение поля таблицы в дату - время
|
|
||||||
*/
|
|
||||||
class Date extends Primitive
|
|
||||||
{
|
|
||||||
public function setRes ($res, $key)
|
|
||||||
{
|
|
||||||
$this->value = $res->getInt ($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setString ($value)
|
|
||||||
{
|
|
||||||
$this->value = 0;
|
|
||||||
if ($tmp = explode("/",$value,3)) {
|
|
||||||
if ($tmp[1] && $tmp[0] && $tmp[2]) {
|
|
||||||
if (checkdate($tmp[1], $tmp[0], $tmp[2])) {
|
|
||||||
$this->value = mktime(0, 0, 0, $tmp[1], $tmp[0], $tmp[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getString ()
|
|
||||||
{
|
|
||||||
return date ("d/m/Y", $this->value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class Password extends Primitive
|
|
||||||
{
|
|
||||||
public function setRes ($res, $key)
|
|
||||||
{
|
|
||||||
$this->value = $res->getString($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setString ($value)
|
|
||||||
{
|
|
||||||
$this->value = md5($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getString ()
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс метаданных таблицы
|
|
||||||
*/
|
|
||||||
class Meta
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'table.php';
|
|
||||||
require_once 'meta.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс для составления запроса
|
|
||||||
*/
|
|
||||||
class Query
|
|
||||||
{
|
|
||||||
static $alias = 0;
|
|
||||||
|
|
||||||
public $table;
|
|
||||||
public $filter = array ();
|
|
||||||
public $calc = array ();
|
|
||||||
public $order = array ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает пустой зарос
|
|
||||||
*/
|
|
||||||
static function create()
|
|
||||||
{
|
|
||||||
return new Query();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Метаданные таблицы
|
|
||||||
* @param string $name Имя таблицы
|
|
||||||
*/
|
|
||||||
function getTableMeta($name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает новый запрос
|
|
||||||
* @param string $name Имя таблицы
|
|
||||||
*
|
|
||||||
* @return Query
|
|
||||||
*/
|
|
||||||
public function from($name)
|
|
||||||
{
|
|
||||||
$result = clone $this;
|
|
||||||
|
|
||||||
$table = new Table();
|
|
||||||
$table->type = 'simple';
|
|
||||||
$table->name = $name;
|
|
||||||
$table->alias = "t" . self::$alias++;
|
|
||||||
|
|
||||||
$result->table = $table;
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет к запросу условие
|
|
||||||
* @param string $field Имя поля таблицы
|
|
||||||
* @param string $op Имя оператора
|
|
||||||
* @param $value Значение поля
|
|
||||||
*
|
|
||||||
* @return Query
|
|
||||||
*/
|
|
||||||
public function filter($field, $op, $value)
|
|
||||||
{
|
|
||||||
$result = clone $this;
|
|
||||||
$result->filter [] = $result->table->alias ."." . $field . $op . "'" . $value . "'";
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $e Выражение
|
|
||||||
*/
|
|
||||||
public function calc($e)
|
|
||||||
{
|
|
||||||
$result = clone $this;
|
|
||||||
$result->calc [] = $e;
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function joinOn($first, $e)
|
|
||||||
{
|
|
||||||
$result = $this->compose($first, array ('filter', 'calc', 'order'));
|
|
||||||
|
|
||||||
$e = strtr($e, array ("a." => $this->table->alias . ".",
|
|
||||||
"b." => $first->table->alias . "."));
|
|
||||||
|
|
||||||
$table = new Table ();
|
|
||||||
$table->type = 'join';
|
|
||||||
$table->name = $this->table->name;
|
|
||||||
$table->alias = $this->table->alias;
|
|
||||||
$table->join = $first->table;
|
|
||||||
$table->condition = $e;
|
|
||||||
|
|
||||||
$result->table = $table;
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обьединяет параметры двух заросов
|
|
||||||
* @param Query $first
|
|
||||||
* @pram array $list Список параметров
|
|
||||||
*
|
|
||||||
* @return Query
|
|
||||||
*/
|
|
||||||
private function compose(Query $first, array $list)
|
|
||||||
{
|
|
||||||
$result = new Query();
|
|
||||||
foreach ($list as $name) {
|
|
||||||
$result->$name = array_merge($this->$name, $first->$name);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Заковычивает значение
|
|
||||||
*/
|
|
||||||
public function quote ($value)
|
|
||||||
{
|
|
||||||
return "'" . $value . "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Компиляция таблицы
|
|
||||||
* @param Table $table
|
|
||||||
*
|
|
||||||
* @return string Часть строки SQL
|
|
||||||
*/
|
|
||||||
private function table(Table $table)
|
|
||||||
{
|
|
||||||
if ($table->type == 'simple') {
|
|
||||||
return $table->name ." AS ".$table->alias;
|
|
||||||
}
|
|
||||||
if ($table->type == 'join') {
|
|
||||||
return $table->name ." AS ".$table->alias. " JOIN " . $this->table ($table->join) . " ON " . $table->condition;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Компиляция WHERE
|
|
||||||
*
|
|
||||||
* @return string Часть строки SQL
|
|
||||||
*/
|
|
||||||
private function where ()
|
|
||||||
{
|
|
||||||
return implode(" AND ", $this->filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Компиляция запроса в SELECT SQL
|
|
||||||
*
|
|
||||||
* @return string SQL выражение
|
|
||||||
*/
|
|
||||||
public function select()
|
|
||||||
{
|
|
||||||
return "SELECT "
|
|
||||||
. ((!empty($this->calc))? implode (",", $this->calc): "*")
|
|
||||||
. " FROM " . $this->table($this->table)
|
|
||||||
. ((!empty ($this->filter))? " WHERE " . $this->where() : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Компиляция в DELETE
|
|
||||||
*/
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
return "DELETE FROM " . $this->table->name
|
|
||||||
. ((!empty ($this->filter))? " WHERE " . $this->where() : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_prefix($prefix, $array) {
|
|
||||||
$result = array();
|
|
||||||
foreach ($array as $value) {
|
|
||||||
$result [] = $prefix . $value;
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Компиляция в UPDATE
|
|
||||||
* TODO: Разные типы запросов Query->update(); Query->select(), Query->insert();!!
|
|
||||||
* Возвраащают statement
|
|
||||||
*/
|
|
||||||
public function update($values)
|
|
||||||
{
|
|
||||||
$pairs = array ();
|
|
||||||
foreach ($values as $key => $value) { //
|
|
||||||
$pairs [] = $key . "=" . $this->quote ($value);
|
|
||||||
}
|
|
||||||
return "UPDATE " . $this->table->name . " SET "
|
|
||||||
. implode(",", $pairs)
|
|
||||||
. ((!empty($this->filter))? " WHERE " . $this->where() : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Компиляция в INSERT
|
|
||||||
*/
|
|
||||||
public function insert($values)
|
|
||||||
{
|
|
||||||
return "INSERT INTO ". $this->table->name . "("
|
|
||||||
. implode(",", array_keys($values))
|
|
||||||
. ") VALUES (" . implode(",", array_map(array($this, 'quote'), array_values($values))) . ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс таблицы
|
|
||||||
*/
|
|
||||||
class Table
|
|
||||||
{
|
|
||||||
public $type = 'simple';
|
|
||||||
public $name;
|
|
||||||
public $alias;
|
|
||||||
public $join;
|
|
||||||
public $condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/collection.php';
|
|
||||||
|
|
||||||
class SafeCollection extends Collection
|
|
||||||
{
|
|
||||||
protected function _clean()
|
|
||||||
{
|
|
||||||
if(get_magic_quotes_gpc()) {
|
|
||||||
$this->data = $this->_stripSlashes($this->data);
|
|
||||||
}
|
|
||||||
$this->data = $this->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function import(array $data)
|
|
||||||
{
|
|
||||||
parent::import($data);
|
|
||||||
$this->_clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strip slashes code from php.net website.
|
|
||||||
*
|
|
||||||
* @param mixed $value
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function _stripSlashes($value)
|
|
||||||
{
|
|
||||||
if(is_array($value)) {
|
|
||||||
return array_map(array($this,'_stripSlashes'), $value);
|
|
||||||
} else {
|
|
||||||
return stripslashes($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/path.php';
|
|
||||||
require_once 'creole/util/sql/SQLStatementExtractor.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обработка файлов для установки
|
|
||||||
*/
|
|
||||||
class Setup
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Содержимое PHP файла
|
|
||||||
*/
|
|
||||||
static function fileContent($file, array $tpl)
|
|
||||||
{
|
|
||||||
ob_start();
|
|
||||||
include $file;
|
|
||||||
$result = ob_get_contents();
|
|
||||||
ob_clean();
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Копирует файлы шаблонной директории
|
|
||||||
*/
|
|
||||||
static function copyTemplatePath($srcPath, $dstPath, array $tpl, $tplFile = 'tpl')
|
|
||||||
{
|
|
||||||
$out = new Path($srcPath);
|
|
||||||
$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)));
|
|
||||||
Path::prepare($dst);
|
|
||||||
file_put_contents($dst, self::fileContent($file, $tpl));
|
|
||||||
} else {
|
|
||||||
// Обычный файл
|
|
||||||
$dst = $out->append($path->relPath ($file));
|
|
||||||
Path::prepare($dst);
|
|
||||||
copy($file, $dst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Выполнение Списка SQL команд
|
|
||||||
*/
|
|
||||||
static function batchSQL(Connection $conn, $file)
|
|
||||||
{
|
|
||||||
$stmtList = SQLStatementExtractor::extractFile ($file);
|
|
||||||
foreach ($stmtList as $stmt) {
|
|
||||||
$conn->executeQuery ($stmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
100
core/spell.php
100
core/spell.php
|
|
@ -1,100 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/search/htmlhelper.php';
|
|
||||||
/**
|
|
||||||
* Функции для проверки орфографии
|
|
||||||
* rename Spell -> SpellHelper ??
|
|
||||||
*/
|
|
||||||
class Spell
|
|
||||||
{
|
|
||||||
private $pspell;
|
|
||||||
public $autocorrect = false;
|
|
||||||
public function __construct ($language, $encoding)
|
|
||||||
{
|
|
||||||
$this->pspell = pspell_new($language, '', '', $encoding, PSPELL_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
function spellCheckWord ($word)
|
|
||||||
{
|
|
||||||
$word = $word[0];
|
|
||||||
|
|
||||||
// Ignore ALL CAPS
|
|
||||||
if (preg_match('/^[A-Z0-9]*$/', $word)) return $word;
|
|
||||||
|
|
||||||
// Return dictionary words
|
|
||||||
if (pspell_check($this->pspell, $word))
|
|
||||||
return $word;
|
|
||||||
|
|
||||||
// Auto-correct with the first suggestion, color green
|
|
||||||
if ($this->autocorrect && $suggestions = pspell_suggest($this->pspell, $word))
|
|
||||||
return '<span class="spell-suggest">' . current($suggestions) . '</span>';
|
|
||||||
|
|
||||||
// No suggestions, color red
|
|
||||||
return '<span class="spell-nosuggest">' . $word . '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isGoodWord ($word)
|
|
||||||
{
|
|
||||||
// Ignore ALL CAPS
|
|
||||||
if (preg_match('/^[A-Z]*$/', $word)) return true;
|
|
||||||
if (preg_match('/^[0-9]*$/', $word)) return true;
|
|
||||||
|
|
||||||
// Return dictionary words
|
|
||||||
if (pspell_check($this->pspell, $word))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function suggest ($string)
|
|
||||||
{
|
|
||||||
return preg_replace_callback('/\b\w+\b/', array($this, 'spellCheckWord'), $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Вызывает функцию для каждого найденного слова
|
|
||||||
*/
|
|
||||||
function eachWord ($call, $string)
|
|
||||||
{
|
|
||||||
$begin = indexLeft ($string, 'ctype_alpha', 0);
|
|
||||||
while ($begin !== false) {
|
|
||||||
$end = indexLeft ($string, 'not_ctype_alpha', $begin);
|
|
||||||
call_user_func ($call, $string, $begin, $end);
|
|
||||||
$begin = indexLeft ($string, 'ctype_alpha', $end);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет слово на соответствие со словарем
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function doWord (&$string, $begin, $end)
|
|
||||||
{
|
|
||||||
$word = substr($string, $begin, $end - $begin);
|
|
||||||
if (! $this->isGoodWord ($word)) {
|
|
||||||
$start = max(indexLeft ($string, 'not_ctype_alpha', $begin - 100), 0);
|
|
||||||
$offset = indexLeft ($string, 'not_ctype_alpha', $end + 100);
|
|
||||||
if (! $offset) {
|
|
||||||
$offset = strlen($string);
|
|
||||||
}
|
|
||||||
$length = $offset - $start;
|
|
||||||
throw new Exception ($this->suggest(substr($string, $start, $length)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Часть текста содержащий неправильное слово
|
|
||||||
*/
|
|
||||||
function getError ($string)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
self::eachWord (array ($this, 'doWord'), $string);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return $e->getMessage();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразование дерева из модели Plain в массив массивов (Adjacency List)
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'core/functions.php';
|
|
||||||
|
|
||||||
define (SORT_DESC, 0); // descending
|
|
||||||
define (SORT_ASC, 1); // ascending
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Выбирает все сроки из таблицы с уникальными значениями ключа
|
|
||||||
* @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 $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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обходит таблицу как дерево
|
|
||||||
* @param $level Array Уровни вложенности
|
|
||||||
* @param $table Таблица
|
|
||||||
* @param $fn Функция которая применяется к каждой ветке дерева
|
|
||||||
* $fn ($name, $index, $rows, $cc)
|
|
||||||
* @param $name Ключ уровня
|
|
||||||
* @param $index Значение ключа уровня
|
|
||||||
* @param $rows Все столбцы текущго уровня
|
|
||||||
* @parma $cc Столбцы более низкого уровня
|
|
||||||
*/
|
|
||||||
function tableTreeWalk($level, $table, $fn) {
|
|
||||||
if (empty ($level)) return $table;
|
|
||||||
$name = array_shift ($level);
|
|
||||||
|
|
||||||
$keys = key_unique_values($name, $table);
|
|
||||||
$data = array ();
|
|
||||||
foreach ($keys as $index) {
|
|
||||||
list($rows, $table) = partition (lcurry('__index', $index, $name), $table);
|
|
||||||
// $rows = array_filter ($table, lcurry('__index', intval($index), $name));
|
|
||||||
//$rows = array_filter ($table, create_function ('$x', 'return __index ('.intval($index).', \''.$name.'\', $x);'));
|
|
||||||
$data[$index] = call_user_func ($fn, $name, $index, $rows, tableTreeWalk ($level, $rows, $fn));
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Расширения для PHPTAL для отображения времени и даты
|
|
||||||
* package utils
|
|
||||||
*/
|
|
||||||
class DateTime_Tales implements PHPTAL_Tales
|
|
||||||
{
|
|
||||||
static public function date ($expression, $nothrow = false)
|
|
||||||
{
|
|
||||||
return "phptal_date(".PHPTAL_TalesInternal::path ($expression).")";
|
|
||||||
}
|
|
||||||
|
|
||||||
static public function time ($expression, $nothrow = false)
|
|
||||||
{
|
|
||||||
return "phptal_time(".PHPTAL_TalesInternal::path ($expression).")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Регистрация нового префикса для подключения компонента */
|
|
||||||
$registry = PHPTAL_TalesRegistry::getInstance();
|
|
||||||
$registry->registerPrefix('date', array('DateTime_Tales', 'date'));
|
|
||||||
$registry->registerPrefix('time', array('DateTime_Tales', 'time'));
|
|
||||||
|
|
||||||
|
|
||||||
function phptal_date ($e)
|
|
||||||
{
|
|
||||||
return date ("d.m.Y", $e);
|
|
||||||
}
|
|
||||||
|
|
||||||
function phptal_time ($e)
|
|
||||||
{
|
|
||||||
return date ("H:i", $e);
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
function generatePassword($length = 9, $strength = 0) {
|
|
||||||
$vowels = 'aeuy';
|
|
||||||
$consonants = 'bdghjmnpqrstvz';
|
|
||||||
if ($strength & 1) {
|
|
||||||
$consonants .= 'BDGHJLMNPQRSTVWXZ';
|
|
||||||
}
|
|
||||||
if ($strength & 2) {
|
|
||||||
$vowels .= "AEUY";
|
|
||||||
}
|
|
||||||
if ($strength & 4) {
|
|
||||||
$consonants .= '23456789';
|
|
||||||
}
|
|
||||||
if ($strength & 8) {
|
|
||||||
$consonants .= '@#$%';
|
|
||||||
}
|
|
||||||
|
|
||||||
$password = '';
|
|
||||||
$alt = time() % 2;
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
if ($alt == 1) {
|
|
||||||
$password .= $consonants[(rand() % strlen($consonants))];
|
|
||||||
$alt = 0;
|
|
||||||
} else {
|
|
||||||
$password .= $vowels[(rand() % strlen($vowels))];
|
|
||||||
$alt = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $password;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// from creole
|
|
||||||
function strToArray($str)
|
|
||||||
{
|
|
||||||
$str = substr($str, 1, -1); // remove { }
|
|
||||||
$res = array();
|
|
||||||
|
|
||||||
$subarr = array();
|
|
||||||
$in_subarr = 0;
|
|
||||||
|
|
||||||
$toks = explode(',', $str);
|
|
||||||
foreach($toks as $tok) {
|
|
||||||
if ($in_subarr > 0) { // already in sub-array?
|
|
||||||
$subarr[$in_subarr][] = $tok;
|
|
||||||
if ('}' === substr($tok, -1, 1)) { // check to see if we just added last component
|
|
||||||
$res[] = $this->strToArray(implode(',', $subarr[$in_subarr]));
|
|
||||||
$in_subarr--;
|
|
||||||
}
|
|
||||||
} elseif ($tok{0} === '{') { // we're inside a new sub-array
|
|
||||||
if ('}' !== substr($tok, -1, 1)) {
|
|
||||||
$in_subarr++;
|
|
||||||
// if sub-array has more than one element
|
|
||||||
$subarr[$in_subarr] = array();
|
|
||||||
$subarr[$in_subarr][] = $tok;
|
|
||||||
} else {
|
|
||||||
$res[] = $this->strToArray($tok);
|
|
||||||
}
|
|
||||||
} else { // not sub-array
|
|
||||||
$val = trim($tok, '"'); // remove " (surrounding strings)
|
|
||||||
// perform type castng here?
|
|
||||||
$res[] = $val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class TableExcelView {
|
|
||||||
private $list = array();
|
|
||||||
private $data = array();
|
|
||||||
|
|
||||||
function setColumns(array $list) {
|
|
||||||
$this->list = $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeTable() {
|
|
||||||
$xls = new ExcelTable();
|
|
||||||
$xls->setRow(1, 1, array_keys($this->list));
|
|
||||||
|
|
||||||
foreach($this->data as $n => $item) {
|
|
||||||
$result = array();
|
|
||||||
foreach($this->list as $key => $c) {
|
|
||||||
if (is_callable($c)) {
|
|
||||||
$result [] = call_user_func($c, $item, $n);
|
|
||||||
} else {
|
|
||||||
if (is_numeric($item[$c])) {
|
|
||||||
$result [] = new Excel_Number($item[$c]);
|
|
||||||
} else {
|
|
||||||
$result [] = $item[$c];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$xls->addRow(1, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $xls;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeTable($data, $file) {
|
|
||||||
$this->data = $data;
|
|
||||||
|
|
||||||
$xls = new ExcelDocument();
|
|
||||||
$xls->addTable(array($this, 'makeTable'));
|
|
||||||
$xls->save($file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TableHTMLView {
|
|
||||||
private $list = array();
|
|
||||||
private $stack = array();
|
|
||||||
private $result = array();
|
|
||||||
|
|
||||||
function writeElement($name, $content) {
|
|
||||||
echo "<".$name.">";
|
|
||||||
echo $content;
|
|
||||||
echo "</".$name.">";
|
|
||||||
}
|
|
||||||
|
|
||||||
function startElement($name) {
|
|
||||||
array_push($this->stack, $name);
|
|
||||||
echo "<".$name.">";
|
|
||||||
}
|
|
||||||
|
|
||||||
function endElement() {
|
|
||||||
$name = array_pop($this->stack);
|
|
||||||
echo "</".$name.">";
|
|
||||||
}
|
|
||||||
|
|
||||||
function setColumns(array $list) {
|
|
||||||
$this->list = $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeTable($data) {
|
|
||||||
$this->startElement('table');
|
|
||||||
$this->startElement('thead');
|
|
||||||
$this->startElement('tr');
|
|
||||||
foreach($this->list as $key => $c) {
|
|
||||||
$this->writeElement('th', $key);
|
|
||||||
}
|
|
||||||
$this->endElement();
|
|
||||||
$this->endElement();
|
|
||||||
|
|
||||||
$this->startElement('tbody');
|
|
||||||
foreach($data as $n => $item) {
|
|
||||||
$this->startElement('tr');
|
|
||||||
foreach($this->list as $key => $c) {
|
|
||||||
if (is_callable($c)) {
|
|
||||||
$this->writeElement('td', call_user_func($c, $item, $n));
|
|
||||||
} else {
|
|
||||||
$this->writeElement('td', $item[$c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->endElement();
|
|
||||||
}
|
|
||||||
$this->endElement();
|
|
||||||
$this->endElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
function translit($st) {
|
|
||||||
$st = strtr($st,"абвгдеёзийклмнопрстуфхъыэ !№", "abvgdeeziyklmnoprstufh_ie__#");
|
|
||||||
$st = strtr($st,"АБВГДЕЁЗИЙКЛМНОПРСТУФХЪЫЭ", "ABVGDEEZIYKLMNOPRSTUFH_IE");
|
|
||||||
$st = strtr($st, array(
|
|
||||||
"ж"=>"zh", "ц"=>"ts", "ч"=>"ch", "ш"=>"sh",
|
|
||||||
"щ"=>"shch","ь"=>"", "ю"=>"yu", "я"=>"ya",
|
|
||||||
"Ж"=>"ZH", "Ц"=>"TS", "Ч"=>"CH", "Ш"=>"SH",
|
|
||||||
"Щ"=>"SHCH","Ь"=>"", "Ю"=>"YU", "Я"=>"YA",
|
|
||||||
"ї"=>"i", "Ї"=>"Yi", "є"=>"ie", "Є"=>"Ye"
|
|
||||||
));
|
|
||||||
return $st;
|
|
||||||
}
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
<?php
|
|
||||||
//****************************************************************************
|
|
||||||
// phpDatabase 2.1
|
|
||||||
//****************************************************************************
|
|
||||||
// Author: Maxim Poltarak <maxx at e dash taller dot net>
|
|
||||||
// Category: Databases
|
|
||||||
//****************************************************************************
|
|
||||||
// The lib is FREEWARE. This means you may use it anywhere you want, you may
|
|
||||||
// do anything with it. The Author mentioned above is NOT responsible for any
|
|
||||||
// consequences of using this library.
|
|
||||||
// If you don't agree with this, you MAY NOT use the lib!
|
|
||||||
//****************************************************************************
|
|
||||||
// All improvings, feature requests, bug reports, etc. are gladly accepted.
|
|
||||||
//****************************************************************************
|
|
||||||
// Note: For best viewing of the code Tab size 4 is recommended
|
|
||||||
//****************************************************************************
|
|
||||||
|
|
||||||
class CDatabase
|
|
||||||
{
|
|
||||||
var $link;
|
|
||||||
var $db;
|
|
||||||
var $host, $user, $pass;
|
|
||||||
|
|
||||||
function CDatabase($db, $host = "localhost", $user = "", $pass = "")
|
|
||||||
{
|
|
||||||
$this->db = $db;
|
|
||||||
$this->host = $host;
|
|
||||||
$this->user = $user;
|
|
||||||
$this->pass = $pass;
|
|
||||||
$str = "host={$host} port=5432 dbname={$db} user={$user} password={$pass}";
|
|
||||||
$this->link = pg_connect($str);
|
|
||||||
}
|
|
||||||
|
|
||||||
function query($sql)
|
|
||||||
{
|
|
||||||
if (!$this->link) return 0;
|
|
||||||
return pg_query($this->link, $sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
function affected_rows()
|
|
||||||
{
|
|
||||||
return pg_affected_rows($this->link);
|
|
||||||
}
|
|
||||||
|
|
||||||
function num_rows($q)
|
|
||||||
{
|
|
||||||
return pg_num_rows($q);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetch_array($q) // fetchAll
|
|
||||||
{
|
|
||||||
return pg_fetch_array($q, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetch_object($q) // fetchObject
|
|
||||||
{
|
|
||||||
return pg_fetch_object($q);
|
|
||||||
}
|
|
||||||
/* function data_seek($q, $n) {
|
|
||||||
return pg_data_seek($q, $n);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function free_result($q)
|
|
||||||
{
|
|
||||||
return pg_free_result($q);
|
|
||||||
}
|
|
||||||
|
|
||||||
function insert_id($seq)
|
|
||||||
{
|
|
||||||
$query = "SELECT currval('$seq')";
|
|
||||||
$res = $this->query($query);
|
|
||||||
$row = pg_fetch_array($res, NULL, PGSQL_ASSOC);
|
|
||||||
pg_free_result($res);
|
|
||||||
return ($row) ? $row['currval'] : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function error()
|
|
||||||
{
|
|
||||||
return pg_last_error($this->link);
|
|
||||||
}
|
|
||||||
|
|
||||||
function error_die($msg = '')
|
|
||||||
{
|
|
||||||
die(((empty($msg)) ? '' : $msg . ': ') . $this->error());
|
|
||||||
}
|
|
||||||
|
|
||||||
function sql2var($sql)
|
|
||||||
{
|
|
||||||
|
|
||||||
if ((empty($sql)) || (!($query = $this->query($sql)))) return false;
|
|
||||||
|
|
||||||
if ($this->num_rows($query) < 1) return false;
|
|
||||||
return $this->result2var($query);
|
|
||||||
}
|
|
||||||
|
|
||||||
function result2var($q)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!($Data = $this->fetch_array($q))) return false;
|
|
||||||
$this->free_result($q);
|
|
||||||
|
|
||||||
foreach($Data as $k => $v) $GLOBALS[$k] = $v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*function sql2array($sql, $keyField = '')
|
|
||||||
{
|
|
||||||
|
|
||||||
if ((empty($sql)) || (!($query = $this->query($sql)))) return false;
|
|
||||||
|
|
||||||
if ($this->num_rows($query) < 1) return false;
|
|
||||||
return $this->result2array($query, $keyField);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
function result2array($q, $keyField = '')
|
|
||||||
{
|
|
||||||
$Result = array();
|
|
||||||
while ($Data = $this->fetch_array($q))
|
|
||||||
if (empty($keyField)) $Result[] = $Data;
|
|
||||||
else $Result[$Data[$keyField]] = $Data;
|
|
||||||
$this->free_result($q);
|
|
||||||
return $Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*function list_tables()
|
|
||||||
{
|
|
||||||
return mysql_list_tables($this->db, $this->link);
|
|
||||||
}
|
|
||||||
|
|
||||||
function list_fields($table_name)
|
|
||||||
{
|
|
||||||
return mysql_list_fields($this->db, $table_name, $this->link);
|
|
||||||
}*/
|
|
||||||
};
|
|
||||||
|
|
@ -1,636 +0,0 @@
|
||||||
<?php
|
|
||||||
//****************************************************************************
|
|
||||||
// phpDBTree 1.4
|
|
||||||
//****************************************************************************
|
|
||||||
// Author: Maxim Poltarak <maxx at e dash taller dot net>
|
|
||||||
// WWW: http://dev.e-taller.net/dbtree/
|
|
||||||
// Category: Databases
|
|
||||||
// Description: PHP class implementing a Nested Sets approach to storing
|
|
||||||
// tree-like structures in database tables. This technique was
|
|
||||||
// introduced by Joe Celko <http://www.celko.com/> and has some
|
|
||||||
// advantages over a widely used method called Adjacency Matrix.
|
|
||||||
//****************************************************************************
|
|
||||||
// The lib is FREEWARE. That means you may use it anywhere you want, you may
|
|
||||||
// do anything with it. The Author mentioned above is NOT responsible for any
|
|
||||||
// consequences of using this library.
|
|
||||||
// If you don't agree with this, you are NOT ALLOWED to use the lib!
|
|
||||||
//****************************************************************************
|
|
||||||
// You're welcome to send me all improvings, feature requests, bug reports...
|
|
||||||
//****************************************************************************
|
|
||||||
// SAMPLE DB TABLE STRUCTURE:
|
|
||||||
//
|
|
||||||
// CREATE TABLE categories (
|
|
||||||
// cat_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
// cat_left INT UNSIGNED NOT NULL,
|
|
||||||
// cat_right INT UNSIGNED NOT NULL,
|
|
||||||
// cat_level INT UNSIGNED NOT NULL,
|
|
||||||
// PRIMARY KEY(cat_id),
|
|
||||||
// KEY(cat_left, cat_right, cat_level)
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// This is believed to be the optimal Nested Sets use case. Use `one-to-one`
|
|
||||||
// relations on `cat_id` field between this `structure` table and
|
|
||||||
// another `data` table in your database.
|
|
||||||
//
|
|
||||||
// Don't forget to make a single call to clear()
|
|
||||||
// to set up the Root node in an empty table.
|
|
||||||
//
|
|
||||||
//****************************************************************************
|
|
||||||
// NOTE: Although you may use this library to retrieve data from the table,
|
|
||||||
// it is recommended to write your own queries for doing that.
|
|
||||||
// The main purpose of the library is to provide a simpler way to
|
|
||||||
// create, update and delete records. Not to SELECT them.
|
|
||||||
//****************************************************************************
|
|
||||||
//
|
|
||||||
// IMPORTANT! DO NOT create either UNIQUE or PRIMARY keys on the set of
|
|
||||||
// fields (`cat_left`, `cat_right` and `cat_level`)!
|
|
||||||
// Unique keys will destroy the Nested Sets structure!
|
|
||||||
//
|
|
||||||
//****************************************************************************
|
|
||||||
// CHANGELOG:
|
|
||||||
// 16-Apr-2003 -=- 1.1
|
|
||||||
// - Added moveAll() method
|
|
||||||
// - Added fourth parameter to the constructor
|
|
||||||
// - Renamed getElementInfo() to getNodeInfo() /keeping BC/
|
|
||||||
// - Added "Sample Table Structure" comment
|
|
||||||
// - Now it trigger_error()'s in case of any serious error, because if not you
|
|
||||||
// will lose the Nested Sets structure in your table
|
|
||||||
// 19-Feb-2004 -=- 1.2
|
|
||||||
// - Fixed a bug in moveAll() method?
|
|
||||||
// Thanks to Maxim Matyukhin for the patch.
|
|
||||||
// 13-Jul-2004 -=- 1.3
|
|
||||||
// - Changed all die()'s for a more standard trigger_error()
|
|
||||||
// Thanks to Dmitry Romakhin for pointing out an issue with
|
|
||||||
// incorrect error message call.
|
|
||||||
// 09-Nov-2004 -=- 1.4
|
|
||||||
// - Added insertNear() method.
|
|
||||||
// Thanks to Michael Krenz who sent its implementation.
|
|
||||||
// - Removed IGNORE keyword from UPDATE clauses in insert() methods.
|
|
||||||
// It was dumb to have it there all the time. Sorry. Anyway, you had
|
|
||||||
// to follow the important note mencioned above. If you hadn't, you're
|
|
||||||
// in problem.
|
|
||||||
//
|
|
||||||
//****************************************************************************
|
|
||||||
// Note: For best viewing of the code Tab size 4 is recommended
|
|
||||||
//****************************************************************************
|
|
||||||
|
|
||||||
function _case($c, $then, $else) {
|
|
||||||
return " (CASE WHEN $c THEN $then ELSE $else END) ";
|
|
||||||
}
|
|
||||||
|
|
||||||
function _between($a, $x, $y) {
|
|
||||||
return " " . $a . " BETWEEN " . $x . " AND " . $y;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _inside($a, $x, $y) {
|
|
||||||
return " " . $a . " > " . $x . " AND " . $a . " < " . $y;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CDBTree
|
|
||||||
{
|
|
||||||
var $db; // CDatabase class to plug to
|
|
||||||
var $table; // Table with Nested Sets implemented
|
|
||||||
var $id; // Name of the ID-auto_increment-field in the table.
|
|
||||||
// These 3 variables are names of fields which are needed to implement
|
|
||||||
// Nested Sets. All 3 fields should exist in your table!
|
|
||||||
// However, you may want to change their names here to avoid name collisions.
|
|
||||||
var $left = 'cat_left';
|
|
||||||
var $right = 'cat_right';
|
|
||||||
var $level = 'cat_level';
|
|
||||||
var $qryParams = '';
|
|
||||||
var $qryFields = '';
|
|
||||||
var $qryTables = '';
|
|
||||||
var $qryWhere = '';
|
|
||||||
var $qryGroupBy = '';
|
|
||||||
var $qryHaving = '';
|
|
||||||
var $qryOrderBy = '';
|
|
||||||
var $qryLimit = '';
|
|
||||||
var $sqlNeedReset = true;
|
|
||||||
var $sql; // Last SQL query
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Constructor
|
|
||||||
// $DB : CDatabase class instance to link to
|
|
||||||
// $tableName : table in database where to implement nested sets
|
|
||||||
// $itemId : name of the field which will uniquely identify every record
|
|
||||||
// $fieldNames : optional configuration array to set field names. Example:
|
|
||||||
// array(
|
|
||||||
// 'left' => 'cat_left',
|
|
||||||
// 'right' => 'cat_right',
|
|
||||||
// 'level' => 'cat_level'
|
|
||||||
// )
|
|
||||||
function CDBTree(&$DB, $tableName, $itemId, $seq, $fieldNames = array())
|
|
||||||
{
|
|
||||||
|
|
||||||
if (empty($tableName)) trigger_error("phpDbTree: Unknown table", E_USER_ERROR);
|
|
||||||
|
|
||||||
if (empty($itemId)) trigger_error("phpDbTree: Unknown ID column", E_USER_ERROR);
|
|
||||||
$this->seq = $seq;
|
|
||||||
$this->db = $DB;
|
|
||||||
$this->table = $tableName;
|
|
||||||
$this->id = $itemId;
|
|
||||||
|
|
||||||
if (is_array($fieldNames) && sizeof($fieldNames))
|
|
||||||
foreach($fieldNames as $k => $v) $this->$k = $v;
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Returns a Left and Right IDs and Level of an element or false on error
|
|
||||||
// $ID : an ID of the element
|
|
||||||
function getElementInfo($ID)
|
|
||||||
{
|
|
||||||
return $this->getNodeInfo($ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNodeInfo($ID)
|
|
||||||
{
|
|
||||||
$this->sql = 'SELECT ' . $this->left . ',' . $this->right . ',' . $this->level . ' FROM ' . $this->table . ' WHERE ' . $this->id . '=\'' . $ID . '\'';
|
|
||||||
// print_r($this->sql);
|
|
||||||
|
|
||||||
if (($query = $this->db->query($this->sql)) && ($this->db->num_rows($query) == 1) && ($Data = $this->db->fetch_array($query))) return array(
|
|
||||||
(int)$Data[$this->left],
|
|
||||||
(int)$Data[$this->right],
|
|
||||||
(int)$Data[$this->level]
|
|
||||||
);
|
|
||||||
else trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR); // throw new Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Clears table and creates 'root' node
|
|
||||||
// $data : optional argument with data for the root node
|
|
||||||
function clear($data = array())
|
|
||||||
{
|
|
||||||
// clearing table
|
|
||||||
|
|
||||||
if ((!$this->db->query('TRUNCATE ' . $this->table)) && (!$this->db->query('DELETE FROM ' . $this->table))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// preparing data to be inserted
|
|
||||||
|
|
||||||
if (sizeof($data)) {
|
|
||||||
$fld_names = implode(',', array_keys($data)) . ',';
|
|
||||||
|
|
||||||
if (sizeof($data)) $fld_values = '\'' . implode('\',\'', array_values($data)) . '\',';
|
|
||||||
}
|
|
||||||
$fld_names.= $this->left . ',' . $this->right . ',' . $this->level;
|
|
||||||
$fld_values.= '1,2,0';
|
|
||||||
// inserting new record
|
|
||||||
$this->sql = 'INSERT INTO ' . $this->table . '(' . $fld_names . ') VALUES(' . $fld_values . ')';
|
|
||||||
|
|
||||||
if (!($this->db->query($this->sql))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
return $this->db->insert_id($this->seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Updates a record
|
|
||||||
// $ID : element ID
|
|
||||||
// $data : array with data to update: array(<field_name> => <fields_value>)
|
|
||||||
function update($ID, $data)
|
|
||||||
{
|
|
||||||
$sql_set = '';
|
|
||||||
|
|
||||||
foreach($data as $k => $v) $sql_set.= ',' . $k . '=\'' . addslashes($v) . '\'';
|
|
||||||
return $this->db->query('UPDATE ' . $this->table . ' SET ' . substr($sql_set, 1) . ' WHERE ' . $this->id . '=\'' . $ID . '\'');
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Inserts a record into the table with nested sets
|
|
||||||
// $ID : an ID of the parent element
|
|
||||||
// $data : array with data to be inserted: array(<field_name> => <field_value>)
|
|
||||||
// Returns : true on success, or false on error
|
|
||||||
function insert($ID, $data)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// preparing data to be inserted
|
|
||||||
|
|
||||||
if (sizeof($data)) {
|
|
||||||
$fld_names = implode(',', array_keys($data)) . ',';
|
|
||||||
$fld_values = '\'' . implode('\',\'', array_values($data)) . '\',';
|
|
||||||
}
|
|
||||||
$fld_names.= $this->left . ',' . $this->right . ',' . $this->level;
|
|
||||||
$fld_values.= ($rightId) . ',' . ($rightId+1) . ',' . ($level+1);
|
|
||||||
// creating a place for the record being inserted
|
|
||||||
|
|
||||||
if ($ID) {
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET ' . $this->left . '=' . _case($this->left . '>' . $rightId, $this->left . '+2', $this->left) . ',' . $this->right . '=' . _case($this->right . '>=' . $rightId, $this->right . '+2', $this->right) . 'WHERE ' . $this->right . '>=' . $rightId;
|
|
||||||
|
|
||||||
if (!($this->db->query($this->sql))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
}
|
|
||||||
// inserting new record
|
|
||||||
$this->sql = 'INSERT INTO ' . $this->table . '(' . $fld_names . ') VALUES(' . $fld_values . ')';
|
|
||||||
|
|
||||||
if (!($this->db->query($this->sql))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
return $this->db->insert_id($this->seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Inserts a record into the table with nested sets
|
|
||||||
// $ID : ID of the element after which (i.e. at the same level) the new element
|
|
||||||
// is to be inserted
|
|
||||||
// $data : array with data to be inserted: array(<field_name> => <field_value>)
|
|
||||||
// Returns : true on success, or false on error
|
|
||||||
function insertNear($ID, $data)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// preparing data to be inserted
|
|
||||||
|
|
||||||
if (sizeof($data)) {
|
|
||||||
$fld_names = implode(',', array_keys($data)) . ',';
|
|
||||||
$fld_values = '\'' . implode('\',\'', array_values($data)) . '\',';
|
|
||||||
}
|
|
||||||
$fld_names.= $this->left . ',' . $this->right . ',' . $this->level;
|
|
||||||
$fld_values.= ($rightId+1) . ',' . ($rightId+2) . ',' . ($level);
|
|
||||||
// creating a place for the record being inserted
|
|
||||||
|
|
||||||
if ($ID) {
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET ' . $this->left . '=' . _case($this->left . '>' . $rightId, $this->left . '+2', $this->left) . $this->right . '=' . _case($this->right . '>' . $rightId, $this->right . '+2', $this->right) . 'WHERE ' . $this->right . '>' . $rightId;
|
|
||||||
|
|
||||||
if (!($this->db->query($this->sql))) trigger_error("phpDbTree error:" . $this->db->error() , E_USER_ERROR);
|
|
||||||
}
|
|
||||||
// inserting new record
|
|
||||||
$this->sql = 'INSERT INTO ' . $this->table . '(' . $fld_names . ') VALUES(' . $fld_values . ')';
|
|
||||||
|
|
||||||
if (!($this->db->query($this->sql))) trigger_error("phpDbTree error:" . $this->db->error() , E_USER_ERROR);
|
|
||||||
return $this->db->insert_id($this->seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Assigns a node with all its children to another parent
|
|
||||||
// $ID : node ID
|
|
||||||
// $newParentID : ID of new parent node
|
|
||||||
// Returns : false on error
|
|
||||||
function moveAll($ID, $newParentId)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
|
|
||||||
if (!(list($leftIdP, $rightIdP, $levelP) = $this->getNodeInfo($newParentId))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
|
|
||||||
if ($ID == $newParentId || $leftId == $leftIdP || ($leftIdP >= $leftId && $leftIdP <= $rightId)) return false;
|
|
||||||
// whether it is being moved upwards along the path
|
|
||||||
|
|
||||||
if ($leftIdP < $leftId && $rightIdP > $rightId && $levelP < $level-1) {
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
. $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) . ","
|
|
||||||
. $this->right . '=' . _case($this->right . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) , $this->right . '-' . ($rightId-$leftId+1)
|
|
||||||
, _case($this->left . ' BETWEEN ' . ($leftId) . ' AND ' . ($rightId) , $this->right . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->right)) . ","
|
|
||||||
. $this->left . '=' . _case($this->left . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) , $this->left . '-' . ($rightId-$leftId+1) , _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . ($rightId) , $this->left . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->left)) . 'WHERE ' . $this->left . ' BETWEEN ' . ($leftIdP+1) . ' AND ' . ($rightIdP-1);
|
|
||||||
|
|
||||||
} elseif ($leftIdP < $leftId) {
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
. $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) . ","
|
|
||||||
. $this->left . '=' . _case($this->left . ' BETWEEN ' . $rightIdP . ' AND ' . ($leftId-1) , $this->left . '+' . ($rightId-$leftId+1)
|
|
||||||
, _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->left . '-' . ($leftId-$rightIdP) , $this->left)) . ","
|
|
||||||
. $this->right . '=' . _case($this->right . ' BETWEEN ' . $rightIdP . ' AND ' . $leftId, $this->right . '+' . ($rightId-$leftId+1) , _case($this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->right . '-' . ($leftId-$rightIdP) , $this->right)) . 'WHERE ' . $this->left . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId
|
|
||||||
// !!! added this line (Maxim Matyukhin)
|
|
||||||
. ' OR ' . $this->right . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId;
|
|
||||||
} else {
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
. $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level) . ","
|
|
||||||
. $this->left . '=' . _case($this->left . ' BETWEEN ' . $rightId . ' AND ' . $rightIdP, $this->left . '-' . ($rightId-$leftId+1)
|
|
||||||
, _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->left . '+' . ($rightIdP-1-$rightId), $this->left)) . ", "
|
|
||||||
. $this->right . '=' . _case($this->right . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) , $this->right . '-' . ($rightId-$leftId+1) , _case($this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->right . '+' . ($rightIdP-1-$rightId) , $this->right)) . 'WHERE ' . $this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP
|
|
||||||
// !!! added this line (Maxim Matyukhin)
|
|
||||||
. ' OR ' . $this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP;
|
|
||||||
}
|
|
||||||
return $this->db->query($this->sql) or trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Перемещение всех детей ветки в другую ветку
|
|
||||||
function moveChildren($ID, $newParentId)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
|
|
||||||
if (!(list($leftIdP, $rightIdP, $levelP) = $this->getNodeInfo($newParentId))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
|
|
||||||
if ($ID == $newParentId || $leftId == $leftIdP || ($leftIdP >= $leftId && $leftIdP <= $rightId)) return false;
|
|
||||||
// whether it is being moved upwards along the path
|
|
||||||
|
|
||||||
if ($leftIdP < $leftId && $rightIdP > $rightId && $levelP < $level-1) {
|
|
||||||
// _update($this->table, array(), )
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
// Меняем уровень
|
|
||||||
. $this->level . '=' .
|
|
||||||
_case(_between($this->left, $leftId, $rightId),
|
|
||||||
$this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level)
|
|
||||||
// Меняем границы
|
|
||||||
. $this->left . '=' .
|
|
||||||
_case(_beetween($this->left, $rightId+1, $rightIdP-1), $this->left . '-' . $rightId-$leftId+1 ,
|
|
||||||
_case(_between($this->left, $leftId, $rightId), $this->left . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->left))
|
|
||||||
. $this->right . '=' .
|
|
||||||
_case(_between($this->right, $rightId+1, $rightIdP-1), $this->right . '-' . ($rightId-$leftId+1) ,
|
|
||||||
_case(_between($this->left, $leftId, $rightId), $this->right . '+' . ((($rightIdP-$rightId-$level+$levelP) /2) *2+$level-$levelP-1) , $this->right))
|
|
||||||
. 'WHERE ' . _between($this->left, ($leftIdP+1), ($rightIdP-1));
|
|
||||||
|
|
||||||
} elseif ($leftIdP < $leftId) {
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
. $this->level . '=' .
|
|
||||||
_case(_between($this->left, $leftId, $rightId),
|
|
||||||
$this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level)
|
|
||||||
. $this->left . '=' .
|
|
||||||
_case(_between($this->left, $rightIdP, $leftId-1), $this->left . '+' . ($rightId-$leftId+1),
|
|
||||||
_case(_between($this->left, $leftId, $rightId), $this->left . '-' . ($leftId-$rightIdP) , $this->left))
|
|
||||||
. $this->right . '=' .
|
|
||||||
_case(_between($this->right, $rightIdP, $leftId), $this->right . '+' . ($rightId-$leftId+1),
|
|
||||||
_case(_between($this->right, $leftId, $rightId), $this->right . '-' . ($leftId-$rightIdP) , $this->right))
|
|
||||||
. 'WHERE ' . _between($this->left, $leftIdP, $rightId)
|
|
||||||
// !!! added this line (Maxim Matyukhin)
|
|
||||||
. ' OR ' . _between($this->right, $leftIdP, $rightId);
|
|
||||||
} else {
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
. $this->level . '='
|
|
||||||
. _case(_between($this->left, $leftId, $rightId),
|
|
||||||
$this->level . sprintf('%+d', -($level-1) +$levelP) , $this->level)
|
|
||||||
. $this->left . '=' .
|
|
||||||
_case(_between($this->left, $rightId, $rightIdP), $this->left . '-' . ($rightId-$leftId+1),
|
|
||||||
_case(_between($this->left, $leftId, $rightId), $this->left . '+' . ($rightIdP-1-$rightId), $this->left))
|
|
||||||
. $this->right . '=' .
|
|
||||||
_case(_between($this->right, $rightId+1, $rightIdP-1), $this->right . '-' . ($rightId-$leftId+1),
|
|
||||||
_case(_between($this->right, $leftId, $rightId), $this->right . '+' . ($rightIdP-1-$rightId) , $this->right))
|
|
||||||
. 'WHERE ' . _between($this->left, $leftId, $rightIdP)
|
|
||||||
// !!! added this line (Maxim Matyukhin)
|
|
||||||
. ' OR ' . _between($this->right, $leftId, $rightIdP);
|
|
||||||
}
|
|
||||||
return $this->db->query($this->sql) or trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Deletes a record wihtout deleting its children
|
|
||||||
// $ID : an ID of the element to be deleted
|
|
||||||
// Returns : true on success, or false on error
|
|
||||||
function delete($ID)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// Deleting record
|
|
||||||
$this->sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->id . '=\'' . $ID . '\'';
|
|
||||||
|
|
||||||
if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// Clearing blank spaces in a tree
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
. $this->left . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->left . '-1', $this->left) . ", "
|
|
||||||
. $this->right . '=' . _case($this->right . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->right . '-1', $this->right) . ", "
|
|
||||||
. $this->level . '=' . _case($this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId, $this->level . '-1', $this->level) . ", "
|
|
||||||
. $this->left . '=' . _case($this->left . '>' . $rightId, $this->left . '-2', $this->left) . ", "
|
|
||||||
. $this->right . '=' . _case($this->right . '>' . $rightId, $this->right . '-2', $this->right)
|
|
||||||
. ' WHERE ' . $this->right . '>' . $leftId;
|
|
||||||
|
|
||||||
if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Deletes a record with all its children
|
|
||||||
// $ID : an ID of the element to be deleted
|
|
||||||
// Returns : true on success, or false on error
|
|
||||||
function deleteAll($ID)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(list($leftId, $rightId, $level) = $this->getNodeInfo($ID))) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// Deleteing record(s)
|
|
||||||
$this->sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->left . ' BETWEEN ' . $leftId . ' AND ' . $rightId;
|
|
||||||
|
|
||||||
if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// Clearing blank spaces in a tree
|
|
||||||
$deltaId = ($rightId-$leftId) +1;
|
|
||||||
$this->sql = 'UPDATE ' . $this->table . ' SET '
|
|
||||||
. $this->left . '=' . _case($this->left . '>' . $leftId, $this->left . '-' . $deltaId, $this->left) . ", "
|
|
||||||
. $this->right . '=' . _case($this->right . '>' . $leftId, $this->right . '-' . $deltaId, $this->right)
|
|
||||||
. ' WHERE ' . $this->right . '>' . $rightId;
|
|
||||||
|
|
||||||
if (!$this->db->query($this->sql)) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Enumerates children of an element
|
|
||||||
// $ID : an ID of an element which children to be enumerated
|
|
||||||
// $start_level : relative level from which start to enumerate children
|
|
||||||
// $end_level : the last relative level at which enumerate children
|
|
||||||
// 1. If $end_level isn't given, only children of
|
|
||||||
// $start_level levels are enumerated
|
|
||||||
// 2. Level values should always be greater than zero.
|
|
||||||
// Level 1 means direct children of the element
|
|
||||||
// Returns : a result id for using with other DB functions
|
|
||||||
function enumChildrenAll($ID)
|
|
||||||
{
|
|
||||||
return $this->enumChildren($ID, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function enumChildren($ID, $start_level = 1, $end_level = 1)
|
|
||||||
{
|
|
||||||
if ($start_level < 0) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
// We could use sprintf() here, but it'd be too slow
|
|
||||||
$whereSql1 = ' AND ' . $this->table . '.' . $this->level;
|
|
||||||
$whereSql2 = '_' . $this->table . '.' . $this->level . '+';
|
|
||||||
|
|
||||||
if (!$end_level) $whereSql = $whereSql1 . '>=' . $whereSql2 . (int)$start_level;
|
|
||||||
else {
|
|
||||||
$whereSql = ($end_level <= $start_level) ? $whereSql1 . '=' . $whereSql2 . (int)$start_level : ' AND ' . $this->table . '.' . $this->level . ' BETWEEN _' . $this->table . '.' . $this->level . '+' . (int)$start_level . ' AND _' . $this->table . '.' . $this->level . '+' . (int)$end_level;
|
|
||||||
}
|
|
||||||
$this->sql = $this->sqlComposeSelect(array(
|
|
||||||
'', // Params
|
|
||||||
'', // Fields
|
|
||||||
$this->table . ' _' . $this->table . ', ' . $this->table, // Tables
|
|
||||||
'_' . $this->table . '.' . $this->id . '=\'' . $ID . '\'' . ' AND ' . $this->table . '.' . $this->left . ' BETWEEN _' . $this->table . '.' . $this->left . ' AND _' . $this->table . '.' . $this->right . $whereSql
|
|
||||||
));
|
|
||||||
return $this->db->query($this->sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
function enumChildrenArray($ID, $start_level = 1, $end_level = 1)
|
|
||||||
{
|
|
||||||
return $this->db->result2array($this->enumChildren($ID, $start_level, $end_level));
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Enumerates the PATH from an element to its top level parent
|
|
||||||
// $ID : an ID of an element
|
|
||||||
// $showRoot : whether to show root node in a path
|
|
||||||
// Returns : a result id for using with other DB functions
|
|
||||||
function enumPath($ID, $showRoot = false)
|
|
||||||
{
|
|
||||||
$this->sql = $this->sqlComposeSelect(array(
|
|
||||||
'', // Params
|
|
||||||
'', // Fields
|
|
||||||
$this->table . ' _' . $this->table . ', ' . $this->table, // Tables
|
|
||||||
'_' . $this->table . '.' . $this->id . '=\'' . $ID . '\'' . ' AND _' . $this->table . '.' . $this->left . ' BETWEEN ' . $this->table . '.' . $this->left . ' AND ' . $this->table . '.' . $this->right . (($showRoot) ? '' : ' AND ' . $this->table . '.' . $this->level . '>0') , // Where
|
|
||||||
'', // GroupBy
|
|
||||||
'', // Having
|
|
||||||
$this->table . '.' . $this->left // OrderBy
|
|
||||||
|
|
||||||
));
|
|
||||||
return $this->db->query($this->sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
function enumPathArray($ID, $showRoot = false)
|
|
||||||
{
|
|
||||||
return $this->db->result2array($this->enumPath($ID, $showRoot));
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
// Returns query result to fetch data of the element's parent
|
|
||||||
// $ID : an ID of an element which parent to be retrieved
|
|
||||||
// $level : Relative level of parent
|
|
||||||
// Returns : a result id for using with other DB functions
|
|
||||||
function getParent($ID, $level = 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($level < 1) trigger_error("phpDbTree error: " . $this->db->error() , E_USER_ERROR);
|
|
||||||
$this->sql = $this->sqlComposeSelect(array(
|
|
||||||
'', // Params
|
|
||||||
'', // Fields
|
|
||||||
$this->table . ' _' . $this->table . ', ' . $this->table, // Tables
|
|
||||||
'_' . $this->table . '.' . $this->id . '=\'' . $ID . '\'' . ' AND _' . $this->table . '.' . $this->left . ' BETWEEN ' . $this->table . '.' . $this->left . ' AND ' . $this->table . '.' . $this->right . ' AND ' . $this->table . '.' . $this->level . '=_' . $this->table . '.' . $this->level . '-' . (int)$level // Where
|
|
||||||
|
|
||||||
));
|
|
||||||
$result = $this->db->result2array($this->db->query($this->sql));
|
|
||||||
return (int)$result[0][$this->id];
|
|
||||||
}
|
|
||||||
//************************************************************************
|
|
||||||
|
|
||||||
function sqlReset()
|
|
||||||
{
|
|
||||||
$this->qryParams = '';
|
|
||||||
$this->qryFields = '';
|
|
||||||
$this->qryTables = '';
|
|
||||||
$this->qryWhere = '';
|
|
||||||
$this->qryGroupBy = '';
|
|
||||||
$this->qryHaving = '';
|
|
||||||
$this->qryOrderBy = '';
|
|
||||||
$this->qryLimit = '';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
function sqlSetReset($resetMode)
|
|
||||||
{
|
|
||||||
$this->sqlNeedReset = ($resetMode) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
function sqlParams($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryParams : $this->qryParams = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlFields($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryFields : $this->qryFields = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlSelect($param = '')
|
|
||||||
{
|
|
||||||
return $this->sqlFields($param);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlTables($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryTables : $this->qryTables = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlFrom($param = '')
|
|
||||||
{
|
|
||||||
return $this->sqlTables($param);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlWhere($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryWhere : $this->qryWhere = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlGroupBy($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryGroupBy : $this->qryGroupBy = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlHaving($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryHaving : $this->qryHaving = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlOrderBy($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryOrderBy : $this->qryOrderBy = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sqlLimit($param = '')
|
|
||||||
{
|
|
||||||
return (empty($param)) ? $this->qryLimit : $this->qryLimit = $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************************
|
|
||||||
function sqlComposeSelect($arSql)
|
|
||||||
{
|
|
||||||
$joinTypes = array(
|
|
||||||
'join' => 1,
|
|
||||||
'cross' => 1,
|
|
||||||
'inner' => 1,
|
|
||||||
'straight' => 1,
|
|
||||||
'left' => 1,
|
|
||||||
'natural' => 1,
|
|
||||||
'right' => 1
|
|
||||||
);
|
|
||||||
$this->sql = 'SELECT ' . $arSql[0] . ' ';
|
|
||||||
|
|
||||||
if (!empty($this->qryParams)) $this->sql.= $this->sqlParams . ' ';
|
|
||||||
|
|
||||||
if (empty($arSql[1]) && empty($this->qryFields)) $this->sql.= $this->table . '.' . $this->id;
|
|
||||||
else {
|
|
||||||
|
|
||||||
if (!empty($arSql[1])) $this->sql.= $arSql[1];
|
|
||||||
|
|
||||||
if (!empty($this->qryFields)) $this->sql.= ((empty($arSql[1])) ? '' : ',') . $this->qryFields;
|
|
||||||
}
|
|
||||||
$this->sql.= ' FROM ';
|
|
||||||
// $tblAr = array(0 => 'join');
|
|
||||||
$isJoin = ($tblAr = explode(' ', trim($this->qryTables)))
|
|
||||||
&& /*($joinTypes[strtolower($tblAr[0]) ])*/ 1;
|
|
||||||
|
|
||||||
if (empty($arSql[2]) && empty($this->qryTables)) $this->sql.= $this->table;
|
|
||||||
else {
|
|
||||||
|
|
||||||
if (!empty($arSql[2])) $this->sql.= $arSql[2];
|
|
||||||
|
|
||||||
if (!empty($this->qryTables)) {
|
|
||||||
|
|
||||||
if (!empty($arSql[2])) $this->sql.= (($isJoin) ? ' ' : ',');
|
|
||||||
elseif ($isJoin) $this->sql.= $this->table . ' ';
|
|
||||||
$this->sql.= $this->qryTables;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!empty($arSql[3])) || (!empty($this->qryWhere))) {
|
|
||||||
$this->sql.= ' WHERE ' . $arSql[3] . ' ';
|
|
||||||
|
|
||||||
if (!empty($this->qryWhere)) $this->sql.= (empty($arSql[3])) ? $this->qryWhere : 'AND(' . $this->qryWhere . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!empty($arSql[4])) || (!empty($this->qryGroupBy))) {
|
|
||||||
$this->sql.= ' GROUP BY ' . $arSql[4] . ' ';
|
|
||||||
|
|
||||||
if (!empty($this->qryGroupBy)) $this->sql.= (empty($arSql[4])) ? $this->qryGroupBy : ',' . $this->qryGroupBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!empty($arSql[5])) || (!empty($this->qryHaving))) {
|
|
||||||
$this->sql.= ' HAVING ' . $arSql[5] . ' ';
|
|
||||||
|
|
||||||
if (!empty($this->qryHaving)) $this->sql.= (empty($arSql[5])) ? $this->qryHaving : 'AND(' . $this->qryHaving . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!empty($arSql[6])) || (!empty($this->qryOrderBy))) {
|
|
||||||
$this->sql.= ' ORDER BY ' . (isset($arSql[6]) ? $arSql[6] : '') . ' ';
|
|
||||||
|
|
||||||
if (!empty($this->qryOrderBy)) $this->sql.= (empty($arSql[6])) ? $this->qryOrderBy : ',' . $this->qryOrderBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($arSql[7])) $this->sql.= ' LIMIT ' . $arSql[7];
|
|
||||||
elseif (!empty($this->qryLimit)) $this->sql.= ' LIMIT ' . $this->qryLimit;
|
|
||||||
|
|
||||||
if ($this->sqlNeedReset) $this->sqlReset();
|
|
||||||
return $this->sql;
|
|
||||||
}
|
|
||||||
//************************************************************************
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Сортировка дерева в представлении Nested Set
|
|
||||||
* Для дерева которое хранится в базе данных используя представление Nested Set нет возможности отсортировать элементы дерева по
|
|
||||||
* произвольному полю. Поэтому после извлечения дерева из базы данных оно преобразуется в обычное представление сортируется и обратно
|
|
||||||
*
|
|
||||||
* Пример:
|
|
||||||
* $sort = new NestedSetSort();
|
|
||||||
* $data = $sort->sortBy($data, 'name');
|
|
||||||
*/
|
|
||||||
class NestedSetSort {
|
|
||||||
private $data = array();
|
|
||||||
private $result = array();
|
|
||||||
private $sortBy = '';
|
|
||||||
|
|
||||||
public function __construct() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Преобразуем Nested Set в дерево и сортируем
|
|
||||||
private function listTree(array $tree, $offset, $level) {
|
|
||||||
$result = array();
|
|
||||||
for ($i = $offset; $i < sizeof($tree); $i++) {
|
|
||||||
$leaf = $tree[$i];
|
|
||||||
$clevel = $leaf['cat_level'];
|
|
||||||
if ($clevel == $level) {
|
|
||||||
$result [] = array($i);
|
|
||||||
} else if ($clevel > $level) {
|
|
||||||
list($subtree, $i) = $this->listTree($tree, $i, $clevel);
|
|
||||||
$i--;
|
|
||||||
$result[sizeof($result) - 1][1] = $subtree;
|
|
||||||
} else {
|
|
||||||
$this->sortList($result, $tree);
|
|
||||||
return array($result, $i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->sortList($result, $tree);
|
|
||||||
return array($result, $i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Сравнение двух элементов
|
|
||||||
private function compare($a, $b) {
|
|
||||||
$a1 = $this->data[$a[0]][$this->sortBy];
|
|
||||||
$b1 = $this->data[$b[0]][$this->sortBy];
|
|
||||||
return strcmp($a1, $b1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Сортировка списка
|
|
||||||
private function sortList(array &$list, $data) {
|
|
||||||
usort($list, array($this, 'compare'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Создает дерево в виде списка
|
|
||||||
private function reorder(array $tree) {
|
|
||||||
foreach($tree as $node) {
|
|
||||||
$this->result[] = $this->data[$node[0]];
|
|
||||||
if (isset($node[1])) {
|
|
||||||
$this->reorder($node[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sortBy0(array $data, $sortBy)
|
|
||||||
{
|
|
||||||
$this->data = $data;
|
|
||||||
$this->sortBy = $sortBy;
|
|
||||||
$order = $this->listTree($data, 0, 0);
|
|
||||||
return $order[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Сортировка по заданному полю
|
|
||||||
public function sortBy(array $data, $sortBy) {
|
|
||||||
$this->data = $data;
|
|
||||||
$this->sortBy = $sortBy;
|
|
||||||
$order = $this->listTree($data, 0, 0);
|
|
||||||
$this->reorder($order[0]);
|
|
||||||
return $this->result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
<?php
|
|
||||||
foreach (glob(dirname(__FILE__) . "/*.php") as $file) { require_once $file; }
|
|
||||||
|
|
@ -1,298 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class _View_Composite // AbstractCompositeView
|
|
||||||
{
|
|
||||||
protected $_section = array(); // Вложенные шаблоны
|
|
||||||
// Блоки
|
|
||||||
protected $_stylesheet = array(); // Массив стилей текущего шаблона
|
|
||||||
protected $_script = array(); // Массив скриптов текущего шаблона
|
|
||||||
protected $_scriptstring = array();
|
|
||||||
protected $_startup = array();
|
|
||||||
|
|
||||||
protected $_title = null; // Заголовок текущего шаблона
|
|
||||||
public $alias = array();
|
|
||||||
|
|
||||||
function __construct()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Связывет переменную с вложенным шаблоном
|
|
||||||
*
|
|
||||||
* @param string $section переменная шаблона
|
|
||||||
* @param CompositeView $view вложенный шаблон
|
|
||||||
*/
|
|
||||||
public function setView($section, /*CompositeView*/ $view)
|
|
||||||
{
|
|
||||||
$this->_section [$section] = $view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function jGrowl($message, $args)
|
|
||||||
{
|
|
||||||
$this->addScriptRaw('$.jGrowl("' . $message . '", ' . json::encode($args) . ");\n", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setGlobal($name, $args)
|
|
||||||
{
|
|
||||||
$this->addScriptRaw("var " . $name . " = " . json::encode($args) . ";\n", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет скипт к текущему шаблону
|
|
||||||
*
|
|
||||||
* @param string $name путь к скрипту
|
|
||||||
*/
|
|
||||||
public function addScript($name)
|
|
||||||
{
|
|
||||||
$this->_script [] = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет код скипта к текущему шаблону
|
|
||||||
*
|
|
||||||
* @param string $name строка javascript кода
|
|
||||||
*/
|
|
||||||
public function addScriptRaw($name, $startup = false)
|
|
||||||
{
|
|
||||||
if ($startup) {
|
|
||||||
$this->_startup [] = $name;
|
|
||||||
} else {
|
|
||||||
$this->_scriptstring [] = $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет стили к текущему шаблону
|
|
||||||
*
|
|
||||||
* @param string $name путь к стилю
|
|
||||||
*/
|
|
||||||
public function addStyleSheet($name)
|
|
||||||
{
|
|
||||||
$this->_stylesheet [] = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Рекурсивно извлекает из значение свойства обьекта
|
|
||||||
*
|
|
||||||
* @param string $list Имя свойства
|
|
||||||
* @param boolean $flatten
|
|
||||||
*/
|
|
||||||
private function doTree($list, $flatten = true) {
|
|
||||||
$result = ($flatten == true) ? $this->$list : array($this->$list);
|
|
||||||
foreach ($this->_section as $key => $value) {
|
|
||||||
if (is_object($value)) $result = array_merge($value->doTree($list, $flatten), $result);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Массив имен файлов скриптов
|
|
||||||
*
|
|
||||||
* return array
|
|
||||||
*/
|
|
||||||
public function getScripts()
|
|
||||||
{
|
|
||||||
return $this->doTree('_script');
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveAlias($alias, $list)
|
|
||||||
{
|
|
||||||
$result = array();
|
|
||||||
foreach($list as $item) {
|
|
||||||
$result [] = strtr($item, $alias);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Строка со скриптом
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getScriptRaw()
|
|
||||||
{
|
|
||||||
return implode("\n", $this->doTree('_scriptstring'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getScriptStartup()
|
|
||||||
{
|
|
||||||
return implode("\n", $this->doTree('_startup'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*abstract*/ public function set($key, $value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Массив имен файлов стилей
|
|
||||||
*
|
|
||||||
* return array
|
|
||||||
*/
|
|
||||||
public function getStyleSheet()
|
|
||||||
{
|
|
||||||
return $this->doTree('_stylesheet');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обработка всех вложенных шаблонов
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
foreach ($this->_section as $key => $value) {
|
|
||||||
$this->set($key, (is_object($value)) ? $value->execute() : $value); // ?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Установка заголовка шаблона
|
|
||||||
*
|
|
||||||
* @param string $title
|
|
||||||
*/
|
|
||||||
public function setTitle($title)
|
|
||||||
{
|
|
||||||
$this->_title = $title;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function isNotNull($title)
|
|
||||||
{
|
|
||||||
return $title !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Общая строка заголовка
|
|
||||||
*/
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return implode(" - ", array_filter($this->doTree('_title', false), array($this, 'isNotNull')));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function findGroup($groups, $file)
|
|
||||||
{
|
|
||||||
foreach($groups as $key => $group) {
|
|
||||||
if(in_array($file, $group)) {
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function groupFiles(array $list, $debug)
|
|
||||||
{
|
|
||||||
$debug = ($debug) ? 'debug=1' : '';
|
|
||||||
$path = parse_url(WWW_PATH, PHP_URL_PATH);
|
|
||||||
$list = array_reverse($list);
|
|
||||||
// Группы нужно передвавать как параметр !!!
|
|
||||||
$groups = array(
|
|
||||||
'table' => array($path . '/js/table.js', $path . '/js/listtable.js',
|
|
||||||
$path . '/js/page.js', $path . '/js/pagemenu.js'),
|
|
||||||
'base' => array($path . '/js/admin.js', $path . '/js/cookie.js'),
|
|
||||||
);
|
|
||||||
$use = array();
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
foreach ($list as $file) {
|
|
||||||
$name = $this->findGroup($groups, $file);
|
|
||||||
if($name) {
|
|
||||||
$use [$name] = 1;
|
|
||||||
} else {
|
|
||||||
$result [] = $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$list = array();
|
|
||||||
foreach ($use as $name => $value) {
|
|
||||||
$list [] = WWW_PATH . "/min/?$debug&f=" . implode(",", $groups[$name]);
|
|
||||||
}
|
|
||||||
return array_merge($list, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обработка шаблона
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
|
|
||||||
$alias = $this->doTree('alias');
|
|
||||||
|
|
||||||
// require_once 'minify.php';
|
|
||||||
// Скрипты и стили
|
|
||||||
$this->set('scripts', array_unique($this->groupFiles($this->resolveAlias($alias, $this->getScripts()), false)));
|
|
||||||
$this->set('stylesheet', array_unique($this->groupFiles($this->resolveAlias($alias, $this->getStyleSheet()), false)));
|
|
||||||
|
|
||||||
$this->set('scriptstring', $this->getScriptRaw());
|
|
||||||
$this->set('startup', $this->getScriptStartup());
|
|
||||||
$this->set('title', $this->getTitle());
|
|
||||||
//
|
|
||||||
return $this->execute(); // execute+phptal ??
|
|
||||||
}
|
|
||||||
|
|
||||||
function setAlias($alias)
|
|
||||||
{
|
|
||||||
$this->alias = $alias;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addAlias($name, $path)
|
|
||||||
{
|
|
||||||
$this->alias['${' . $name . '}'] = $path;
|
|
||||||
$this->set($name, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadImports($importFile)
|
|
||||||
{
|
|
||||||
// Подключение стилей и скриптов
|
|
||||||
if (file_exists($importFile)) {
|
|
||||||
$import = file_get_contents($importFile);
|
|
||||||
$files = explode("\n", $import);
|
|
||||||
foreach ($files as $file) {
|
|
||||||
if (strpos($file, ".js") !== false) {
|
|
||||||
$this->addScript(strtr(trim($file), $this->alias));
|
|
||||||
} else if(strpos($file, ".css") !== false) {
|
|
||||||
$this->addStyleSheet(strtr(trim($file), $this->alias));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Извлекает текст из HTML документа
|
|
||||||
*/
|
|
||||||
function stripText($document)
|
|
||||||
{
|
|
||||||
$search = array("'<script[^>]*?>.*?</script>'si" => "", // strip out javascript
|
|
||||||
"'<[\/\!]*?[^<>]*?>'si" => "", // strip out html tags
|
|
||||||
"'([\r\n])[\s]+'" => "\\1", // strip out white space
|
|
||||||
"'&(quot|#34|#034|#x22);'i" => "\"", // replace html entities
|
|
||||||
"'&(amp|#38|#038|#x26);'i" => "&", // added hexadecimal values
|
|
||||||
"'&(lt|#60|#060|#x3c);'i" => ">",
|
|
||||||
"'&(gt|#62|#062|#x3e);'i" => "<",
|
|
||||||
"'&(nbsp|#160|#xa0);'i" => " ",
|
|
||||||
"'&(iexcl|#161);'i" => chr(161),
|
|
||||||
"'&(cent|#162);'i" => chr(162),
|
|
||||||
"'&(pound|#163);'i" => chr(163),
|
|
||||||
"'&(copy|#169);'i" => chr(169),
|
|
||||||
"'&(reg|#174);'i" => chr(174),
|
|
||||||
"'&(deg|#176);'i" => chr(176));
|
|
||||||
$text = preg_replace(array_keys($search), array_values($search), $document);
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Разделение текста на массив слов
|
|
||||||
*/
|
|
||||||
function tokenize ($document)
|
|
||||||
{
|
|
||||||
$array = preg_split("/[\W]+/", $document);
|
|
||||||
return $array;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ищет один из символов с конца строки
|
|
||||||
*
|
|
||||||
* @param string $haystack
|
|
||||||
* @param array $needle Массив символов для поиска
|
|
||||||
* @param int $offset Смещение от начала строки
|
|
||||||
*
|
|
||||||
* @return int Позицию первого совпадения
|
|
||||||
*/
|
|
||||||
function indexRight ($haystack, $needle, $offset = 0)
|
|
||||||
{
|
|
||||||
if ((bool)$offset === false) $offset = 0;
|
|
||||||
while ($offset >= 0) {
|
|
||||||
if (in_array ($haystack[$offset], $needle)) {
|
|
||||||
return $offset;
|
|
||||||
}
|
|
||||||
$offset --;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ищет один из символов с начала строки
|
|
||||||
*
|
|
||||||
* @param string $haystack
|
|
||||||
* @param array $needle Массив символов для поиска
|
|
||||||
* @param int $offset Смещение от начала строки
|
|
||||||
*
|
|
||||||
* @return int Позицию первого совпадения
|
|
||||||
*/
|
|
||||||
function indexLeft ($haystack, $needle, $offset = 0)
|
|
||||||
{
|
|
||||||
if ($offset < 0) return false;
|
|
||||||
while ($offset < strlen($haystack)) {
|
|
||||||
if ((is_callable($needle) && call_user_func ($needle, $haystack[$offset]))
|
|
||||||
|| (is_array ($needle) && in_array ($haystack[$offset], $needle))) {
|
|
||||||
return $offset;
|
|
||||||
}
|
|
||||||
$offset ++;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function not_ctype_alpha ($ch)
|
|
||||||
{
|
|
||||||
return !ctype_alpha($ch);
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/search/htmlhelper.php';
|
|
||||||
require_once 'core/search/stemmer.php';
|
|
||||||
require_once 'core/path.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Индексирование файлов
|
|
||||||
*/
|
|
||||||
class Index
|
|
||||||
{
|
|
||||||
const ARRAY_FILE = 0;
|
|
||||||
const ARRAY_TEXT = 1;
|
|
||||||
|
|
||||||
public $index = array ();
|
|
||||||
public $text = array ();
|
|
||||||
protected $count = 0;
|
|
||||||
|
|
||||||
function getTitle ($content) {
|
|
||||||
$title = "'<title[^>]*?>(.*?)</title>'si";
|
|
||||||
preg_match($title, $content, $matches);
|
|
||||||
if(isset($matches[1])) {
|
|
||||||
return $matches[1];
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выбираем основу слова
|
|
||||||
function clean ($word)
|
|
||||||
{
|
|
||||||
return Stemmer::russian(strtolower($word));
|
|
||||||
}
|
|
||||||
|
|
||||||
function process ($base, $files)
|
|
||||||
{
|
|
||||||
$path = new Path($base);
|
|
||||||
// Список документов
|
|
||||||
foreach ($path->getContentRec($files) as $file) {
|
|
||||||
$content = file_get_contents ($file);
|
|
||||||
$text = stripText($content);
|
|
||||||
// $title = self::getTitle ($content);
|
|
||||||
$title = pathinfo($file, PATHINFO_BASENAME);
|
|
||||||
// echo $file, "\n";
|
|
||||||
// Список слов в документе
|
|
||||||
$list = tokenize($text);
|
|
||||||
foreach ($list as $word) {
|
|
||||||
$preword = self::clean($word);
|
|
||||||
if (isset($this->index[$preword])) {
|
|
||||||
$index = $this->index[$preword];
|
|
||||||
if ( ! in_array ($this->count, $index)) $this->index[$preword] [] = $this->count;
|
|
||||||
} else {
|
|
||||||
// Не записываем слова длинна которых меньше 2
|
|
||||||
if (strlen($preword) > 1) {
|
|
||||||
$this->index[$preword] = array ($this->count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->text [] = array ($title, $path->relPath ($file), $text);
|
|
||||||
$this->count ++;
|
|
||||||
}
|
|
||||||
ksort($this->index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Сохранение результата поиска
|
|
||||||
*/
|
|
||||||
function saveData ($file)
|
|
||||||
{
|
|
||||||
$file = fopen($file, "w");
|
|
||||||
// Количество слов и текстов
|
|
||||||
fwrite ($file, pack("SS", count($this->index), count($this->text)));
|
|
||||||
foreach ($this->index as $word => $value) {
|
|
||||||
$length = strlen($word);
|
|
||||||
array_unshift ($value, "SSa*S*", $length, count($value), $word);
|
|
||||||
fwrite($file, call_user_func_array ('pack', $value));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->text as $text) {
|
|
||||||
fwrite($file, pack("SSSa*a*a*",
|
|
||||||
strlen($text[0]), strlen($text[1]), strlen($text[2])
|
|
||||||
, $text[0], $text[1], $text[2]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Разбирвет строку запроса на токены
|
|
||||||
*/
|
|
||||||
class Lexer
|
|
||||||
{
|
|
||||||
const TOKEN_NOT = 1;
|
|
||||||
const TOKEN_OR = 2;
|
|
||||||
const TOKEN_LPAREN = 3;
|
|
||||||
const TOKEN_RPAREN = 4;
|
|
||||||
const TOKEN_AND = 5;
|
|
||||||
const TOKEN_WORD = 6;
|
|
||||||
const TOKEN_EOL = 7;
|
|
||||||
|
|
||||||
protected $src;
|
|
||||||
private $offset = 0;
|
|
||||||
public $token;
|
|
||||||
|
|
||||||
public function __construct ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSource ($src)
|
|
||||||
{
|
|
||||||
$this->src = $src;
|
|
||||||
$this->offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function skipSpace ()
|
|
||||||
{
|
|
||||||
while (!$this->isEOL() && $this->getChar() == " ") {
|
|
||||||
$this->offset++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getChar ()
|
|
||||||
{
|
|
||||||
return $this->src [$this->offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет на конец строки
|
|
||||||
*/
|
|
||||||
private function isEOL () {
|
|
||||||
return $this->offset >= strlen($this->src);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Односимвольный токен
|
|
||||||
*/
|
|
||||||
private function easyToken () {
|
|
||||||
$ch = $this->getChar ();
|
|
||||||
switch ($ch) {
|
|
||||||
case '~': $token = array(self::TOKEN_NOT, $ch); break;
|
|
||||||
case '|': $token = array(self::TOKEN_OR, $ch); break;
|
|
||||||
case '(': $token = array(self::TOKEN_LPAREN, $ch); break;
|
|
||||||
case ')': $token = array(self::TOKEN_RPAREN, $ch); break;
|
|
||||||
case '&': $token = array(self::TOKEN_AND, $ch); break;
|
|
||||||
default:
|
|
||||||
$this->offset++;
|
|
||||||
$token = $this->getToken();
|
|
||||||
}
|
|
||||||
$this->offset++;
|
|
||||||
return $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает следующий токен
|
|
||||||
*/
|
|
||||||
public function getToken ()
|
|
||||||
{
|
|
||||||
$this->skipSpace ();
|
|
||||||
if ($this->isEOL()) {
|
|
||||||
return array(self::TOKEN_EOL, "");
|
|
||||||
}
|
|
||||||
if (ctype_alpha($this->getChar())) {
|
|
||||||
$start = $this->offset;
|
|
||||||
while (!$this->isEOL() && ctype_alpha($this->getChar())) {
|
|
||||||
$this->offset ++;
|
|
||||||
}
|
|
||||||
return array(self::TOKEN_WORD, substr ($this->src, $start, $this->offset-$start));
|
|
||||||
}
|
|
||||||
return $this->easyToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function nextToken ()
|
|
||||||
{
|
|
||||||
$this->token = $this->getToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/search/lexer.php';
|
|
||||||
require_once 'core/functions.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск в индексе
|
|
||||||
*/
|
|
||||||
class Search
|
|
||||||
{
|
|
||||||
private $lexer;
|
|
||||||
private $index;
|
|
||||||
function __construct ($index)
|
|
||||||
{
|
|
||||||
$this->lexer = new Lexer();
|
|
||||||
$this->index = $index;
|
|
||||||
|
|
||||||
$this->op = array ($this, 'Op');
|
|
||||||
$this->binary = array ($this, 'binaryOp');
|
|
||||||
$this->union = array ($this, 'union');
|
|
||||||
$this->intersection = lcurry($this->op, 'array_uintersect', $this->union);
|
|
||||||
|
|
||||||
$this->notQuery = lcurry ($this->binary, Lexer::TOKEN_NOT,
|
|
||||||
lcurry($this->op, 'array_udiff', 'array_udiff'), array ($this, 'easyQuery'));
|
|
||||||
|
|
||||||
$this->orQuery = lcurry ($this->binary, Lexer::TOKEN_OR,
|
|
||||||
lcurry($this->op, $this->union, $this->union), $this->notQuery);
|
|
||||||
|
|
||||||
$this->andQuery = lcurry ($this->binary, Lexer::TOKEN_AND, $this->intersection, $this->orQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
function union ($a, $b, $callback)
|
|
||||||
{
|
|
||||||
return array_merge($a, $b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Eq ($a, $b)
|
|
||||||
{
|
|
||||||
return $a == $b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Op ($files, $words, $a, $b) {
|
|
||||||
return array (
|
|
||||||
'words' => call_user_func ($words, $a['words'], $b['words'], array ($this, 'eq')),
|
|
||||||
'files' => call_user_func ($files, $a['files'], $b['files'], array ($this, 'eq'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getQuery ($source)
|
|
||||||
{
|
|
||||||
$this->lexer->setSource ($source);
|
|
||||||
$this->lexer->nextToken();
|
|
||||||
return $this->topQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
function topQuery ()
|
|
||||||
{
|
|
||||||
$result = call_user_func ($this->andQuery);
|
|
||||||
while ($this->lexer->token[0] == Lexer::TOKEN_LPAREN) {
|
|
||||||
$result = call_user_func ($this->intersection, $result, call_user_func ($this->andQuery));
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function easyQuery ()
|
|
||||||
{
|
|
||||||
$result = null;
|
|
||||||
if ($this->lexer->token[0] == Lexer::TOKEN_LPAREN) {
|
|
||||||
$this->lexer->nextToken ();
|
|
||||||
$result = $this->topQuery ();
|
|
||||||
if ($this->lexer->token[0] == Lexer::TOKEN_RPAREN) {
|
|
||||||
$this->lexer->nextToken ();
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
} else {
|
|
||||||
$result = call_user_func ($this->index, $this->lexer->token[1]);
|
|
||||||
$this->lexer->nextToken ();
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $type Тип лексемы
|
|
||||||
* @param function $op Функция при совпадении типа лексемы при запросе
|
|
||||||
* @param function $next Следующий обработчик запроса
|
|
||||||
*/
|
|
||||||
function binaryOp ($type, $op, $next)
|
|
||||||
{
|
|
||||||
$result = call_user_func($next);
|
|
||||||
while ($this->lexer->token[0] == $type) {
|
|
||||||
$this->lexer->nextToken();
|
|
||||||
$result = call_user_func($op, $result, call_user_func ($next));
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'core/search/search.php';
|
|
||||||
require_once 'core/search/htmlhelper.php';
|
|
||||||
require_once 'core/search/stemmer.php';
|
|
||||||
|
|
||||||
class Searcher {
|
|
||||||
/* protected */ public $index;
|
|
||||||
protected $text;
|
|
||||||
protected $search;
|
|
||||||
public function __construct ()
|
|
||||||
{
|
|
||||||
// Может передавать обьект метод по умлочанию getWordStat??
|
|
||||||
$this->search = new Search (array ($this, 'getWord'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Читает содержимое индексного файла
|
|
||||||
*
|
|
||||||
* @param string $file Имя файла
|
|
||||||
*/
|
|
||||||
function setSource ($fileName)
|
|
||||||
{
|
|
||||||
$file = fopen($fileName, "r");
|
|
||||||
$words = fread($file, 4);
|
|
||||||
$all = unpack("Swords/Stexts", $words);
|
|
||||||
for ($i = 0; $i < $all['words']; $i++) {
|
|
||||||
$pos = fread($file, 4);
|
|
||||||
$size = unpack("Sword/Sindex", $pos);
|
|
||||||
|
|
||||||
$word = fread($file, $size['word']);
|
|
||||||
$index = unpack("S*", fread($file, $size['index']*2));
|
|
||||||
$this->index[$word] = $index;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($i = 0; $i < $all['texts']; $i++) {
|
|
||||||
$pos = fread($file, 6);
|
|
||||||
$size = unpack("Stitle/Surl/Stext", $pos);
|
|
||||||
//
|
|
||||||
$title = fread($file, $size['title']);
|
|
||||||
$url = fread($file, $size['url']);
|
|
||||||
$text = fread($file, $size['text']);
|
|
||||||
$this->text [] = array ($title, $url, $text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// По слову возвращаем список файлов и слово
|
|
||||||
public function getWord ($word)
|
|
||||||
{
|
|
||||||
$preword = Stemmer::russian($word); // Index?? -> clean
|
|
||||||
if (isset($this->index[$preword])) { // Search??
|
|
||||||
return array ('files' => $this->index[$preword], 'words' => array ($preword));
|
|
||||||
}
|
|
||||||
return array ('files' => array (), 'words' => array ());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Список документов в которых встечается слово
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function getResult (&$query)
|
|
||||||
{
|
|
||||||
$result = array ();
|
|
||||||
$word = $query['words'];
|
|
||||||
$list = $query['files'];
|
|
||||||
//
|
|
||||||
foreach ($list as $n) {
|
|
||||||
$result [] = array (
|
|
||||||
'title' => $this->text[$n][0],
|
|
||||||
'file' => $this->text[$n][1],
|
|
||||||
'text' => self::getSlice ($word[0], $this->text[$n][2]));
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Часть документа в котором встречается слово
|
|
||||||
*
|
|
||||||
* @param $word Слово
|
|
||||||
* @param $text Текст содержащий слово
|
|
||||||
*/
|
|
||||||
function getSlice ($word, $text)
|
|
||||||
{
|
|
||||||
$pos = stripos($text, $word);
|
|
||||||
$offset = max(max ($pos-100, indexRight($text, array ("."), $pos) + 1), 0);
|
|
||||||
$real = substr($text, $pos, strlen($word)) ;
|
|
||||||
return substr($text, $offset, $pos - $offset)
|
|
||||||
. "<span style='color: red'>" . $real . "</span>" . substr ($text, $pos + strlen($word), 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск по запросу
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function search ($query)
|
|
||||||
{
|
|
||||||
$result = $this->search->getQuery($query);
|
|
||||||
return $this->getResult($result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
<?php
|
|
||||||
/*
|
|
||||||
* PHP5 implementation of Martin Porter's stemming algorithm for Russian language.
|
|
||||||
* Written on a cold winter evening close to the end of 2005 by Dennis Kreminsky (etranger at etranger dot ru)
|
|
||||||
* Use the code freely, but don't hold me responsible if it breaks whatever it might break.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
define ('CHAR_LENGTH', '1'); // all Russian characters take 2 bytes in UTF-8, so instead of using (not supported by default) mb_*
|
|
||||||
// string functions, we use the standard ones with a dirty char-length trick.
|
|
||||||
// Should you want to use WIN-1251 (or any other charset), convert this source file to that encoding
|
|
||||||
// and then change CHAR_LENGTH to the proper value, which is likely to be '1' then.
|
|
||||||
//
|
|
||||||
class Stemmer {
|
|
||||||
|
|
||||||
static public function russian($word)
|
|
||||||
{
|
|
||||||
$a = self::rv($word);
|
|
||||||
$start = $a[0];
|
|
||||||
$rv = $a[1];
|
|
||||||
$rv = self::step1($rv);
|
|
||||||
$rv = self::step2($rv);
|
|
||||||
$rv = self::step3($rv);
|
|
||||||
$rv = self::step4($rv);
|
|
||||||
return $start.$rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private function rv($word)
|
|
||||||
{
|
|
||||||
$vowels = array('а','е','и','о','у','ы','э','ю','я');
|
|
||||||
$flag = 0;
|
|
||||||
$rv = '';
|
|
||||||
$start = '';
|
|
||||||
for ($i=0; $i<strlen($word); $i+=CHAR_LENGTH) {
|
|
||||||
if ($flag==1)
|
|
||||||
$rv .= substr($word, $i, CHAR_LENGTH);
|
|
||||||
else
|
|
||||||
$start .= substr($word, $i, CHAR_LENGTH);
|
|
||||||
if (array_search(substr($word,$i,CHAR_LENGTH), $vowels) !== false)
|
|
||||||
$flag=1;
|
|
||||||
}
|
|
||||||
return array($start,$rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function substitute ($word, &$suffix_list)
|
|
||||||
{
|
|
||||||
foreach ($suffix_list as $suffix) {
|
|
||||||
if (self::has_suffix($word, $suffix)) {
|
|
||||||
$word = self::cut_suffix($word, $suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $word;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function has_suffix ($word, $suffix)
|
|
||||||
{
|
|
||||||
return substr($word, -(strlen($suffix))) == $suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function has_aya ($word, $suffix)
|
|
||||||
{
|
|
||||||
return (substr($word,-strlen($suffix)-CHAR_LENGTH,CHAR_LENGTH)=='а' || substr($word,-strlen($suffix)-CHAR_LENGTH,CHAR_LENGTH)=='я');
|
|
||||||
}
|
|
||||||
|
|
||||||
static function cut_suffix ($word, $suffix)
|
|
||||||
{
|
|
||||||
return substr($word, 0, strlen($word) - strlen($suffix));
|
|
||||||
}
|
|
||||||
|
|
||||||
static private function step1($word)
|
|
||||||
{
|
|
||||||
$perfective1 = array('в', 'вши', 'вшись');
|
|
||||||
foreach ($perfective1 as $suffix) {
|
|
||||||
if (self::has_suffix($word, $suffix) && self::has_aya ($word, $suffix)) {
|
|
||||||
return self::cut_suffix($word, $suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$perfective2 = array('ив','ивши','ившись','ывши','ывшись');
|
|
||||||
foreach ($perfective2 as $suffix) {
|
|
||||||
if (self::has_suffix($word, $suffix)) {
|
|
||||||
return self::cut_suffix($word, $suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflexive = array('ся', 'сь');
|
|
||||||
$word = self::substitute($word, $reflexive);
|
|
||||||
|
|
||||||
$adjective = array('ее','ие','ые','ое','ими','ыми','ей','ий','ый','ой','ем','им','ым','ом','его','ого','ему','ому','их','ых','ую','юю','ая','яя','ою','ею');
|
|
||||||
$participle2 = array('ем','нн','вш','ющ','щ');
|
|
||||||
$participle1 = array('ивш','ывш','ующ');
|
|
||||||
foreach ($adjective as $suffix) {
|
|
||||||
if (self::has_suffix($word, $suffix)) {
|
|
||||||
$word = self::cut_suffix($word, $suffix);
|
|
||||||
|
|
||||||
foreach ($participle1 as $suffix)
|
|
||||||
if (self::has_suffix($word, $suffix) && self::has_aya ($word, $suffix))
|
|
||||||
$word = self::cut_suffix($word, $suffix);
|
|
||||||
|
|
||||||
return self::substitute($word, $participle2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$verb1 = array('ла','на','ете','йте','ли','й','л','ем','н','ло','но','ет','ют','ны','ть','ешь','нно');
|
|
||||||
foreach ($verb1 as $suffix)
|
|
||||||
if (self::has_suffix($word, $suffix) && self::has_aya ($word, $suffix))
|
|
||||||
return self::cut_suffix($word, $suffix);
|
|
||||||
|
|
||||||
$verb2 = array('ила','ыла','ена','ейте','уйте','ите','или','ыли','ей','уй','ил','ыл','им','ым','ен','ило','ыло','ено','ят','ует','уют','ит','ыт','ены','ить','ыть','ишь','ую','ю');
|
|
||||||
foreach ($verb2 as $suffix)
|
|
||||||
if (self::has_suffix($word, $suffix))
|
|
||||||
return self::cut_suffix($word, $suffix);
|
|
||||||
|
|
||||||
$noun = array('а','ев','ов','ие','ье','е','иями','ями','ами','еи','ии','и','ией','ей','ой','ий','й','иям','ям','ием','ем','ам','ом','о','у','ах','иях','ях','ы','ь','ию','ью','ю','ия','ья','я');
|
|
||||||
foreach ($noun as $suffix) {
|
|
||||||
if (self::has_suffix($word, $suffix))
|
|
||||||
return self::cut_suffix($word, $suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $word;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private function step2($word)
|
|
||||||
{
|
|
||||||
if (substr($word,-CHAR_LENGTH,CHAR_LENGTH) == 'и')
|
|
||||||
$word = substr($word, 0, strlen($word)-CHAR_LENGTH);
|
|
||||||
return $word;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private function step3($word)
|
|
||||||
{
|
|
||||||
$vowels = array('а','е','и','о','у','ы','э','ю','я');
|
|
||||||
$flag = 0;
|
|
||||||
$r1 = '';
|
|
||||||
$r2 = '';
|
|
||||||
for ($i=0; $i<strlen($word); $i+=CHAR_LENGTH)
|
|
||||||
{
|
|
||||||
if ($flag==2)
|
|
||||||
$r1.=substr($word, $i, CHAR_LENGTH);
|
|
||||||
if (array_search(substr($word,$i,CHAR_LENGTH), $vowels) !== false)
|
|
||||||
$flag=1;
|
|
||||||
if ($flag=1 && array_search(substr($word,$i,CHAR_LENGTH), $vowels) === false)
|
|
||||||
$flag=2;
|
|
||||||
}
|
|
||||||
$flag=0;
|
|
||||||
for ($i=0; $i<strlen($r1); $i+=CHAR_LENGTH)
|
|
||||||
{
|
|
||||||
if ($flag==2)
|
|
||||||
$r2.=substr($r1, $i, CHAR_LENGTH);
|
|
||||||
if (array_search(substr($r1,$i,CHAR_LENGTH), $vowels) !== false)
|
|
||||||
$flag=1;
|
|
||||||
if ($flag=1 && array_search(substr($r1,$i,CHAR_LENGTH), $vowels) === false)
|
|
||||||
$flag=2;
|
|
||||||
}
|
|
||||||
$derivational=array('ост', 'ость');
|
|
||||||
foreach ($derivational as $suffix)
|
|
||||||
if (substr($r2,-(strlen($suffix))) == $suffix)
|
|
||||||
$word=substr($word, 0, strlen($r2)-strlen($suffix));
|
|
||||||
return $word;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private function step4($word)
|
|
||||||
{
|
|
||||||
if (substr($word,-CHAR_LENGTH*2)=='нн')
|
|
||||||
$word=substr($word, 0, strlen($word)-CHAR_LENGTH);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$superlative=array('ейш', 'ейше');
|
|
||||||
foreach ($superlative as $suffix)
|
|
||||||
if (substr($word,-(strlen($suffix))) == $suffix)
|
|
||||||
$word = substr($word, 0, strlen($word) - strlen($suffix));
|
|
||||||
if (substr($word,-CHAR_LENGTH*2) == 'нн')
|
|
||||||
$word = substr($word, 0, strlen($word) - CHAR_LENGTH);
|
|
||||||
}
|
|
||||||
// should there be a guard flag? can't think of a russian word that ends with ейшь or ннь anyways, though the algorithm states this is an "otherwise" case
|
|
||||||
if (substr($word,-CHAR_LENGTH,CHAR_LENGTH) == 'ь')
|
|
||||||
$word=substr($word, 0, strlen($word)-CHAR_LENGTH);
|
|
||||||
return $word;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -14,7 +14,7 @@ class Adapter
|
||||||
public function get($name)
|
public function get($name)
|
||||||
{
|
{
|
||||||
if (is_array ($this->adaptee)) {
|
if (is_array ($this->adaptee)) {
|
||||||
return $this->adaptee [$name];
|
return $this->adaptee[$name];
|
||||||
} else {
|
} else {
|
||||||
return $this->adaptee->$name;
|
return $this->adaptee->$name;
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
/**
|
/**
|
||||||
* Коллекция
|
* Коллекция
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// HttpConncectionRequest
|
class Connection_HttpRequest
|
||||||
class HttpConnection
|
|
||||||
{
|
{
|
||||||
const POST = "POST";
|
const POST = "POST";
|
||||||
const GET = "GET";
|
const GET = "GET";
|
||||||
|
|
@ -9,18 +8,23 @@ class HttpConnection
|
||||||
private $param = array(); // Параметры запроса
|
private $param = array(); // Параметры запроса
|
||||||
public $data = null; // Содержание
|
public $data = null; // Содержание
|
||||||
public $url; // Адресс
|
public $url; // Адресс
|
||||||
public $method = self::GET; // Метод
|
public $method; // Метод
|
||||||
public $port = 80;
|
public $port = 80;
|
||||||
public $host = "";
|
public $host = "";
|
||||||
public $proxy_host = false;
|
public $proxy_host = null;
|
||||||
public $proxy_port = false;
|
public $proxy_port = null;
|
||||||
|
public $http_version = 'HTTP/1.1';
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
$this->method = self::GET;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает заголовок соединения
|
* Возвращает заголовок соединения
|
||||||
*/
|
*/
|
||||||
public function getHeader()
|
public function getHeader()
|
||||||
{
|
{
|
||||||
$result = $this->method . " " . $this->url . " HTTP/1.1\r\n";
|
$result = $this->method . " " . $this->url . " " . $this->http_version . "\r\n";
|
||||||
$result .= "Host: ". $this->host ."\r\n";
|
$result .= "Host: ". $this->host ."\r\n";
|
||||||
foreach ($this->param as $key => $value) {
|
foreach ($this->param as $key => $value) {
|
||||||
$result .= $key . ": " . $value . "\r\n";
|
$result .= $key . ": " . $value . "\r\n";
|
||||||
|
|
@ -75,10 +79,10 @@ class HttpConnection
|
||||||
{
|
{
|
||||||
$host = ($this->proxy_host) ? $this->proxy_host : $this->host;
|
$host = ($this->proxy_host) ? $this->proxy_host : $this->host;
|
||||||
$port = ($this->proxy_port) ? $this->proxy_port : $this->port;
|
$port = ($this->proxy_port) ? $this->proxy_port : $this->port;
|
||||||
|
$errno = 0;
|
||||||
|
$errstr = '';
|
||||||
$socket = fsockopen($host, $port, $errno, $errstr, 30);
|
$socket = fsockopen($host, $port, $errno, $errstr, 30);
|
||||||
if (! $socket) {
|
if (is_resource($socket)) {
|
||||||
return null; // Exception
|
|
||||||
} else {
|
|
||||||
$header = $this->getHeader();
|
$header = $this->getHeader();
|
||||||
fwrite($socket, $header);
|
fwrite($socket, $header);
|
||||||
|
|
||||||
|
|
@ -91,5 +95,17 @@ class HttpConnection
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function getJSON($url, $data) {
|
||||||
|
$c = new Connection_HttpRequest();
|
||||||
|
$c->http_version = "HTTP/1.0";
|
||||||
|
|
||||||
|
$query = http_build_query($data);
|
||||||
|
$c->setUrl($q = $url . '?' . $query);
|
||||||
|
$page = $c->getPage();
|
||||||
|
|
||||||
|
$response = new Connection_HttpResponse($page);
|
||||||
|
return json_decode((string) preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $response->getData()), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3,11 +3,14 @@
|
||||||
/**
|
/**
|
||||||
* Обрабатывает HTTP ответ
|
* Обрабатывает HTTP ответ
|
||||||
*/
|
*/
|
||||||
class HttpConnectionResponse
|
class Connection_HttpResponse
|
||||||
{
|
{
|
||||||
private $offset;
|
private $offset;
|
||||||
private $param = array ();
|
private $param = array ();
|
||||||
private $code;
|
private $code;
|
||||||
|
public $response;
|
||||||
|
public $version;
|
||||||
|
public $data;
|
||||||
|
|
||||||
public function __construct($response)
|
public function __construct($response)
|
||||||
{
|
{
|
||||||
414
src/Controller/Action.php
Normal file
414
src/Controller/Action.php
Normal file
|
|
@ -0,0 +1,414 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../functions.php';
|
||||||
|
|
||||||
|
|
||||||
|
function forceUrl($name)
|
||||||
|
{
|
||||||
|
if (is_callable($name)) {
|
||||||
|
return call_user_func($name);
|
||||||
|
}
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Контроллер страниц
|
||||||
|
*/
|
||||||
|
class Controller_Action
|
||||||
|
{
|
||||||
|
|
||||||
|
const TEMPLATE_EXTENSION = ".html"; // Расширение для шаблонов
|
||||||
|
const ACTION_PREFIX = "action"; // Префикс для функций действий
|
||||||
|
|
||||||
|
public $jsPath; // Глобальный путь к скриптам
|
||||||
|
public $themePath; // Глобальный путь к текущей теме
|
||||||
|
|
||||||
|
// Параметры устанавливаются при создании контроллера
|
||||||
|
public $name = ''; // Имя модуля
|
||||||
|
public $viewPath = null; // Путь к шаблонам контроллера
|
||||||
|
public $viewPathPrefix = null; // Путь к шаблонам контроллера
|
||||||
|
|
||||||
|
public $moduleTitle = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Соединение с базой данных
|
||||||
|
*/
|
||||||
|
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 function __construct () {
|
||||||
|
$this->path = new Widgets_PathMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addSuggest(View_View $view, $name)
|
||||||
|
{
|
||||||
|
$suggest = array();
|
||||||
|
$file = Path::join($this->viewPath, 'help', $name . '.suggest');
|
||||||
|
if (file_exists($file)) {
|
||||||
|
include($file);
|
||||||
|
$view->suggestions = $suggest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findIcon($icon, $size)
|
||||||
|
{
|
||||||
|
return Path::join($this->iconPath, $size . 'x' . $size, $icon . '.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создает представление
|
||||||
|
* @param $name String
|
||||||
|
* @param $viewClass String
|
||||||
|
* @return View_Composite
|
||||||
|
*/
|
||||||
|
public function getView($name, $viewClass = 'View_Composite')
|
||||||
|
{
|
||||||
|
$file = $name . self::TEMPLATE_EXTENSION;
|
||||||
|
|
||||||
|
$list = array(
|
||||||
|
Path::join($this->viewPath, TEMPLATES, $this->viewPathPrefix) => Path::join(WWW_PATH, "modules", $this->name, TEMPLATES, $this->viewPathPrefix),
|
||||||
|
Path::join(CMS_PATH, "templates") => Path::join(WWW_PATH, "templates")
|
||||||
|
);
|
||||||
|
|
||||||
|
// Поиск файла для шаблона
|
||||||
|
foreach($list as $ospath => $path) {
|
||||||
|
$template = Path::join($ospath, $file);
|
||||||
|
if(file_exists($template)) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.View_Composite.*/$tpl = new $viewClass($template);
|
||||||
|
|
||||||
|
$tpl->set('icons', $this->iconPath); // Путь к файлам текущей темы
|
||||||
|
$tpl->set('media', $this->themePath); // Путь к файлам текущей темы
|
||||||
|
$tpl->set('assets', Path::join(WWW_PATH, "assets", "css"));
|
||||||
|
$tpl->set('script', $this->jsPath); // Путь к файлам скриптов
|
||||||
|
$tpl->set('template', $path); // Путь к файлам текущего шаблона
|
||||||
|
|
||||||
|
$tpl->setAlias(array(
|
||||||
|
'icons' => $this->iconPath,
|
||||||
|
'script' => $this->jsPath,
|
||||||
|
// Для media и template поиск происходит как для файлов шаблонов
|
||||||
|
'media' => $list,
|
||||||
|
'template' => $list
|
||||||
|
));
|
||||||
|
|
||||||
|
$tpl->loadImports(Path::skipExtension($template) . ".import");
|
||||||
|
|
||||||
|
$this->addSuggest($tpl, $name);
|
||||||
|
return $tpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModel($name)
|
||||||
|
{
|
||||||
|
if (!$this->factory) {
|
||||||
|
$this->factory = new Model_Factory($this->db, $this->_registry);
|
||||||
|
}
|
||||||
|
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)) {
|
||||||
|
$action = "actionIndex";
|
||||||
|
}
|
||||||
|
$view = $this->forward($action, $request);
|
||||||
|
if ($view instanceof View_View) {
|
||||||
|
$view->active_module = get_class($this);
|
||||||
|
$view->module_action = $action;
|
||||||
|
}
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(HttpRequest $request)
|
||||||
|
{
|
||||||
|
$result = $this->execute1($request);
|
||||||
|
if (!empty($result)) {
|
||||||
|
$this->view = $result;
|
||||||
|
}
|
||||||
|
$text = $this->render();
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function forward($action, HttpRequest $args) {
|
||||||
|
$value = call_user_func(array($this, $action), $args);
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Страница по умолчанию
|
||||||
|
*/
|
||||||
|
public function actionIndex(HttpRequest $request) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postUrl($name, $param)
|
||||||
|
{
|
||||||
|
$uri = array_merge(array('module' =>
|
||||||
|
strtr($this->modulePrefix . strtolower(get_class($this)), array('module_' => '')), "action" => $name),
|
||||||
|
$this->param, $param);
|
||||||
|
|
||||||
|
return "?" . http_build_query($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация ссылки c учетом прав пользователя на ссылки
|
||||||
|
* @param string $name Действие
|
||||||
|
* @param array $param Дополнительные параметры
|
||||||
|
* 'mode' означает что элемент до отправки обрабатывается javascript
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function nUrl($name, array $param = array())
|
||||||
|
{
|
||||||
|
/*.Filter_ActionAccess.*/$access = $this->access;
|
||||||
|
if ($access != null || $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
|
||||||
|
* @param $name
|
||||||
|
* @param array $param
|
||||||
|
* @return array|null
|
||||||
|
*
|
||||||
|
* @example ?action=$name&mode=ajax
|
||||||
|
* {$param[i].key = $param[i].value}
|
||||||
|
*/
|
||||||
|
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, $prefix = '')
|
||||||
|
{
|
||||||
|
if (file_exists($path)) {
|
||||||
|
require_once ($path);
|
||||||
|
$class = $prefix . pathinfo($path, PATHINFO_FILENAME);
|
||||||
|
return new $class($setup);
|
||||||
|
}
|
||||||
|
throw new Exception("NO CLASS $path");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadSettings($path)
|
||||||
|
{
|
||||||
|
$result = new Settings($path);
|
||||||
|
$result->read();
|
||||||
|
return $result->export();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для Widgets
|
||||||
|
public $view = null;
|
||||||
|
public $childNodes = array();
|
||||||
|
public $ctrlValues = 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 setValue(/*Widget*/ $name, $value)
|
||||||
|
{
|
||||||
|
$this->ctrlValues[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление дочернего отображения к текущему отображению
|
||||||
|
*/
|
||||||
|
public function addView(/*CompositeView*/ $section, $node)
|
||||||
|
{
|
||||||
|
$this->childViews[$section] = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация содержания
|
||||||
|
* Путаница c execute и render
|
||||||
|
*/
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
if ($this->view instanceof View_View) {
|
||||||
|
$this->view->assignValues($this->ctrlValues);
|
||||||
|
|
||||||
|
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(HttpRequest $request)
|
||||||
|
{
|
||||||
|
$pageId = time();
|
||||||
|
$request->session()->set('page', $pageId);
|
||||||
|
return $pageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkPageId(HttpRequest $request, $page)
|
||||||
|
{
|
||||||
|
if ($request->get('__forced__')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$_page = $request->session()->get('page');
|
||||||
|
$result = ($_page && $_page == $page);
|
||||||
|
$request->session()->clean('page');
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getActionPath()
|
||||||
|
{
|
||||||
|
return new Controller_State('index');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Тоже убрать в метод Controller_Model
|
||||||
|
function getActionPath(HttpRequest $request, $action = null)
|
||||||
|
{
|
||||||
|
$this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFilePathToPath($filePath, $type)
|
||||||
|
{
|
||||||
|
$pathToItem = $this->directoryPath($filePath, $type, 'default');
|
||||||
|
$this->path->addMenuItems($pathToItem['path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function directoryPath($path, $type, $action)
|
||||||
|
{
|
||||||
|
$path = empty($path) ? '/' : $path;
|
||||||
|
|
||||||
|
$base = new Path($path);
|
||||||
|
$parts = $base->getParts();
|
||||||
|
|
||||||
|
$_path = '/' . implode('/', $parts);
|
||||||
|
|
||||||
|
$rs = new Model_Resources($this->db);
|
||||||
|
$section_path = $rs->getSectionByPath($_path, $type);
|
||||||
|
|
||||||
|
$pathMenu = new Widgets_PathMenu();
|
||||||
|
$pathMenu->addTitle('title');
|
||||||
|
$modules = ['image' => 'images','page' => 'pages','document' => 'documents','media' => 'videos'];
|
||||||
|
|
||||||
|
while ($section_path->id_parent) {
|
||||||
|
$_path = '/' . implode('/', $parts);
|
||||||
|
$pathMenu->addMenuItem(
|
||||||
|
forceUrl($this->nUrl('', array('module'=>$modules[$type],'action' => $action, 'mode' => 'ajax', 'path' => $_path))),
|
||||||
|
$section_path->title
|
||||||
|
);
|
||||||
|
$section_path = $rs->getSectionById($section_path->id_parent);
|
||||||
|
array_pop($parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pathMenu->addMenuItem(
|
||||||
|
forceUrl($this->nUrl('', array('module'=>$modules[$type],'action' => $action, 'mode' => 'ajax', 'path' => '/'))),
|
||||||
|
$this->moduleTitle
|
||||||
|
);
|
||||||
|
return $pathMenu->getItemsReverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
325
src/Controller/Component.php
Normal file
325
src/Controller/Component.php
Normal file
|
|
@ -0,0 +1,325 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function replaceContent($match) {
|
||||||
|
$result = phptal_component(htmlspecialchars_decode($match[3]));
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyComponents($text) {
|
||||||
|
return preg_replace_callback('/<(\w+)(\s+[a-zA-Z\-]+=\"[^\"]*\")*\s+tal:replace="structure\s+component:([^\"]*)"[^>]*>/u', 'replaceContent', $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ComponentRequest {
|
||||||
|
public $component_id;
|
||||||
|
public $r;
|
||||||
|
|
||||||
|
function __construct($c, HttpRequest $r) {
|
||||||
|
$this->component_id = $c;
|
||||||
|
$this->r = $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get($key, $default = null) {
|
||||||
|
if ($key == 'active_page') {
|
||||||
|
return $this->r->get($key);
|
||||||
|
}
|
||||||
|
if ($arr = $this->r->get($key)) {
|
||||||
|
if (is_array($arr)) {
|
||||||
|
return Arr::get($arr, $this->component_id, $default);
|
||||||
|
} else {
|
||||||
|
return $arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAction() {
|
||||||
|
return $this->r->getAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс компонента
|
||||||
|
*/
|
||||||
|
class Controller_Component
|
||||||
|
{
|
||||||
|
public $viewPath = array();
|
||||||
|
public $webPath = array();
|
||||||
|
|
||||||
|
public $template = null;
|
||||||
|
public $templatePath;
|
||||||
|
|
||||||
|
public $component_id;
|
||||||
|
public $COMPONENTS_WEB;
|
||||||
|
|
||||||
|
public /*.Settings.*/$registry;
|
||||||
|
public /*.Database.*/$db;
|
||||||
|
public /*.Collection.*/$parameter;
|
||||||
|
|
||||||
|
public $module;
|
||||||
|
public $item_module;
|
||||||
|
|
||||||
|
function before() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function get($request, $key, $default) {
|
||||||
|
}
|
||||||
|
|
||||||
|
function execute(HttpRequest $request, $has_id = true) {
|
||||||
|
$crequest = new ComponentRequest($this->component_id, $request);
|
||||||
|
$action = 'action' . ucfirst($request->get('action', 'index'));
|
||||||
|
|
||||||
|
$this->before();
|
||||||
|
if (method_exists($this, $action)) {
|
||||||
|
return call_user_func(array($this, $action), $crequest);
|
||||||
|
} else {
|
||||||
|
return $this->actionIndex($crequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getView($name)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
/*.Settings.*/$registry = $this->registry;
|
||||||
|
$template = ($this->template) ? $this->template : $registry->readKey(array('system', 'template'));
|
||||||
|
|
||||||
|
$selected = null;
|
||||||
|
foreach ($this->viewPath as $index => $viewPath) {
|
||||||
|
// Загружать шаблон по умолчанию если не найден текущий
|
||||||
|
if(is_dir(Path::join($this->viewPath[$index], 'templates', $template))) {
|
||||||
|
$tpl = new PHPTAL(Path::join($this->viewPath[$index], 'templates', $template, $name));
|
||||||
|
$tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION);
|
||||||
|
$selected = $index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($selected === null) {
|
||||||
|
$tpl = new PHPTAL(Path::join($this->viewPath[0], 'templates', 'modern', $name));
|
||||||
|
$tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION);
|
||||||
|
$template = 'modern';
|
||||||
|
$selected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tpl->stripComments(true);
|
||||||
|
$tpl->addPreFilter(new PHPTAL_PreFilter_Normalize());
|
||||||
|
|
||||||
|
$tpl->set('common', Path::join(WWW_PATH, '../', 'common'));
|
||||||
|
$tpl->set('script', Path::join(WWW_PATH, 'js'));
|
||||||
|
$tpl->set('media', Path::join(TEMPLATE_WEB, $template));
|
||||||
|
$tpl->set('site_template', SITE_WWW_PATH . '/templates' . $registry->readKey(array('system', 'template')));
|
||||||
|
$tpl->set('base', SITE_WWW_PATH);
|
||||||
|
|
||||||
|
$tpl->set('component_base', $this->webPath[$selected]);
|
||||||
|
$tpl->set('component', Path::join($this->webPath[$selected], 'templates', $template));
|
||||||
|
$tpl->set('component_id', $this->component_id);
|
||||||
|
|
||||||
|
return $tpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplatePath($name) {
|
||||||
|
return Path::join($this->viewPath[0], 'templates', 'modern', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplateWebPath()
|
||||||
|
{
|
||||||
|
return Path::join($this->webPath[0], 'templates', 'modern');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $name Имя модели
|
||||||
|
*/
|
||||||
|
private function getModelPath($name)
|
||||||
|
{
|
||||||
|
return Path::join (CMS_PATH, "model", $name . ".php");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создает модель
|
||||||
|
* @param string $name
|
||||||
|
* @return model
|
||||||
|
*/
|
||||||
|
public function getModel($name)
|
||||||
|
{
|
||||||
|
require_once ($this->getModelPath ($name));
|
||||||
|
$modelName = $name . "Mapper";
|
||||||
|
$model = new $modelName ();
|
||||||
|
$model->db = $this->db;
|
||||||
|
return $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function options($key, $val, /*.Database_PDOStatement.*/$res) {
|
||||||
|
$result = array();
|
||||||
|
while($res->next()) {
|
||||||
|
$result[] = array('value' => $res->getString($key), 'name' => $res->getString($val));
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function optionsPair($list, $selected = false) {
|
||||||
|
$result = array();
|
||||||
|
foreach ($list as $key => $value) {
|
||||||
|
$result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInfo() {
|
||||||
|
$filename = Path::join($this->viewPath[0], 'install.json');
|
||||||
|
if (file_exists($filename)) {
|
||||||
|
$settings = json_decode(file_get_contents($filename), true);
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация интерфейса для выбора галлереи фотографии
|
||||||
|
*/
|
||||||
|
public function setParameters(/*.View_Composite.*/$view)
|
||||||
|
{
|
||||||
|
$form = new Form_Form();
|
||||||
|
$options = new OptionFactory($this->db);
|
||||||
|
|
||||||
|
$settings = $this->getInfo();
|
||||||
|
$form->addFieldList($settings['parameter'], $options);
|
||||||
|
|
||||||
|
$view->form = $form;
|
||||||
|
$view->component = $settings['component'];
|
||||||
|
$view->component_title = $settings['title'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static function loadComponent($expression, Database $db, Settings $registry)
|
||||||
|
{
|
||||||
|
|
||||||
|
$expression = htmlspecialchars_decode($expression);
|
||||||
|
$offset = strpos($expression, '?');
|
||||||
|
$url = parse_url($expression);
|
||||||
|
|
||||||
|
$arguments = array();
|
||||||
|
if ($offset === false) {
|
||||||
|
$path = $expression;
|
||||||
|
} else if (is_int($offset)) {
|
||||||
|
$path = substr($expression, 0, $offset);
|
||||||
|
$query = substr($expression, $offset + 1);
|
||||||
|
parse_str($query, $arguments);
|
||||||
|
}
|
||||||
|
$name = $path;
|
||||||
|
|
||||||
|
$path = Path::join (BASE_PATH, 'components', $name, $name . '.php');
|
||||||
|
$className = 'Component_' . $name;
|
||||||
|
|
||||||
|
if (file_exists($path)) {
|
||||||
|
require_once ($path);
|
||||||
|
|
||||||
|
$component = new $className();
|
||||||
|
$component->db = $db;
|
||||||
|
$component->registry = $registry;
|
||||||
|
|
||||||
|
$component->viewPath = array(BASE_PATH . '/components/' . $name . '/');
|
||||||
|
$component->webPath = array(SITE_WWW_PATH . '/components/' . $name);
|
||||||
|
|
||||||
|
$component->COMPONENTS_WEB = SITE_WWW_PATH . '/components/';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$path = Path::join (COMPONENTS, $name, $name . '.php');
|
||||||
|
require_once ($path);
|
||||||
|
$component = new $className();
|
||||||
|
$component->db = $db;
|
||||||
|
$component->registry = $registry;
|
||||||
|
|
||||||
|
$component->viewPath = array(COMPONENTS . '/' . $name . '/', BASE_PATH . '/components/' . $name . '/');
|
||||||
|
if (defined('COMPONENTS_WEB')) {
|
||||||
|
$component->webPath = array(COMPONENTS_WEB . '/' . $name, SITE_WWW_PATH . '/components/' . $name);
|
||||||
|
$component->COMPONENTS_WEB = COMPONENTS_WEB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $db->prepareStatement("SELECT * FROM component WHERE code = ?");
|
||||||
|
$stmt->setString(1, $expression);
|
||||||
|
$cid = $stmt->executeQuery();
|
||||||
|
if ($cid->next()) {
|
||||||
|
$component->component_id = $cid->getInt('id_component');
|
||||||
|
} else {
|
||||||
|
$last = $db->getIdGenerator();
|
||||||
|
if ($last->isBeforeInsert()) {
|
||||||
|
$result = $last->getId('component_id_component_seq');
|
||||||
|
|
||||||
|
$stmt = $db->prepareStatement("INSERT INTO component (id_component, code) VALUES ($result, ?)");
|
||||||
|
$stmt->setString(1, $expression);
|
||||||
|
$stmt->executeQuery();
|
||||||
|
}
|
||||||
|
if ($last->isAfterInsert()) {
|
||||||
|
$stmt = $db->prepareStatement("INSERT INTO component (code) VALUES (?)");
|
||||||
|
$stmt->setString(1, $expression);
|
||||||
|
$stmt->executeQuery();
|
||||||
|
|
||||||
|
$result = $last->getId('component_id_component_seq');
|
||||||
|
}
|
||||||
|
$component->component_id = $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = new Collection();
|
||||||
|
$params->import(array_merge($_GET, $arguments));
|
||||||
|
$component->parameter = $params;
|
||||||
|
$component->template = $params->get('template', false);
|
||||||
|
|
||||||
|
global $componentsConfig;
|
||||||
|
$editor = $component->getEditUrl();
|
||||||
|
if ($editor) {
|
||||||
|
$componentsConfig[] = $editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $component;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEditUrl() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function raw_query(/*.ComponentRequest.*/ $request)
|
||||||
|
{
|
||||||
|
$arr = $request->r->export('get');
|
||||||
|
|
||||||
|
$param = array();
|
||||||
|
/*.Collection.*/$parameter = $this->parameter;
|
||||||
|
foreach($parameter->export() as $key => $value) {
|
||||||
|
$param[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
foreach($arr as $key => $value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$data[$key] = Arr::get($value, $this->component_id);
|
||||||
|
} else {
|
||||||
|
$data[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['param'] = $param;
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function query(/*.ComponentRequest.*/ $request, $list)
|
||||||
|
{
|
||||||
|
$arr = $request->r->export('get');
|
||||||
|
|
||||||
|
foreach($list as $key => $val) {
|
||||||
|
$arr[$key] [$this->component_id] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($arr['active_page']);
|
||||||
|
return '?' . http_build_query($arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRequireJsPath($name, $path, $shim = null) {
|
||||||
|
global $requireJsConfig;
|
||||||
|
$requireJsConfig['paths'][$name] = $path;
|
||||||
|
if ($shim) {
|
||||||
|
$requireJsConfig['shim'][$name] = $shim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function actionIndex(/*.ComponentRequest.*/ $request) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,32 +1,38 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'core/controller/controller.php';
|
|
||||||
require_once 'core/controller/installer.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Первичный контроллер контроллер страниц
|
* Первичный контроллер контроллер страниц
|
||||||
* @package core
|
* @package system.controller
|
||||||
*/
|
*/
|
||||||
class Controller_Front extends Controller
|
class Controller_Front extends Controller_Action
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var Shortcut */
|
||||||
protected $shortcut; // Ярлык к модулю
|
protected $shortcut; // Ярлык к модулю
|
||||||
protected $_param; // Параметр по которому выбирается модуль
|
protected $_param; // Параметр по которому выбирается модуль
|
||||||
protected $default; // Значение параметра по умолчанию
|
protected $default; // Значение параметра по умолчанию
|
||||||
protected $installer;
|
|
||||||
|
|
||||||
public function __construct(Settings $_registry, $_shortcut)
|
protected $modules = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Settings $_registry
|
||||||
|
* @param Shortcut $_shortcut
|
||||||
|
*/
|
||||||
|
public function __construct(Settings $_registry, $_shortcut) // $db, $installer, $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; // $cc->newShortcut();
|
||||||
|
|
||||||
$this->db = Database::getConnection($registry->readKey(array('system', 'dsn')));
|
$dsn = $registry->readKey(array('system', 'dsn'));
|
||||||
$this->installer = new Installer($_registry);
|
$this->db = Database::getConnection($dsn); // $cc->newConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isLoaded($name)
|
||||||
|
{
|
||||||
|
return isset($this->modules[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Создает экземпляр модуля и выполняет действия для него
|
* Создает экземпляр модуля и выполняет действия для него
|
||||||
|
|
@ -34,17 +40,22 @@ class Controller_Front extends Controller
|
||||||
* @param request $request Имя модуля
|
* @param request $request Имя модуля
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function loadModule($name, Collection $request)
|
public function loadModule($name, Collection $request, $controller = false)
|
||||||
{
|
{
|
||||||
$this->installer->setUp($this->db, array($this, 'installPath'));
|
if ($this->isLoaded($name)) {
|
||||||
$this->installer->doUpdates($name); // ModuleLoader (1)
|
$module = $this->modules[$name];
|
||||||
|
return $module->access->execute($request);
|
||||||
|
}
|
||||||
|
|
||||||
$moduleFile = Shortcut::getUrl($this->shortcut, $name); // ModuleLoader (2)
|
if ($controller) {
|
||||||
$module = $this->loadClass($moduleFile);
|
$moduleFile = Shortcut::getUrl($this->shortcut, $name, $controller); // ModuleLoader (2)
|
||||||
|
} else {
|
||||||
|
$moduleFile = Shortcut::getUrl($this->shortcut, $name, $name); // ModuleLoader (2)
|
||||||
|
}
|
||||||
|
|
||||||
|
$module = $this->loadClass($moduleFile, null, 'Module_');
|
||||||
if ($module) {
|
if ($module) {
|
||||||
// Инициализация модуля
|
// Инициализация модуля
|
||||||
// $module->viewPath = dirname($moduleFile);
|
|
||||||
$module->viewPath = Shortcut::getUrl('modulepath', $name);
|
$module->viewPath = Shortcut::getUrl('modulepath', $name);
|
||||||
$module->name = $name;
|
$module->name = $name;
|
||||||
|
|
||||||
|
|
@ -59,15 +70,17 @@ 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 . '/filter/actionlogger.php', $module, 'Filter_');
|
||||||
$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 . '/filter/actionaccess.php', $logger, 'Filter_');
|
||||||
$module->access->access = $this->loadSettings(Shortcut::getUrl('access', $name));
|
$module->access->access = $this->loadSettings(Shortcut::getUrl('access', $name));
|
||||||
|
|
||||||
$module->setUp();
|
$module->setUp();
|
||||||
|
|
||||||
return $module->access->execute($request);
|
$this->modules[$name] = $module;
|
||||||
|
$result = $module->access->execute($request);
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
return null; // throw new FileNotFoundException();
|
return null; // throw new FileNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
@ -80,13 +93,14 @@ class Controller_Front extends Controller
|
||||||
$this->default = $name;
|
$this->default = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getParameter(Collection $list)
|
|
||||||
{
|
|
||||||
return ($list->get($this->_param)) ? $list->get($this->_param): $this->default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(HTTPRequest $request)
|
public function execute(HTTPRequest $request)
|
||||||
{
|
{
|
||||||
return $this->loadModule($this->getParameter($request), $request);
|
$name = explode("_", $request->get($this->_param, $this->default));
|
||||||
|
if (count($name) >= 2) {
|
||||||
|
$controller = $name[1];
|
||||||
|
} else {
|
||||||
|
$controller = false;
|
||||||
|
}
|
||||||
|
return $this->loadModule($name[0], $request, $controller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'core/settings.php';
|
class Controller_Installer
|
||||||
|
|
||||||
class Installer
|
|
||||||
{
|
{
|
||||||
protected $db;
|
protected $db_manager;
|
||||||
protected $installPath;
|
protected $installPath;
|
||||||
public $_registry;
|
public $_registry;
|
||||||
|
|
||||||
|
|
@ -13,15 +11,20 @@ class Installer
|
||||||
$this->_registry = $_registry;
|
$this->_registry = $_registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUp($db, $installPath)
|
public function setUp($db_manager, $installPath)
|
||||||
{
|
{
|
||||||
$this->db = $db;
|
$this->db_manager = $db_manager;
|
||||||
$this->installPath = $installPath;
|
$this->installPath = $installPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSetupFile($name)
|
function getSetupFile($name)
|
||||||
{
|
{
|
||||||
return Path::join(call_user_func($this->installPath, $name), "setup.php");
|
$setup = Path::join(call_user_func($this->installPath, $name), "install.json");
|
||||||
|
return $setup;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUninstallFile($name){
|
||||||
|
return Path::join(call_user_func($this->installPath, $name), "sql", "uninstall.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверка версии обновления
|
// Проверка версии обновления
|
||||||
|
|
@ -40,22 +43,33 @@ class Installer
|
||||||
|
|
||||||
function installSQL(array $sql, $version_new, $version_old, $name)
|
function installSQL(array $sql, $version_new, $version_old, $name)
|
||||||
{
|
{
|
||||||
require_once "core/setup.php";
|
$result = [];
|
||||||
|
$json_installer = new Database_JsonInstall($this->db_manager);
|
||||||
foreach ($sql as $version => $install) {
|
foreach ($sql as $version => $install) {
|
||||||
if (version_compare($version, $version_new, "<=") && version_compare($version, $version_old, ">")) {
|
if (version_compare($version, $version_new, "<=") && version_compare($version, $version_old, ">")) {
|
||||||
// this->installPath this->db
|
|
||||||
$file = Path::join(call_user_func($this->installPath, $name), "sql", $install);
|
$file = Path::join(call_user_func($this->installPath, $name), "sql", $install);
|
||||||
Setup::batchSQL($this->db, $file);
|
$json_installer->install($file,null);
|
||||||
|
$result[] = $version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function uninstall($name){
|
||||||
|
$uninstall = $this->getUninstallFile($name);
|
||||||
|
if (file_exists($uninstall)) {
|
||||||
|
$json_installer = new Database_JsonInstall($this->db_manager);
|
||||||
|
$json_installer->install($uninstall,null);
|
||||||
|
}
|
||||||
|
$this->_registry->removeKey($name);
|
||||||
|
$this->_registry->write();
|
||||||
|
}
|
||||||
// Устанавливает обновления если есть
|
// Устанавливает обновления если есть
|
||||||
function doUpdates($name, $force = false) // Установка модуля
|
function doUpdates($name, $force = false) // Установка модуля
|
||||||
{
|
{
|
||||||
|
$result = array();
|
||||||
$setup = $this->getSetupFile($name);
|
$setup = $this->getSetupFile($name);
|
||||||
if (file_exists($setup) && ($this->isChanged($name) || $force)) {
|
if (file_exists($setup) && ($this->isChanged($name) || $force)) {
|
||||||
|
|
||||||
$registry = $this->_registry;
|
$registry = $this->_registry;
|
||||||
$settings = new Settings($setup);
|
$settings = new Settings($setup);
|
||||||
$settings->read();
|
$settings->read();
|
||||||
|
|
@ -69,21 +83,29 @@ class Installer
|
||||||
$version_old = "0.0";
|
$version_old = "0.0";
|
||||||
$registry->writeKey(array($name), array());
|
$registry->writeKey(array($name), array());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_compare($version_old, $settings->get('version'), "!=")) {
|
if (version_compare($version_old, $settings->get('version'), "!=")) {
|
||||||
$sql = $settings->get('sql');
|
$sql = $settings->get('sql');
|
||||||
if (is_array($sql)) {
|
if (is_array($sql)) {
|
||||||
$this->installSQL($sql, $version_new, $version_old, $name);
|
$res = $this->installSQL($sql, $version_new, $version_old, $name);
|
||||||
|
if($res){
|
||||||
|
$result[]=$res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обновление версии меню
|
// Обновление версии меню
|
||||||
|
$registry->removeKey($name);
|
||||||
$registry->writeKey(array($name), $settings->get('settings'));
|
$registry->writeKey(array($name), $settings->get('settings'));
|
||||||
$registry->writeKey(array($name),
|
$registry->writeKey(array($name),
|
||||||
array('version' => $version_new,
|
array('version' => $version_new,
|
||||||
'time' => filemtime($setup)));
|
'time' => filemtime($setup)));
|
||||||
$registry->write();
|
$registry->write();
|
||||||
}
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function install($dbinit_path,$dbfill_path=null){
|
||||||
|
$json_installer = new Database_JsonInstall($this->db_manager);
|
||||||
|
$json_installer->install($dbinit_path,$dbfill_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
520
src/Controller/Model.php
Normal file
520
src/Controller/Model.php
Normal file
|
|
@ -0,0 +1,520 @@
|
||||||
|
<?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()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->menu = new Widgets_PageMenu();
|
||||||
|
$this->table = new Widgets_ReactListTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->table->addMenuItem($this->aUrl('delete'), 'удалить', false, 'all', 'btn-danger', 'remove');
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveParameters(HttpRequest $args, $list) {
|
||||||
|
foreach ($list as $item) {
|
||||||
|
$args->session()->set(array($this, $item), $args->get($item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getJSONList(/*.Model_Mapper.*/ $model, HttpRequest $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);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCSV(Model_Mapper $model, HttpRequest $request, $title) {
|
||||||
|
$ref = $request->get('ref');
|
||||||
|
|
||||||
|
$list = $model->findAll($request, $request->get('ref'));
|
||||||
|
|
||||||
|
header('Content-Type: text/csv; charset=utf-8');
|
||||||
|
header('Content-Disposition: attachment; filename='.$title.'.csv');
|
||||||
|
|
||||||
|
echo "\xEF\xBB\xBF"; //UTF-8 BOM.
|
||||||
|
|
||||||
|
$output = fopen('php://output', 'w');
|
||||||
|
if (is_resource($output)) {
|
||||||
|
foreach ($list as $row) {
|
||||||
|
fputcsv($output, (array)$row,';');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Удаление строк из таблицы
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
return json_encode(array('result' => 'ok'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ответ на запрос по поиску
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
if ($request->get('filter')) {
|
||||||
|
$data = new Collection();
|
||||||
|
$data->import($request->get('filter'));
|
||||||
|
$model->addFilter($model->requestToSQL($data, $this->formSchema));
|
||||||
|
}
|
||||||
|
return $this->getJSONList($model, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function actionCSV(HttpRequest $request)
|
||||||
|
{
|
||||||
|
$model = $this->getModel($this->useModel);
|
||||||
|
$title = $request->get("title");
|
||||||
|
if(!$title){
|
||||||
|
$title = "noname";
|
||||||
|
}
|
||||||
|
return $this->getCSV($model, $request, $title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setFormSchema()
|
||||||
|
{
|
||||||
|
$model = $this->getModel($this->useModel);
|
||||||
|
$ui = new Model_UIMapper($model);
|
||||||
|
|
||||||
|
$this->formSchema = $ui->getFormSchema();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сохранение формы
|
||||||
|
*/
|
||||||
|
function beforeSave(/*Model*/ $item, HttpRequest $request)
|
||||||
|
{
|
||||||
|
if (empty($this->formSchema)) {
|
||||||
|
$this->setFormSchema();
|
||||||
|
}
|
||||||
|
// Сделать отображение Формы в обьект и обратно
|
||||||
|
foreach ($this->formSchema as $key => $conv) {
|
||||||
|
list($value, $type) = $conv;
|
||||||
|
$item->$value = call_user_func(array('Primitive', 'to_' . $type), $request->get($key)); // Здесь нужно преобразовывать тип значения
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обновление формы
|
||||||
|
*/
|
||||||
|
function formUpdate(Form_Form $form, HttpRequest $request) {
|
||||||
|
$form->setValues($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Загрузка формы
|
||||||
|
*/
|
||||||
|
function beforeLoad(/*.Model_Model.*/$item, Form_Form $form)
|
||||||
|
{
|
||||||
|
if (empty($this->formSchema)) {
|
||||||
|
$this->setFormSchema();
|
||||||
|
}
|
||||||
|
// Вставка значений из данных в форму
|
||||||
|
// Отображение обьекта в поля формы
|
||||||
|
$form->fill($item, $this->formSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeFirstLoad(Form_Form $form)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка ввода
|
||||||
|
protected function validate(Validator_Validator $validator, Collection $request)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Действие для проверки формы
|
||||||
|
*/
|
||||||
|
public function actionValidate($request)
|
||||||
|
{
|
||||||
|
$validator = new Validator_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_Form $form, $id = null, $ref = null)
|
||||||
|
{
|
||||||
|
if (empty($this->schema)) {
|
||||||
|
$model = $this->getModel($this->useModel);
|
||||||
|
$ui = new Model_UIMapper($model);
|
||||||
|
$schema = $ui->getEditSchema();
|
||||||
|
|
||||||
|
$form->addFieldList($schema);
|
||||||
|
} else {
|
||||||
|
$form->addFieldList($this->schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление
|
||||||
|
*/
|
||||||
|
public function actionAdd(HttpRequest $request)
|
||||||
|
{
|
||||||
|
// {{{ тоже может быть один ref или несколько
|
||||||
|
$ref = $request->get('ref');
|
||||||
|
$this->addParameter('ref', $ref); // Добавляет параметр в url
|
||||||
|
/// }}}
|
||||||
|
|
||||||
|
// Проверка
|
||||||
|
$validator = new Validator_Validator();
|
||||||
|
$validator->addRuleList($this->schema);
|
||||||
|
|
||||||
|
// Действия до проверки формы
|
||||||
|
$this->validate($validator, $request); // <--|
|
||||||
|
$validator->validate($request); // --|
|
||||||
|
// Проверка формы
|
||||||
|
if (!$validator->isValid()) {
|
||||||
|
return json_encode(array('result'=>'fail','errors'=>$validator->getErrorMsg()));
|
||||||
|
}
|
||||||
|
// Нужен тест для формы
|
||||||
|
$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 ??? или выход или новая форма для создания новости
|
||||||
|
|
||||||
|
$id = $model->saveDB($item, $request);
|
||||||
|
|
||||||
|
// Для страницы со списком id -> идентификатор родительской таблицы !!??
|
||||||
|
// $request->set('id', $request->get('ref'));
|
||||||
|
if ($request->get('apply')) {
|
||||||
|
$request->setAction('form');
|
||||||
|
return (string) $this->forward('actionForm', $request);
|
||||||
|
}
|
||||||
|
//$request->setAction('index');
|
||||||
|
$result = array('result'=>'ok');
|
||||||
|
if($id){
|
||||||
|
$result['action'] = forceUrl($this->nUrl('add', array('id' => $id, 'ref' => $request->get('ref'))));
|
||||||
|
}
|
||||||
|
return json_encode($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Заголовок
|
||||||
|
*/
|
||||||
|
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 Form_Form(); // Показываем форму
|
||||||
|
$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);
|
||||||
|
}else{//Создание нового элемента
|
||||||
|
$this->beforeFirstLoad($form);
|
||||||
|
}
|
||||||
|
return json_encode($tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function tableSetup(Widgets_ListTable $table, $id = null, $ref = null)
|
||||||
|
{
|
||||||
|
// FIXME: После замены везде $tableSchema -> table->setHeader удалить!
|
||||||
|
if ($this->tableSchema) {
|
||||||
|
$table->setHeader($this->tableSchema);
|
||||||
|
} else {
|
||||||
|
// Настройка таблицы отображения по схеме данных
|
||||||
|
$model = $this->getModel($this->useModel);
|
||||||
|
$ui = new Model_UIMapper($model);
|
||||||
|
$ui->hidden = $table->hidden;
|
||||||
|
|
||||||
|
$schema = $ui->getTableSchema();
|
||||||
|
$schema[0]['action'] = forceUrl($table->getFirstItem());
|
||||||
|
|
||||||
|
$table->setHeader($schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public function actionDefault(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 = new stdClass();
|
||||||
|
|
||||||
|
// Помощники действий
|
||||||
|
$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);
|
||||||
|
if (!$this->table->getData('module')) {
|
||||||
|
$this->table->setData('module', strtolower($this->useModel));
|
||||||
|
}
|
||||||
|
$tpl->menu_path = $this->path->getItems();
|
||||||
|
|
||||||
|
$this->table->makeData();
|
||||||
|
$tpl->table = array('data' => $this->table->data);
|
||||||
|
$tpl->menu = $this->menu->menu->getItems();
|
||||||
|
$tpl->path = $this->path->getItems();
|
||||||
|
|
||||||
|
return json_encode($tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public function actionSetup(HttpRequest $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), 'page' => 1, 'size' => 0, 'desc' => 'asc', 'key' => false));
|
||||||
|
|
||||||
|
return $this->forward('actionIndex', $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
protected function formPage($form, $request, $template = 'form') {
|
||||||
|
$view = new stdClass();//$this->getView($template);
|
||||||
|
$view->form = $form;
|
||||||
|
$form->action = forceUrl($this->nUrl('add', array('page' => $this->getPageId($request)))); // Действие для формы
|
||||||
|
|
||||||
|
$view->path = $this->path->getItems();
|
||||||
|
$view->back = $this->path->getPrev();
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getActionPath() {
|
||||||
|
return new Controller_State('index');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Тоже убрать в метод Controller_Model
|
||||||
|
function getActionPath(HttpRequest $request, $action = null) {
|
||||||
|
$this->_getActionPath()->getPath($this, ($action) ? $action : $request->getAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function parse_params($expression) {
|
||||||
|
$expression = htmlspecialchars_decode($expression);
|
||||||
|
$offset = strpos($expression, '?');
|
||||||
|
$url = parse_url($expression);
|
||||||
|
|
||||||
|
$arguments = array();
|
||||||
|
if ($offset === false) {
|
||||||
|
$path = $expression;
|
||||||
|
} else if (is_int($offset)) {
|
||||||
|
$path = substr($expression, 0, $offset);
|
||||||
|
$query = substr($expression, $offset+1);
|
||||||
|
parse_str($query, $arguments);
|
||||||
|
}
|
||||||
|
return $arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function actionFormPage(HttpRequest $request) {
|
||||||
|
//$tpl = $this->getView('formpage', 'View_Top');
|
||||||
|
|
||||||
|
$view = $this->getView('formpage', 'View_Top');
|
||||||
|
|
||||||
|
$params = $this->parse_params($request->get('params'));
|
||||||
|
|
||||||
|
|
||||||
|
// $model = $this->getModel($this->useModel);
|
||||||
|
$form = new Form_Form(); // Показываем форму
|
||||||
|
$form->header = 'Редактирование записи';
|
||||||
|
$this->formSetup($form, $request->get('id'), $request->get('ref')); // Инициализация формы
|
||||||
|
/*
|
||||||
|
$ui = new Model_UIMapper($model);
|
||||||
|
$schema = $ui->getEditSchema();
|
||||||
|
$form->addFieldList($schema);
|
||||||
|
*/
|
||||||
|
|
||||||
|
$list = $request->get('table_item');
|
||||||
|
$id = ($list[0]) ? $list[0] : $request->get('id');
|
||||||
|
|
||||||
|
// $tpl = $this->formPage($form, $request);
|
||||||
|
|
||||||
|
$view->setView('form', $form);
|
||||||
|
$view->action = forceUrl($this->nUrl('addpage', array('ref' => $params['id']))); // Действие для формы
|
||||||
|
|
||||||
|
// $view->menu_path = $this->path->getItems();
|
||||||
|
$view->back = '';
|
||||||
|
return $view;
|
||||||
|
|
||||||
|
// return $tpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Для поддержки редактрования на сайте */
|
||||||
|
public function actionAddPage(HttpRequest $request)
|
||||||
|
{
|
||||||
|
// {{{ тоже может быть один ref или несколько
|
||||||
|
$ref = $request->get('ref');
|
||||||
|
$this->addParameter('ref', $ref); // Добавляет параметр в url
|
||||||
|
/// }}}
|
||||||
|
$validator = new Validator_Validator();
|
||||||
|
$validator->addRuleList($this->schema);
|
||||||
|
|
||||||
|
// Действия до проверки формы
|
||||||
|
$this->validate($validator, $request); // <--|
|
||||||
|
$validator->validate($request); // --|
|
||||||
|
// Проверка формы
|
||||||
|
if (!$validator->isValid()) {
|
||||||
|
return $validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Нужен тест для формы
|
||||||
|
$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); // Сюдаже и истрия переходов
|
||||||
|
$model->saveDB($item, $request);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Controller/Request.php
Normal file
16
src/Controller/Request.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Controller_Request {
|
||||||
|
function __construct($request, $id) {
|
||||||
|
$this->r = $request;
|
||||||
|
$this->id = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get($name) {
|
||||||
|
$v = $this->r->get($name);
|
||||||
|
if ($id && is_array($v)) {
|
||||||
|
return isset($v[$id]) ? $v[$id] : $def;
|
||||||
|
}
|
||||||
|
return $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/Controller/Service.php
Normal file
64
src/Controller/Service.php
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс сервиса = Упрощенный компонент
|
||||||
|
*/
|
||||||
|
class Controller_Service
|
||||||
|
{
|
||||||
|
public $viewPath = array();
|
||||||
|
public $registry; // Registry->getInstance
|
||||||
|
public $template;
|
||||||
|
public $templatePath;
|
||||||
|
public $COMPONENTS_WEB;
|
||||||
|
|
||||||
|
public function getTemplatePath($name)
|
||||||
|
{
|
||||||
|
return Path::join($this->viewPath[0], 'templates', 'modern', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplateWebPath()
|
||||||
|
{
|
||||||
|
return Path::join($this->webPath[0], strtolower(get_class($this)), 'templates', 'modern');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $name Имя модели
|
||||||
|
*/
|
||||||
|
private function getModelPath($name)
|
||||||
|
{
|
||||||
|
return Path::join (CMS_PATH, "model", $name . ".php");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создает модель
|
||||||
|
* @param string $name
|
||||||
|
* @return model
|
||||||
|
*/
|
||||||
|
public function getModel($name)
|
||||||
|
{
|
||||||
|
require_once 'mapper/mapper.php';
|
||||||
|
|
||||||
|
require_once ($this->getModelPath ($name));
|
||||||
|
$modelName = $name . "Mapper";
|
||||||
|
$model = new $modelName ();
|
||||||
|
$model->db = $this->db;
|
||||||
|
return $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function options($key, $val, $res) {
|
||||||
|
$result = array();
|
||||||
|
while($res->next()) {
|
||||||
|
$result[] = array('value' => $res->getInt($key), 'name' => $res->getString($val));
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function optionsPair($list, $selected = false) {
|
||||||
|
$result = array();
|
||||||
|
foreach ($list as $key => $value) {
|
||||||
|
$result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class State
|
class Controller_State
|
||||||
{
|
{
|
||||||
public $action = '';
|
public $action = '';
|
||||||
public $states = array();
|
public $states = array();
|
||||||
|
|
@ -13,7 +13,7 @@ class 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 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 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 State
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
$path = State::make('index')
|
|
||||||
->addState(State::make('form'))
|
|
||||||
->addState(State::make('view'));
|
|
||||||
|
|
||||||
$path->getPath(0, 'form');
|
|
||||||
*/
|
|
||||||
180
src/Database.php
Normal file
180
src/Database.php
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
<?php
|
||||||
|
///<reference path="database/pdostatement.php" />
|
||||||
|
require_once "database/pdostatement.php";
|
||||||
|
/**
|
||||||
|
* Класс оболочка для PDO для замены Creole
|
||||||
|
*/
|
||||||
|
class Database extends PDO
|
||||||
|
{
|
||||||
|
|
||||||
|
public $dsn;
|
||||||
|
public function __construct($dsn, $username = null, $password = null)
|
||||||
|
{
|
||||||
|
parent::__construct($dsn, $username, $password);
|
||||||
|
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Database_PDOStatement', array()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDSN()
|
||||||
|
{
|
||||||
|
return $this->dsn;
|
||||||
|
}
|
||||||
|
public function isPostgres(){
|
||||||
|
return ($this->dsn["phptype"] == "pgsql");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Создает соединение с базой данных
|
||||||
|
*/
|
||||||
|
static function getConnection(array $dsn)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($dsn['phptype'] == 'pgsql' || $dsn['phptype'] == 'mysql') {
|
||||||
|
$port = (isset($dsn['port'])) ? "port={$dsn['port']};" : "";
|
||||||
|
/*.Database.*/$connection = new static("{$dsn['phptype']}:host={$dsn['hostspec']}; $port dbname={$dsn['database']}", $dsn['username'], $dsn['password']);
|
||||||
|
if ($dsn['phptype'] == 'pgsql') {
|
||||||
|
$connection->query('SET client_encoding="UTF-8"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($dsn['phptype'] == 'sqlite') {
|
||||||
|
/*.Database.*/$connection = new static("{$dsn['phptype']}:{$dsn['database']}");
|
||||||
|
$connection->setAttribute(PDO::ATTR_TIMEOUT, 5);
|
||||||
|
$mode = defined('SQLITE_JOURNAL_MODE') ? SQLITE_JOURNAL_MODE : 'WAL';
|
||||||
|
$connection->query("PRAGMA journal_mode=$mode");
|
||||||
|
|
||||||
|
if(!function_exists('sqliteLower')){
|
||||||
|
function sqliteLower($str) {
|
||||||
|
return mb_strtolower($str, 'UTF-8');
|
||||||
|
}
|
||||||
|
$connection->sqliteCreateFunction('LOWER', 'sqliteLower', 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$connection->dsn = $dsn;
|
||||||
|
return $connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function executeQuery($query, $values=null)
|
||||||
|
{
|
||||||
|
/*.Database_PDOStatement.*/$stmt = $this->prepare($query);
|
||||||
|
|
||||||
|
$stmt->execute($values);
|
||||||
|
$stmt->cache = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareStatement($query)
|
||||||
|
{
|
||||||
|
return new Database_Statement($query, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для совместимости со старым представлением баз данных CIS
|
||||||
|
/**
|
||||||
|
* Извлекает из базы все элементы по запросу
|
||||||
|
*/
|
||||||
|
public function fetchAllArray($query,$values=null)
|
||||||
|
{
|
||||||
|
/*.Database_PDOStatement.*/$sth = $this->prepare($query);
|
||||||
|
$prep = $this->prepareValues($values);
|
||||||
|
$sth->execute($prep);
|
||||||
|
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Извлекает из базы первый элемент по запросу
|
||||||
|
*/
|
||||||
|
public function fetchOneArray($query,$values=null)
|
||||||
|
{
|
||||||
|
/*.Database_PDOStatement.*/$sth = $this->prepare($query);
|
||||||
|
$prep = $this->prepareValues($values);
|
||||||
|
$sth->execute($prep);
|
||||||
|
return $sth->fetch(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function assignQuote($x, $y)
|
||||||
|
{
|
||||||
|
return $x . "=" . $this->quote($y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareValues($values)
|
||||||
|
{
|
||||||
|
if (!$values) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$pg = $this->isPostgres();
|
||||||
|
$prep = array();
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
$result = null;
|
||||||
|
if(is_bool($value)) {
|
||||||
|
if ($pg) {
|
||||||
|
$result = $value ? 'true' : 'false';
|
||||||
|
} else {
|
||||||
|
$result = $value ? 1 : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result = $value;
|
||||||
|
}
|
||||||
|
$prep[":" . $key] = $result;
|
||||||
|
}
|
||||||
|
return $prep;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Создает INSERT запрос
|
||||||
|
*/
|
||||||
|
function insertQuery($table, array $values, $return_id = false, $index = null)
|
||||||
|
{
|
||||||
|
$prep = $this->prepareValues($values);
|
||||||
|
|
||||||
|
$sql = "INSERT INTO $table (" . implode(",", array_keys($values))
|
||||||
|
. ") VALUES (" . implode(",", array_keys($prep)). ")";
|
||||||
|
|
||||||
|
if($return_id){
|
||||||
|
if ($this->isPostgres()){
|
||||||
|
$sql = $sql." RETURNING $index";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$stmt = $this->prepare($sql);
|
||||||
|
$stmt->setFetchMode(PDO::FETCH_ASSOC);
|
||||||
|
$stmt->execute($prep);
|
||||||
|
$result = $stmt->fetch();
|
||||||
|
if ($return_id) {
|
||||||
|
if ($this->isPostgres()) {
|
||||||
|
return $result[$index];
|
||||||
|
} else {
|
||||||
|
$result = $this->fetchOneArray("SELECT $index AS lastid FROM $table WHERE OID = last_insert_rowid()");
|
||||||
|
return $result['lastid'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создает UPDATE запрос
|
||||||
|
*/
|
||||||
|
function updateQuery($table, array $values, $cond)
|
||||||
|
{
|
||||||
|
$prep = $this->prepareValues($values);
|
||||||
|
$sql = "UPDATE $table SET " . implode(",",
|
||||||
|
array_map(function($k,$v){return $k."=".$v;}, array_keys($values), array_keys($prep))) . " WHERE $cond";
|
||||||
|
|
||||||
|
$stmt = $this->prepare($sql);
|
||||||
|
$stmt->setFetchMode(PDO::FETCH_ASSOC);
|
||||||
|
$stmt->execute($prep);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIdGenerator() {
|
||||||
|
return new Database_IdGenerator($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Замечание: Только для Postgres SQL
|
||||||
|
* @param string $seq Имя последовательности для ключа таблицы
|
||||||
|
* @return int Идентефикатор следующей записи
|
||||||
|
*/
|
||||||
|
function getNextId($seq) {
|
||||||
|
$result = $this->fetchOneArray("SELECT nextval('$seq')");
|
||||||
|
return $result['nextval'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function close()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/Database/IdGenerator.php
Normal file
26
src/Database/IdGenerator.php
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Database_IdGenerator {
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
function __construct(Database $db) {
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBeforeInsert() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAfterInsert() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId($seq) {
|
||||||
|
if ($this->db->isPostgres()) {
|
||||||
|
$result = $this->db->fetchOneArray("SELECT nextval('$seq') AS nextval");
|
||||||
|
} else {
|
||||||
|
$result = $this->db->fetchOneArray("SELECT last_insert_rowid() AS nextval");
|
||||||
|
}
|
||||||
|
return intval($result['nextval']);
|
||||||
|
}
|
||||||
|
}
|
||||||
143
src/Database/JsonInstall.php
Normal file
143
src/Database/JsonInstall.php
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
<?php
|
||||||
|
//Действия с базой данных согласно json файлу.
|
||||||
|
|
||||||
|
class Database_JsonInstall {
|
||||||
|
public $db_manager;
|
||||||
|
public $serialColumns;
|
||||||
|
|
||||||
|
public function __construct(Database_Manager $db_manager) {
|
||||||
|
$this->db_manager = $db_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
function install($dbinit_path, $dbfill_path = null) {
|
||||||
|
$dbinit_file = file_get_contents($dbinit_path);
|
||||||
|
if (is_string($dbinit_file)) {
|
||||||
|
$initActions = json_decode($dbinit_file, true);
|
||||||
|
if (!$initActions) {
|
||||||
|
echo "Invalid dbinit.json ".$dbinit_file;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo "No dbinit.json";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->initDataBase($initActions, $dbinit_path);
|
||||||
|
if ($dbfill_path) {
|
||||||
|
$this->fillDataBase($dbfill_path);
|
||||||
|
}
|
||||||
|
$this->makeConstraints($initActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function missingTables($tables) {
|
||||||
|
$actual_tables = $this->db_manager->GetAllTableNames();
|
||||||
|
$missingTables = [];
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
if (!in_array($table, $actual_tables))
|
||||||
|
$missingTables[] = $table;
|
||||||
|
}
|
||||||
|
return $missingTables;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Создать таблицы
|
||||||
|
function initDataBase(/*.array.*/$initActions, $dbinit_path) {
|
||||||
|
$pg = $this->db_manager->db->isPostgres();
|
||||||
|
if (!$pg) {
|
||||||
|
$refs = [];
|
||||||
|
//В sqlite нет alter reference. Референсы надо создавать при создании таблицы.
|
||||||
|
foreach ($initActions as $action) {
|
||||||
|
if ($action["type"] == "alterReference") {
|
||||||
|
if (!isset($refs[$action["table"]]))
|
||||||
|
$refs[$action["table"]] = [];
|
||||||
|
$refs[$action["table"]][]=$action;//добавить к списку референсов для таблицы
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($initActions as $action) {
|
||||||
|
if (!$pg) {
|
||||||
|
if ($action["type"] == "createTable") {
|
||||||
|
$table_name = $action["table_name"];
|
||||||
|
if (isset($refs[$table_name])) {
|
||||||
|
foreach ($refs[$table_name] as $value) {
|
||||||
|
$action['fields'][$value['column']]['references'] =
|
||||||
|
$value['refTable']."(".$value['refColumn'].")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($action["type"] != "alterReference") {
|
||||||
|
$this->db_manager->ExecuteAction($action, $dbinit_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Запомнить все колонки serial
|
||||||
|
$this->serialColumns = [];
|
||||||
|
if ($pg) {
|
||||||
|
foreach ($initActions as $action) {
|
||||||
|
if ($action["type"] == "createTable") {
|
||||||
|
foreach ($action["fields"] as $name => $field) {
|
||||||
|
if ($field["type"]=="serial") {
|
||||||
|
$this->serialColumns[] = [
|
||||||
|
"table"=>$action["table_name"],
|
||||||
|
"column"=>$name
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Заполнить данными
|
||||||
|
function fillDataBase($dbfill_file_path) {
|
||||||
|
$dbfill_file = file_get_contents($dbfill_file_path);
|
||||||
|
if (is_string($dbfill_file)) {
|
||||||
|
$actions = json_decode($dbfill_file,true);
|
||||||
|
if ($actions) {
|
||||||
|
|
||||||
|
//Проверка что упоминаемые в списке действий таблицы уже есть в базе
|
||||||
|
$affected_tables = [];
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
if ($action["table_name"]) {
|
||||||
|
$affected_tables[$action["table_name"]] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$missing = $this->missingTables(array_keys($affected_tables));
|
||||||
|
if (!empty($missing)) {
|
||||||
|
echo "dbfill error. Missing tables: ".implode(" ", $missing);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Выполнение действий
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
$this->db_manager->ExecuteAction($action, $dbfill_file_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo "Invalid dbfill.json";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo "No dbfill.json";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Обновить ключи serial и создать ограничения
|
||||||
|
function makeConstraints($initActions) {
|
||||||
|
$pg = $this->db_manager->db->isPostgres();
|
||||||
|
if ($pg) {
|
||||||
|
foreach ($this->serialColumns as $serialColumn) {
|
||||||
|
$this->db_manager->UpdateSerial($serialColumn["table"], $serialColumn["column"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($initActions as $action) {
|
||||||
|
if ($action["type"] == "alterReference") {
|
||||||
|
$this->db_manager->ExecuteAction($action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
211
src/Database/Manager.php
Normal file
211
src/Database/Manager.php
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Database_Manager
|
||||||
|
{
|
||||||
|
public /*.Database.*/$db;
|
||||||
|
|
||||||
|
function __construct(Database $db) {
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ExecuteAction(/*.array.*/$action, $db_file = "") {
|
||||||
|
switch($action["type"]) {
|
||||||
|
case "dropTable":
|
||||||
|
$this->DropTableQuery($action["table_name"], true);
|
||||||
|
break;
|
||||||
|
case "createTable":
|
||||||
|
$constraints = isset($action["constraints"]) ? $action["constraints"] : NULL;
|
||||||
|
$this->CreateTableQuery($action["table_name"], $action["fields"], $constraints);
|
||||||
|
break;
|
||||||
|
case "addColumn":
|
||||||
|
$this->AddColumn($action["table_name"], $action["column_name"], $action["field"]);
|
||||||
|
break;
|
||||||
|
case "insert":
|
||||||
|
$this->db->insertQuery($action["table_name"], $action["values"]);
|
||||||
|
break;
|
||||||
|
case "alterReference":
|
||||||
|
$this->AlterReference($action["table"], $action["column"], $action["refTable"], $action["refColumn"]);
|
||||||
|
break;
|
||||||
|
case "renameColumn":
|
||||||
|
$this->RenameColumn($action["table"], $action["old_name"], $action["new_name"]);
|
||||||
|
break;
|
||||||
|
case "executeFile":
|
||||||
|
if ($this->db->isPostgres() && isset($action["pgsql"])) {
|
||||||
|
$file = $action["pgsql"];
|
||||||
|
} else {
|
||||||
|
$file = $action["source"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmtList = Tools_SQLStatementExtractor::extractFile(Path::join(dirname($db_file), $file));
|
||||||
|
foreach($stmtList as $stmt) {
|
||||||
|
$this->db->executeQuery($stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("unknown action ". $action["type"] . PHP_EOL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function DropTableQuery($table, $cascade=false) {
|
||||||
|
$statement = "DROP TABLE IF EXISTS ".$table;
|
||||||
|
if ($this->db->isPostgres()&&$cascade) {
|
||||||
|
$statement = $statement." CASCADE";
|
||||||
|
}
|
||||||
|
$this->db->query($statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function AlterReference($table,$column,$refTable,$refColumn) {
|
||||||
|
$this->db->query("ALTER TABLE ".$table." ADD CONSTRAINT ".$table."_".$column."fk"." FOREIGN KEY (".$column.") REFERENCES ".$refTable." (".$refColumn.")");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Извлечение информации о полях таблицы
|
||||||
|
public function TableInfo($table) {
|
||||||
|
$pg = $this->db->isPostgres();
|
||||||
|
if ($pg) {
|
||||||
|
throw new Exception("Not implemented for postgres");
|
||||||
|
} else {
|
||||||
|
$results = $this->db->fetchAllArray("PRAGMA table_info(".$table.");");
|
||||||
|
if (empty($results)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$fields = [];
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$fields[$result["name"]] = [
|
||||||
|
"type"=> $result["type"],
|
||||||
|
"not_null"=> boolval($result["notnull"]),
|
||||||
|
"constraint"=> ((boolean) $result["pk"]) ? "PRIMARY KEY" : null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function RenameColumn($table, $old_name, $new_name) {
|
||||||
|
$pg = $this->db->isPostgres();
|
||||||
|
if ($pg) {
|
||||||
|
$this->db->query("ALTER TABLE ".$table." RENAME COLUMN ".$old_name." TO ".$new_name);
|
||||||
|
} else {
|
||||||
|
$tmp_table = "tmp_" . $table;
|
||||||
|
$this->DropTableQuery($tmp_table);
|
||||||
|
$table_info = $this->TableInfo($table);
|
||||||
|
|
||||||
|
if (isset($table_info[$new_name])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.array.*/$data = $this->DumpTable($table);
|
||||||
|
|
||||||
|
$this->db->query("ALTER TABLE ".$table." RENAME TO ".$tmp_table.";");
|
||||||
|
$table_info[$new_name] = $table_info[$old_name];
|
||||||
|
unset($table_info[$old_name]);
|
||||||
|
$this->CreateTableQuery($table,$table_info,null);
|
||||||
|
|
||||||
|
foreach ($data as $row) {
|
||||||
|
$values = $row['values'];
|
||||||
|
$values[$new_name] = $values[$old_name];
|
||||||
|
unset($values[$old_name]);
|
||||||
|
$this->db->insertQuery($table, $values);
|
||||||
|
}
|
||||||
|
$this->DropTableQuery($tmp_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Обновление ключа serial после ручной вставки
|
||||||
|
public function UpdateSerial($table,$column) {
|
||||||
|
$this->db->query("SELECT setval(pg_get_serial_sequence('".$table."', '".$column."'), coalesce(max(".$column."),0) + 1, false) FROM ".$table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Column_Definition($name,$data,$pg){
|
||||||
|
$constraint = isset($data['constraint'])?" ".$data['constraint']:"";
|
||||||
|
$references = "";
|
||||||
|
if (isset($data['references'])) {
|
||||||
|
$references = " REFERENCES ".$data['references'];
|
||||||
|
}
|
||||||
|
if (isset($data["not_null"])&&$data["not_null"])
|
||||||
|
$constraint .=" NOT NULL";
|
||||||
|
$type = $data['type'];
|
||||||
|
if (!$pg) {
|
||||||
|
if (strtolower($type)=="serial")
|
||||||
|
$type = "integer";
|
||||||
|
//if (strtolower($type)=="boolean")
|
||||||
|
// $type = "integer";
|
||||||
|
}
|
||||||
|
return $name." ".$type.$references.$constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function AddColumn($table_name,$column_name,$field){
|
||||||
|
$pg = $this->db->isPostgres();
|
||||||
|
$q = "ALTER TABLE ".$table_name." ADD COLUMN ".
|
||||||
|
$this->Column_Definition($column_name, $field, $pg);
|
||||||
|
$this->db->query($q);
|
||||||
|
}
|
||||||
|
|
||||||
|
//CreateTableQuery('users',['id'=>['type'=>'integer','constraint'=>'PRIMARY KEY']])
|
||||||
|
public function CreateTableQuery($table, $fields, $constraints) {
|
||||||
|
$pg = $this->db->isPostgres();
|
||||||
|
if ($constraints) {
|
||||||
|
$constraints = ", " . $constraints;
|
||||||
|
}
|
||||||
|
|
||||||
|
$statement = "CREATE TABLE $table (" . implode(",",
|
||||||
|
array_map(function($name,$data) use ($pg) {
|
||||||
|
return $this->Column_Definition($name,$data,$pg);
|
||||||
|
}, array_keys($fields), array_values($fields))
|
||||||
|
) . " " . $constraints . ")";
|
||||||
|
$this->db->query($statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function DumpTable($table_name) {
|
||||||
|
$pg = $this->db->isPostgres();
|
||||||
|
|
||||||
|
/*.array.*/$result = array();
|
||||||
|
/*.array.*/$data = $this->db->fetchAllArray("SELECT * FROM ".$table_name.";");
|
||||||
|
|
||||||
|
if (!$pg) {
|
||||||
|
$table_fields = $this->TableInfo($table_name);
|
||||||
|
foreach ($table_fields as $name => $value) {
|
||||||
|
$type = strtolower($value['type']);
|
||||||
|
if ($type == "boolean") {
|
||||||
|
foreach ($data as &$row) {
|
||||||
|
/*.array.*/$row = $row;
|
||||||
|
if (isset($row[$name])) {
|
||||||
|
$row[$name] = boolval($row[$name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($data as $r) {
|
||||||
|
$result[] = array(
|
||||||
|
"type" => "insert",
|
||||||
|
"table_name" => $table_name,
|
||||||
|
"values" => $r
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetAllTableNames() {
|
||||||
|
$result = [];
|
||||||
|
if ($this->db->isPostgres()) {
|
||||||
|
$query = "SELECT table_name as name FROM information_schema.tables WHERE table_schema='public'";
|
||||||
|
} else {
|
||||||
|
$query = "SELECT * FROM sqlite_master WHERE type='table'";
|
||||||
|
}
|
||||||
|
$tables = $this->db->fetchAllArray($query);
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
$result[] = $table['name'];
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function DumpInserts() {
|
||||||
|
$table_names = $this->GetAllTableNames();
|
||||||
|
$result = array();
|
||||||
|
foreach ($table_names as $table_name) {
|
||||||
|
$result = array_merge($result, $this->DumpTable($table_name));
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
97
src/Database/PDOStatement.php
Normal file
97
src/Database/PDOStatement.php
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ .'/../tools/string.php';
|
||||||
|
|
||||||
|
class Database_PDOStatement extends PDOStatement implements IteratorAggregate
|
||||||
|
{
|
||||||
|
protected $cursorPos = 0;
|
||||||
|
public $cache = array();
|
||||||
|
public $fields;
|
||||||
|
|
||||||
|
function getIterator() {
|
||||||
|
return new Database_StatementIterator($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function __construct() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewind() {
|
||||||
|
$this->cursorPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function seek($rownum) {
|
||||||
|
if ($rownum < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostgreSQL rows start w/ 0, but this works, because we are
|
||||||
|
// looking to move the position _before_ the next desired position
|
||||||
|
$this->cursorPos = $rownum;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function valid() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function first() {
|
||||||
|
if($this->cursorPos !== 0) { $this->seek(0); }
|
||||||
|
return $this->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
if ($this->getRecordCount() > $this->cursorPos) {
|
||||||
|
if (!isset($this->cache[$this->cursorPos])) {
|
||||||
|
$this->cache[$this->cursorPos] = $this->fetch(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
$this->fields = $this->cache[$this->cursorPos];
|
||||||
|
|
||||||
|
$this->cursorPos++;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$this->fields = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function key() {
|
||||||
|
return $this->cursorPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function current() {
|
||||||
|
return $this->cache[$this->cursorPos];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRow() {
|
||||||
|
return $this->fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInt($name) {
|
||||||
|
return intval($this->fields[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBlob($name) {
|
||||||
|
return $this->fields[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getString($name) {
|
||||||
|
return $this->fields[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBoolean($name) {
|
||||||
|
return (bool)$this->fields[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
function get($name) {
|
||||||
|
return $this->fields[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArray($name) {
|
||||||
|
return strToArray($this->fields[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRecordCount() {
|
||||||
|
return count($this->cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/Database/Statement.php
Normal file
61
src/Database/Statement.php
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс оболочка для PDOStatement для замены Creole
|
||||||
|
*/
|
||||||
|
class Database_Statement
|
||||||
|
{
|
||||||
|
protected $limit = null;
|
||||||
|
protected $offset = null;
|
||||||
|
protected $statement = null;
|
||||||
|
protected $binds = array();
|
||||||
|
protected $conn;
|
||||||
|
protected $query;
|
||||||
|
|
||||||
|
function __construct($query, /*.Database.*/ $conn) {
|
||||||
|
$this->query = $query;
|
||||||
|
$this->conn = $conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setInt($n, $value)
|
||||||
|
{
|
||||||
|
$this->binds [] = array($n, $value, PDO::PARAM_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setString($n, $value)
|
||||||
|
{
|
||||||
|
$this->binds [] = array($n, $value, PDO::PARAM_STR);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBlob($n, $value)
|
||||||
|
{
|
||||||
|
$this->binds [] = array($n, $value, PDO::PARAM_LOB);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLimit($limit)
|
||||||
|
{
|
||||||
|
$this->limit = $limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOffset($offset)
|
||||||
|
{
|
||||||
|
$this->offset = $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeQuery()
|
||||||
|
{
|
||||||
|
if ($this->limit) {
|
||||||
|
$this->query .= " LIMIT {$this->limit} OFFSET {$this->offset}";
|
||||||
|
}
|
||||||
|
/*.Database_PDOStatement.*/$stmt = $this->conn->prepare($this->query);
|
||||||
|
foreach ($this->binds as $bind) {
|
||||||
|
list($n, $value, $type) = $bind;
|
||||||
|
$stmt->bindValue($n, $value, (int) $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
$stmt->cache = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/Database/StatementIterator.php
Normal file
46
src/Database/StatementIterator.php
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Database_StatementIterator implements Iterator
|
||||||
|
{
|
||||||
|
|
||||||
|
private $result;
|
||||||
|
private $pos = 0;
|
||||||
|
private $fetchmode;
|
||||||
|
private $row_count;
|
||||||
|
|
||||||
|
public function __construct(/*.Database_PDOStatement.*/ $rs) {
|
||||||
|
$this->result = $rs;
|
||||||
|
$this->row_count = $rs->getRecordCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewind() {
|
||||||
|
$this->pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function valid() {
|
||||||
|
return ($this->pos < $this->row_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
function key() {
|
||||||
|
return $this->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function current() {
|
||||||
|
if (!isset($this->result->cache[$this->pos])) {
|
||||||
|
$this->result->cache[$this->pos] = $this->result->fetch(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
return $this->result->cache[$this->pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
$this->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
function seek($index) {
|
||||||
|
$this->pos = $index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function count() {
|
||||||
|
return $this->row_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Excel/DataTime.php
Normal file
16
src/Excel/DataTime.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Excel_DateTime
|
||||||
|
{
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = intval($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getString()
|
||||||
|
{
|
||||||
|
return date('Y-m-d\TH:i:s.u', $this->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/Excel/Document.php
Normal file
100
src/Excel/Document.php
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Документ
|
||||||
|
*/
|
||||||
|
class Excel_Document {
|
||||||
|
static $ns = "urn:schemas-microsoft-com:office:spreadsheet";
|
||||||
|
private $table = array ();
|
||||||
|
protected $styles = array();
|
||||||
|
|
||||||
|
function addTable($table) {
|
||||||
|
$this->table [] = $table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление стиля к документу
|
||||||
|
* @param $name string Имя стиля
|
||||||
|
* @param $values array Параметры стиля
|
||||||
|
* @param $type Тип стиля
|
||||||
|
*/
|
||||||
|
function setStyle ($name, array $values, $type = 'Interior')
|
||||||
|
{
|
||||||
|
if(!isset($this->styles[$name])) {
|
||||||
|
$this->styles[$name] = array();
|
||||||
|
}
|
||||||
|
$this->styles[$name][$type] = $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация стилей
|
||||||
|
*/
|
||||||
|
private function createStyles (XMLWriter $doc) {
|
||||||
|
$doc->startElement('Styles');
|
||||||
|
foreach ($this->styles as $name => $sn) {
|
||||||
|
$doc->startElement('Style');
|
||||||
|
$doc->writeAttribute('ss:ID', $name);
|
||||||
|
foreach ($sn as $type => $s) {
|
||||||
|
// Стиль Borders - составной
|
||||||
|
if ($type == 'Borders') {
|
||||||
|
$doc->startElement('Borders');
|
||||||
|
foreach ($s as $border) {
|
||||||
|
/*.array.*/$border = $border;
|
||||||
|
$doc->startElement('Border');
|
||||||
|
foreach ($border as $key => $value) {
|
||||||
|
$doc->writeAttribute('ss:' . $key, $value);
|
||||||
|
}
|
||||||
|
$doc->endElement();
|
||||||
|
}
|
||||||
|
$doc->endElement();
|
||||||
|
} else {
|
||||||
|
$doc->startElement($type);
|
||||||
|
foreach ($s as $key => $value) {
|
||||||
|
$doc->writeAttribute('ss:' . $key, $value);
|
||||||
|
}
|
||||||
|
$doc->endElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$doc->endElement();
|
||||||
|
}
|
||||||
|
$doc->endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Преобразует переводы строки в спец символы
|
||||||
|
*/
|
||||||
|
function clean ($s) {
|
||||||
|
assert(is_string($s));
|
||||||
|
|
||||||
|
return strtr($s, array ("\n" => " "));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сохраняет таблицу в формате Office 2003 XML
|
||||||
|
* http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats
|
||||||
|
*/
|
||||||
|
function save($filename)
|
||||||
|
{
|
||||||
|
$doc = new XMLWriter();
|
||||||
|
$doc->openURI($filename);
|
||||||
|
$doc->setIndent(false);
|
||||||
|
$doc->startDocument('1.0','utf-8');
|
||||||
|
$doc->startElement('Workbook');
|
||||||
|
$doc->writeAttribute('xmlns', self::$ns);
|
||||||
|
$doc->writeAttribute('xmlns:ss', self::$ns);
|
||||||
|
|
||||||
|
$this->createStyles($doc);
|
||||||
|
|
||||||
|
foreach ($this->table as $table) {
|
||||||
|
if ($table instanceof Excel_Table) {
|
||||||
|
$table->createTable($doc);
|
||||||
|
} else {
|
||||||
|
$table_data = call_user_func($table);
|
||||||
|
$table_data->createTable($doc);
|
||||||
|
unset($table_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$doc->endElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
17
src/Excel/Number.php
Normal file
17
src/Excel/Number.php
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Excel_Number
|
||||||
|
{
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = intval($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getString()
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,35 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class Excel_Number
|
|
||||||
{
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
function __construct($value)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getString()
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Excel_DateTime
|
|
||||||
{
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
function __construct($value)
|
|
||||||
{
|
|
||||||
$this->value = intval($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getString()
|
|
||||||
{
|
|
||||||
return date('Y-m-d\TH:i:s.u', $this->value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Клетка таблицы
|
* Клетка таблицы
|
||||||
*/
|
*/
|
||||||
|
|
@ -68,15 +38,15 @@ class TableRow
|
||||||
/**
|
/**
|
||||||
* Таблица
|
* Таблица
|
||||||
*/
|
*/
|
||||||
class ExcelTable
|
class Excel_Table
|
||||||
{
|
{
|
||||||
static $index;
|
static $index;
|
||||||
private $name;
|
private $name;
|
||||||
private $style;
|
private $style;
|
||||||
protected $rows = array();
|
protected $rows = array();
|
||||||
|
|
||||||
protected $splitVertical = false;
|
protected $_splitVertical = false;
|
||||||
protected $splitHorizontal = false;
|
protected $_splitHorizontal = false;
|
||||||
|
|
||||||
function __construct()
|
function __construct()
|
||||||
{
|
{
|
||||||
|
|
@ -94,7 +64,8 @@ class ExcelTable
|
||||||
if(! isset($this->rows[$x])) {
|
if(! isset($this->rows[$x])) {
|
||||||
$this->rows[$x] = new TableRow();
|
$this->rows[$x] = new TableRow();
|
||||||
}
|
}
|
||||||
$this->rows[$x]->setCell($y, $value);
|
/*.TableRow.*/$row = $this->rows[$x];
|
||||||
|
$row->setCell($y, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -142,12 +113,13 @@ class ExcelTable
|
||||||
* @param $cell Номер столбца
|
* @param $cell Номер столбца
|
||||||
* @param $merge Количество клеток для обьединения
|
* @param $merge Количество клеток для обьединения
|
||||||
*/
|
*/
|
||||||
function setCellMerge ($row, $cell, $merge)
|
function setCellMerge($x, $cell, $merge)
|
||||||
{
|
{
|
||||||
assert(is_numeric($row) && $row > 0);
|
assert(is_numeric($x) && $x > 0);
|
||||||
assert(is_numeric($cell) && $cell > 0);
|
assert(is_numeric($cell) && $cell > 0);
|
||||||
|
|
||||||
$this->rows[$row]->cells[$cell]->merge = $merge;
|
/*.TableRow.*/$row = $this->rows[$x];
|
||||||
|
$row->cells[$cell]->merge = $merge;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -181,7 +153,8 @@ class ExcelTable
|
||||||
*/
|
*/
|
||||||
function getRows()
|
function getRows()
|
||||||
{
|
{
|
||||||
return max(array_keys($this->rows));
|
/*.array.*/$keys = array_keys($this->rows);
|
||||||
|
return max($keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -189,27 +162,26 @@ class ExcelTable
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
function getRowCells($row)
|
function getRowCells(TableRow $row)
|
||||||
{
|
{
|
||||||
return max(array_keys($row->cells));
|
/*.array.*/$keys = array_keys($row->cells);
|
||||||
|
return max($keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Разделяет таблицу на две части по вертикали
|
* Разделяет таблицу на две части по вертикали
|
||||||
* @param $n integer Количество столбцов слева
|
* @param $n integer Количество столбцов слева
|
||||||
*/
|
*/
|
||||||
function splitVertical($n)
|
function splitVertical($n) {
|
||||||
{
|
$this->_splitVertical = $n;
|
||||||
$this->splitVertical = $n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Разделяет таблицу на две части по горизонтали
|
* Разделяет таблицу на две части по горизонтали
|
||||||
* @param $n integer Количество столбцов сверху
|
* @param $n integer Количество столбцов сверху
|
||||||
*/
|
*/
|
||||||
function splitHorizontal($n)
|
function splitHorizontal($n) {
|
||||||
{
|
$this->_splitHorizontal = $n;
|
||||||
$this->splitHorizontal = $n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -218,8 +190,7 @@ class ExcelTable
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
function getColumns()
|
function getColumns() {
|
||||||
{
|
|
||||||
return max(array_map(array($this, 'getRowCells'), $this->rows));
|
return max(array_map(array($this, 'getRowCells'), $this->rows));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,7 +202,7 @@ class ExcelTable
|
||||||
/**
|
/**
|
||||||
* Генерация клетки таблицы (Переработать)
|
* Генерация клетки таблицы (Переработать)
|
||||||
*/
|
*/
|
||||||
function createCell ($ncell, XMLWriter $doc, $j, $value, $setIndex) {
|
function createCell (TableCell $ncell, XMLWriter $doc, $j, /*.any.*/$value, $setIndex) {
|
||||||
$doc->startElement("Cell");
|
$doc->startElement("Cell");
|
||||||
|
|
||||||
if ($ncell->style) {
|
if ($ncell->style) {
|
||||||
|
|
@ -291,7 +262,7 @@ class ExcelTable
|
||||||
$doc->writeAttribute('ss:Height', $this->rows[$i]->height);
|
$doc->writeAttribute('ss:Height', $this->rows[$i]->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
$nrow = $this->rows[$i];
|
/*.TableRow.*/$nrow = $this->rows[$i];
|
||||||
// Флаг индикатор подстановки номера столбца
|
// Флаг индикатор подстановки номера столбца
|
||||||
$setIndex = false;
|
$setIndex = false;
|
||||||
for ($j = 1; $j <= $columns; $j++) {
|
for ($j = 1; $j <= $columns; $j++) {
|
||||||
|
|
@ -321,117 +292,20 @@ class ExcelTable
|
||||||
$doc->writeAttribute('xmlns', 'urn:schemas-microsoft-com:office:excel');
|
$doc->writeAttribute('xmlns', 'urn:schemas-microsoft-com:office:excel');
|
||||||
|
|
||||||
$doc->writeElement('FrozenNoSplit');
|
$doc->writeElement('FrozenNoSplit');
|
||||||
if ($this->splitVertical) {
|
if ($this->_splitVertical) {
|
||||||
$doc->writeElement('SplitVertical', $this->splitVertical);
|
$doc->writeElement('SplitVertical', $this->_splitVertical);
|
||||||
$doc->writeElement('LeftColumnRightPane', $this->splitVertical);
|
$doc->writeElement('LeftColumnRightPane', $this->_splitVertical);
|
||||||
}
|
}
|
||||||
if ($this->splitHorizontal) {
|
if ($this->_splitHorizontal) {
|
||||||
$doc->writeElement('SplitHorizontal', $this->splitHorizontal);
|
$doc->writeElement('SplitHorizontal', $this->_splitHorizontal);
|
||||||
$doc->writeElement('TopRowBottomPane', $this->splitHorizontal);
|
$doc->writeElement('TopRowBottomPane', $this->_splitHorizontal);
|
||||||
}
|
}
|
||||||
if ($this->splitHorizontal && $this->splitVertical) {
|
if ($this->_splitHorizontal && $this->_splitVertical) {
|
||||||
$doc->writeElement('ActivePane', 0);
|
$doc->writeElement('ActivePane', 0);
|
||||||
} else if($this->splitHorizontal) {
|
} else if($this->_splitHorizontal) {
|
||||||
$doc->writeElement('ActivePane', 2);
|
$doc->writeElement('ActivePane', 2);
|
||||||
}
|
}
|
||||||
$doc->endElement();
|
$doc->endElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Документ
|
|
||||||
*/
|
|
||||||
class ExcelDocument {
|
|
||||||
static $ns = "urn:schemas-microsoft-com:office:spreadsheet";
|
|
||||||
private $table = array ();
|
|
||||||
protected $styles = array();
|
|
||||||
|
|
||||||
function addTable($table) {
|
|
||||||
$this->table [] = $table;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавление стиля к документу
|
|
||||||
* @param $name string Имя стиля
|
|
||||||
* @param $values array Параметры стиля
|
|
||||||
* @param $type Тип стиля
|
|
||||||
*/
|
|
||||||
function setStyle ($name, array $values, $type = 'Interior')
|
|
||||||
{
|
|
||||||
if(!isset($this->styles[$name])) {
|
|
||||||
$this->styles[$name] = array();
|
|
||||||
}
|
|
||||||
$this->styles[$name][$type] = $values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Генерация стилей
|
|
||||||
*/
|
|
||||||
private function createStyles (XMLWriter $doc) {
|
|
||||||
$doc->startElement('Styles');
|
|
||||||
foreach ($this->styles as $name => $sn) {
|
|
||||||
$doc->startElement('Style');
|
|
||||||
$doc->writeAttribute('ss:ID', $name);
|
|
||||||
foreach ($sn as $type => $s) {
|
|
||||||
// Стиль Borders - составной
|
|
||||||
if ($type == 'Borders') {
|
|
||||||
$doc->startElement('Borders');
|
|
||||||
foreach ($s as $border) {
|
|
||||||
$doc->startElement('Border');
|
|
||||||
foreach ($border as $key => $value) {
|
|
||||||
$doc->writeAttribute('ss:' . $key, $value);
|
|
||||||
}
|
|
||||||
$doc->endElement();
|
|
||||||
}
|
|
||||||
$doc->endElement();
|
|
||||||
} else {
|
|
||||||
$doc->startElement($type);
|
|
||||||
foreach ($s as $key => $value) {
|
|
||||||
$doc->writeAttribute('ss:' . $key, $value);
|
|
||||||
}
|
|
||||||
$doc->endElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$doc->endElement();
|
|
||||||
}
|
|
||||||
$doc->endElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразует переводы строки в спец символы
|
|
||||||
*/
|
|
||||||
function clean ($s) {
|
|
||||||
assert(is_string($s));
|
|
||||||
|
|
||||||
return strtr($s, array ("\n" => ' '));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Сохраняет таблицу в формате Office 2003 XML
|
|
||||||
* http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats
|
|
||||||
*/
|
|
||||||
function save($filename)
|
|
||||||
{
|
|
||||||
$doc = new xmlWriter();
|
|
||||||
$doc->openURI($filename);
|
|
||||||
$doc->setIndent(false);
|
|
||||||
$doc->startDocument('1.0','utf-8');
|
|
||||||
$doc->startElement('Workbook');
|
|
||||||
$doc->writeAttribute('xmlns', self::$ns);
|
|
||||||
$doc->writeAttribute('xmlns:ss', self::$ns);
|
|
||||||
|
|
||||||
$this->createStyles($doc);
|
|
||||||
|
|
||||||
foreach ($this->table as $table) {
|
|
||||||
if ($table instanceof ExcelTable) {
|
|
||||||
$table->createTable($doc);
|
|
||||||
} else {
|
|
||||||
$table_data = call_user_func($table);
|
|
||||||
$table_data->createTable($doc);
|
|
||||||
unset($table_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$doc->endElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
/**
|
/**
|
||||||
* Фильтр действий
|
* Фильтр действий
|
||||||
*/
|
*/
|
||||||
class ActionAccess
|
class Filter_ActionAccess
|
||||||
{
|
{
|
||||||
public $access = array();
|
public $access = array();
|
||||||
|
public $processor;
|
||||||
|
|
||||||
function __construct($processor)
|
function __construct(/*.Filter_Filter.*/$processor) {
|
||||||
{
|
|
||||||
$this->processor = $processor;
|
$this->processor = $processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,14 +17,12 @@ class ActionAccess
|
||||||
* !! Реализация класса проверки действий не должна быть внутри Контроллера!!!
|
* !! Реализация класса проверки действий не должна быть внутри Контроллера!!!
|
||||||
* Информация о доступе может быть в файле, базе данных и т.д.
|
* Информация о доступе может быть в файле, базе данных и т.д.
|
||||||
*/
|
*/
|
||||||
function checkAction($action)
|
function checkAction($action) {
|
||||||
{
|
|
||||||
// Импликация !! http://ru.wikipedia.org/wiki/Импликация
|
// Импликация !! http://ru.wikipedia.org/wiki/Импликация
|
||||||
return (!isset($this->access[$action]) || in_array(UserAccess::$access, $this->access[$action]));
|
return (!isset($this->access[$action]) || in_array(Filter_UserAccess::$access, $this->access[$action]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(HTTPRequest $request)
|
function execute(HttpRequest $request) {
|
||||||
{
|
|
||||||
$action = $request->getAction();
|
$action = $request->getAction();
|
||||||
if(! $this->checkAction($action)) {
|
if(! $this->checkAction($action)) {
|
||||||
$request->set('action', 'index');
|
$request->set('action', 'index');
|
||||||
|
|
@ -1,25 +1,21 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'core/path.php';
|
class Filter_ActionLogger
|
||||||
|
|
||||||
class ActionLogger
|
|
||||||
{
|
{
|
||||||
public $before = array ();
|
public $before = array();
|
||||||
public $file;
|
public $file;
|
||||||
public $action;
|
public $action;
|
||||||
public $processor;
|
public $processor;
|
||||||
|
|
||||||
function __construct($processor)
|
function __construct(/*.Filter_Filter.*/$processor) {
|
||||||
{
|
|
||||||
$this->processor = $processor;
|
$this->processor = $processor;
|
||||||
$this->file = fopen(Shortcut::getUrl('access.log'), "a");
|
$this->file = fopen(Shortcut::getUrl('access.log'), "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(HTTPRequest $request)
|
function execute(HttpRequest $request) {
|
||||||
{
|
|
||||||
$action = $request->getAction();
|
$action = $request->getAction();
|
||||||
if(in_array($action, $this->before)) {
|
if(in_array($action, $this->before)) {
|
||||||
fwrite($this->file, "time: " . date("r", time()) . " query: ". json::encode(array_merge($_POST, $_GET)) . " by: " . UserAccess::$name . "\n");
|
fwrite($this->file, "time: " . date("r", time()) . " query: ". json_encode(array_merge($_POST, $_GET)) . " by: " . Filter_UserAccess::$name . "\n");
|
||||||
}
|
}
|
||||||
return $this->processor->execute($request);
|
return $this->processor->execute($request);
|
||||||
}
|
}
|
||||||
52
src/Filter/Authorization.php
Normal file
52
src/Filter/Authorization.php
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Filter_Authorization {
|
||||||
|
const SESSION_BROWSER_SIGN_SECRET = '@w3dsju45Msk#';
|
||||||
|
const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign';
|
||||||
|
|
||||||
|
static function isLogged() {
|
||||||
|
if (session_status() == PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
$hash = self::getBrowserSign();
|
||||||
|
// Если $hash не совпадает $_SESSION['hash'] то удаляем сессию
|
||||||
|
if (isset($_SESSION ['access']) && isset($_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME])) {
|
||||||
|
|
||||||
|
if ($hash == $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME]) {
|
||||||
|
// UserAccess::getUserById($_SESSION ['access']); // Поиск по идентификатору
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function enter($id)
|
||||||
|
{
|
||||||
|
// $db->executeQuery("UPDATE visitor SET sid = '' WHERE id_visitor = " . $result->getInt('id_user'));
|
||||||
|
session_register("access");
|
||||||
|
session_register("time");
|
||||||
|
|
||||||
|
// $_SESSION ["group"] = $result->getInt('access');
|
||||||
|
$_SESSION ["access"] = $id; // id_user
|
||||||
|
$_SESSION [self::SESSION_BROWSER_SIGN_KEYNAME] = self::getBrowserSign();
|
||||||
|
$_SESSION ["time"] = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getBrowserSign()
|
||||||
|
{
|
||||||
|
$rawSign = self::SESSION_BROWSER_SIGN_SECRET;
|
||||||
|
// $signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING');
|
||||||
|
$signParts = array();
|
||||||
|
|
||||||
|
foreach ($signParts as $signPart) {
|
||||||
|
$rawSign .= '::' . (isset($_SERVER[$signPart]) ? $_SERVER[$signPart] : 'none');
|
||||||
|
}
|
||||||
|
return md5($rawSign);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function logout() {
|
||||||
|
session_destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
/**
|
/**
|
||||||
* Попытка реализовать фильтр для запросов
|
* Попытка реализовать фильтр для запросов
|
||||||
*/
|
*/
|
||||||
class Filter
|
class Filter_Filter
|
||||||
{
|
{
|
||||||
public $processor;
|
public $processor;
|
||||||
public function __construct($processor)
|
public function __construct(/*.Filter_Filter.*/$processor)
|
||||||
{
|
{
|
||||||
$this->processor = $processor;
|
$this->processor = $processor;
|
||||||
}
|
}
|
||||||
|
|
@ -16,9 +16,9 @@ class Filter
|
||||||
return $this->processor->execute($request);
|
return $this->processor->execute($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getView($name)
|
public function getView($name, $class = 'View_Top')
|
||||||
{
|
{
|
||||||
return $this->processor->getView($name);
|
return $this->processor->getView($name, $class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConnection()
|
public function getConnection()
|
||||||
177
src/Filter/Login.php
Normal file
177
src/Filter/Login.php
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Фильтр для проверки авторизации
|
||||||
|
*
|
||||||
|
* action: login(password, login)
|
||||||
|
* action: logout()
|
||||||
|
*/
|
||||||
|
// В класс авторизации передавать обьект для управления пользователем
|
||||||
|
// Вынести в отдельный файл
|
||||||
|
class Filter_Login extends Filter_Filter
|
||||||
|
{
|
||||||
|
const SESSION_BROWSER_SIGN_SECRET = '@w3dsju45Msk#';
|
||||||
|
const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign';
|
||||||
|
public $mode = 'ajax';
|
||||||
|
|
||||||
|
//AJAX-Реквесты для которых не требуется авторизация, потребовалось для сбора статистики
|
||||||
|
public $whiteRequestList = array(array('module' => "requiredcontent", "action" => "getcount"));
|
||||||
|
/**
|
||||||
|
* Проверка авторизации
|
||||||
|
* @return Boolean Авторизовани пользователь или нет
|
||||||
|
*/
|
||||||
|
public function isLoggin(HttpRequest $request)
|
||||||
|
{
|
||||||
|
// Авторизация
|
||||||
|
session_start();
|
||||||
|
$db = $this->getConnection();
|
||||||
|
Filter_UserAccess::setUp($db); // Соединение
|
||||||
|
switch ($request->getAction()) {
|
||||||
|
// Авторизация по постоянному паролю
|
||||||
|
case 'login':
|
||||||
|
$login = $request->get('login');
|
||||||
|
$password = $request->get('password');
|
||||||
|
|
||||||
|
$result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину
|
||||||
|
if ($result) {
|
||||||
|
$userPassword = $result->getString('password');
|
||||||
|
if (Filter_UserAccess::$access == 'site_root' && defined('PARENT_PATH')) {
|
||||||
|
$s = new Settings(PARENT_PATH . '/settings.json');
|
||||||
|
$s->read();
|
||||||
|
$dsn = $s->readKey(array('system', 'dsn'));
|
||||||
|
|
||||||
|
$db = Database::getConnection($dsn);
|
||||||
|
$user = $db->fetchOneArray("SELECT * FROM users WHERE login = :login", ['login' => $login]);
|
||||||
|
$userPassword = $user['password'];
|
||||||
|
}
|
||||||
|
// Извлечнеие пользователя из родительской CMS, для проверки пароля
|
||||||
|
if (md5($password) == $userPassword) { // password
|
||||||
|
$this->enter($db, $result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$request->set('error', true);
|
||||||
|
break;
|
||||||
|
case 'logout': // Выход
|
||||||
|
session_destroy();
|
||||||
|
break;
|
||||||
|
// Вход по временному паролю
|
||||||
|
case 'enter':
|
||||||
|
$login = $request->get('login');
|
||||||
|
$password = $request->get('sid');
|
||||||
|
$result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину
|
||||||
|
if ($result) {
|
||||||
|
$temp = md5($result->getString('password') . $result->getString('login') . $result->getString('sid'));
|
||||||
|
if ($password == $temp) {
|
||||||
|
$this->enter($db, $result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$hash = $this->getBrowserSign();
|
||||||
|
// Если $hash не совпадает $_SESSION['hash'] то удаляем сессию
|
||||||
|
if (isset($_SESSION ['access']) && isset($_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME])) {
|
||||||
|
if ($hash == $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME]) {
|
||||||
|
$this->user = $user = Filter_UserAccess::getUserById($_SESSION['access']); // Поиск по идентификатору
|
||||||
|
if ($user && isset($_SESSION['random']) && ($user->get('sid') == $_SESSION['random'])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
session_destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getBrowserSign()
|
||||||
|
{
|
||||||
|
$rawSign = self::SESSION_BROWSER_SIGN_SECRET;
|
||||||
|
//$signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING');
|
||||||
|
$signParts = array();
|
||||||
|
|
||||||
|
foreach ($signParts as $signPart) {
|
||||||
|
$rawSign .= '::' . (isset($_SERVER[$signPart]) ? $_SERVER[$signPart] : 'none');
|
||||||
|
}
|
||||||
|
return md5($rawSign);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function enter($db, $result)
|
||||||
|
{
|
||||||
|
$this->user = $result;
|
||||||
|
$random = rand(0, 1024 * 1024);
|
||||||
|
$db->executeQuery("UPDATE users SET sid = '$random' WHERE id_user = " . $result->getInt('id_user'));
|
||||||
|
|
||||||
|
$_SESSION["group"] = $result->getInt('access');
|
||||||
|
$_SESSION["access"] = $result->getInt('id_user'); // id_user
|
||||||
|
$_SESSION["random"] = $random; // id_user
|
||||||
|
$_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME] = $this->getBrowserSign();
|
||||||
|
$_SESSION["time"] = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(HttpRequest $request)
|
||||||
|
{
|
||||||
|
$logged = $this->isLoggin($request);
|
||||||
|
if ($request->get('action') == 'user_access') {
|
||||||
|
if ($logged) {
|
||||||
|
$result = array();
|
||||||
|
$result['fullname'] = $this->user->getString('patronymic') . " " . $this->user->getString('firstname');
|
||||||
|
$result['email'] = $this->user->getString('email');
|
||||||
|
$result['site'] = 187;
|
||||||
|
$result['hash'] = sha1(self::SESSION_BROWSER_SIGN_SECRET . $this->user->getString('email'));
|
||||||
|
return json_encode($result);
|
||||||
|
} else {
|
||||||
|
return json_encode("NOT AUTHORIZED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->get('action') == 'relogin') {
|
||||||
|
if ($logged) {
|
||||||
|
return json_encode(array('result' => 'ok', 'message' => "Авторизация успешна"));
|
||||||
|
} else {
|
||||||
|
return json_encode(array('result' => 'fail', 'message' => "Неправильное имя пользователя или пароль"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$logged) {
|
||||||
|
// Параметры при неправильной авторизации
|
||||||
|
// Действия по умолчанию !! Возможно переход на форму регистрации
|
||||||
|
if ($request->get('mode') == 'ajax') {
|
||||||
|
if (!$this->requestIsWhite($request, $this->whiteRequestList)) {
|
||||||
|
return json_encode(array('result' => 'fail', 'message' =>"NOT_AUTHORIZED"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$request->set('module', 'login');
|
||||||
|
$request->set('mode', $this->mode);
|
||||||
|
}
|
||||||
|
} else if (isset($_SERVER['HTTP_REFERER'])) {
|
||||||
|
$arr = array();
|
||||||
|
parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $arr);
|
||||||
|
if (isset($arr['back_page']) && $request->get('mode') != 'ajax') {
|
||||||
|
$request->redirect($arr['back_page']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$text = $this->processor->execute($request);
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------
|
||||||
|
* Проверка на попадание реквеста в белый список
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function requestIsWhite(Collection $request, $whiteRequestList){
|
||||||
|
$module = $request->get('module');
|
||||||
|
$action = $request->get('action');
|
||||||
|
foreach ($whiteRequestList as $whiteRequest) {
|
||||||
|
if ($module == $whiteRequest['module'] && $action == $whiteRequest['action']) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
@ -19,12 +16,12 @@ class UserAccess
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setUp($db)
|
public static function setUp(Database $db)
|
||||||
{
|
{
|
||||||
self::$db = $db;
|
self::$db = $db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getUserByQuery($stmt)
|
public static function getUserByQuery(Database_Statement $stmt)
|
||||||
{
|
{
|
||||||
global $GROUPS;
|
global $GROUPS;
|
||||||
$result = $stmt->executeQuery();
|
$result = $stmt->executeQuery();
|
||||||
|
|
@ -65,7 +62,7 @@ class UserAccess
|
||||||
$time = time();
|
$time = time();
|
||||||
if ($time - $lasttime > self::LIFE_TIME) return null; // Вышло время сессии
|
if ($time - $lasttime > self::LIFE_TIME) return null; // Вышло время сессии
|
||||||
$id = self::$id;
|
$id = self::$id;
|
||||||
$stmt = self::$db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время последнего обращения входа
|
self::$db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время последнего обращения входа
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
394
src/Form/Form.php
Normal file
394
src/Form/Form.php
Normal file
|
|
@ -0,0 +1,394 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Элемент формы
|
||||||
|
*/
|
||||||
|
class TField
|
||||||
|
{
|
||||||
|
public $hidden = false;
|
||||||
|
public $name;
|
||||||
|
public $label; // Метка поля
|
||||||
|
public $value; // Значение поля
|
||||||
|
public $type = ""; // Каждому типу элемента соответствует макрос TAL
|
||||||
|
public $error_msg = null;
|
||||||
|
public $default = null;
|
||||||
|
public $error = false;
|
||||||
|
public $require = false;
|
||||||
|
public $hint = null;
|
||||||
|
// Блоки (Убрать в отдельный класс!!!)
|
||||||
|
public $_title = array();
|
||||||
|
public $description = "";
|
||||||
|
public $alias = array();
|
||||||
|
|
||||||
|
public function __construct ($input = array(), $factory = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->default = null;
|
||||||
|
if (isset($input['validate'])) {
|
||||||
|
$this->require = strpos($input['validate'], 'require') !== false;
|
||||||
|
}
|
||||||
|
// Инициализация свойст обьетка
|
||||||
|
foreach (array('label', 'name', 'type', 'description') as $name) {
|
||||||
|
if (isset($input[$name])) {
|
||||||
|
$this->$name = $input[$name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setValue(/*.any.*/$value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId()
|
||||||
|
{
|
||||||
|
return $this->name . '_label';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поле ввода Input
|
||||||
|
*/
|
||||||
|
class TInput extends TField {
|
||||||
|
}
|
||||||
|
|
||||||
|
class TCheckbox extends TField
|
||||||
|
{
|
||||||
|
public $checked = false;
|
||||||
|
function setValue($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
$this->checked = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TSelect extends TField
|
||||||
|
{
|
||||||
|
public $options = array();
|
||||||
|
|
||||||
|
public function __construct ($input, $factory) {
|
||||||
|
parent::__construct($input, $factory);
|
||||||
|
|
||||||
|
if ($factory != null) {
|
||||||
|
$factory->create($this, $input);
|
||||||
|
} else if (isset($input['options.pair'])) {
|
||||||
|
$this->options = $this->optionsPair($input['options.pair']);
|
||||||
|
} else if (isset($input['options'])) {
|
||||||
|
$this->options = $input['options'];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->options as &$option) {
|
||||||
|
$option['selected'] = false;
|
||||||
|
$option['class'] = (isset($option['class'])) ? $option['class'] : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function optionsPair($list, $selected = false) {
|
||||||
|
$result = array();
|
||||||
|
foreach ($list as $key => $value) {
|
||||||
|
$result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выбор из одного элемента
|
||||||
|
*/
|
||||||
|
class TSelectOne extends TSelect
|
||||||
|
{
|
||||||
|
function setValue($value)
|
||||||
|
{
|
||||||
|
// Установить selected у options
|
||||||
|
$this->value = $value;
|
||||||
|
foreach ($this->options as &$option) {
|
||||||
|
$option['selected'] = ($option['value'] == $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TSelectMany extends TSelect
|
||||||
|
{
|
||||||
|
function setValue($value)
|
||||||
|
{
|
||||||
|
// Установить selected у options
|
||||||
|
if (!is_array($value)) { $value = array($value); }
|
||||||
|
$this->value = $value;
|
||||||
|
foreach ($this->options as &$option) {
|
||||||
|
$option['selected'] = (in_array($option['value'], $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TQuestionType extends TSelect
|
||||||
|
{
|
||||||
|
function setValue($value)
|
||||||
|
{
|
||||||
|
// Установить selected у options
|
||||||
|
$this->value = $value;
|
||||||
|
foreach ($this->options as &$option) {
|
||||||
|
$option['selected'] = ($option['value'] == $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поле с датой
|
||||||
|
*/
|
||||||
|
class TDate extends TField
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поле с цветом
|
||||||
|
*/
|
||||||
|
class TColor extends TField
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Текстовое поле
|
||||||
|
*/
|
||||||
|
class TTextArea extends TField
|
||||||
|
{
|
||||||
|
function setValue($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поле для ввода пароля
|
||||||
|
*/
|
||||||
|
class TSecret extends TField
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class TUpload extends TField
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class THidden extends TInput {
|
||||||
|
public $hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TComponentBrowserInput extends TInput
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* При рендеринге каждому классу соответствует шаблон (см. themes/maxim/templates/macros.html)
|
||||||
|
*/
|
||||||
|
class TDateTime extends TInput {
|
||||||
|
}
|
||||||
|
|
||||||
|
class OptionFactory {
|
||||||
|
public $db;
|
||||||
|
|
||||||
|
function __construct($db) {
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
function create(TSelect $field, $input) {
|
||||||
|
if (isset($input['options.resid'])) {
|
||||||
|
$type = $input['options.resid'];
|
||||||
|
|
||||||
|
$res = new Model_Resources($this->db);
|
||||||
|
$field->options = $this->optionsArray('id_section', 'title', $res->getSubsections('', $type));
|
||||||
|
|
||||||
|
} else if (isset($input['options.res'])) {
|
||||||
|
$type = $input['options.res'];
|
||||||
|
|
||||||
|
$res = new Model_Resources($this->db);
|
||||||
|
$field->options = $this->optionsArray('path', 'title', $res->getSubsections('', $type));
|
||||||
|
|
||||||
|
} else if (isset($input['options.all_res'])) {
|
||||||
|
$type = $input['options.all_res'];
|
||||||
|
|
||||||
|
$res = new Model_Resources($this->db);
|
||||||
|
$field->options = $this->optionsArray('id_resource', 'subtitle', $res->getAllResource($type));
|
||||||
|
|
||||||
|
} else if (isset($input['options.db'])) {
|
||||||
|
list($table, $keyvalue) = explode(":", $input['options.db']);
|
||||||
|
list($key, $value) = explode(",", $keyvalue);
|
||||||
|
|
||||||
|
$field->options = $this->optionsDB($key, $value, $this->db->executeQuery("SELECT * FROM $table"));
|
||||||
|
} elseif (isset($input['options.pair'])) {
|
||||||
|
$field->options = $this->optionsPair($input['options.pair']);
|
||||||
|
} else {
|
||||||
|
$field->options = $input['options'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function optionsDB($key, $val, $res) {
|
||||||
|
$result = array();
|
||||||
|
while($res->next()) {
|
||||||
|
$result[] = array('value' => $res->getInt($key), 'name' => $res->getString($val));
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function optionsArray($key, $val, $res) {
|
||||||
|
$result = array();
|
||||||
|
foreach($res as $item) {
|
||||||
|
$result[] = array('value' => $item->{$key}, 'name' => $item->{$val});
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function optionsPair($list, $selected = false) {
|
||||||
|
$result = array();
|
||||||
|
foreach ($list as $key => $value) {
|
||||||
|
$result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Форма для ввода
|
||||||
|
*/
|
||||||
|
class Form_Form extends View_View {
|
||||||
|
public $field = array();
|
||||||
|
public $action = "";
|
||||||
|
public $method = 'post';
|
||||||
|
public $header;
|
||||||
|
|
||||||
|
protected $replace;
|
||||||
|
protected $before;
|
||||||
|
|
||||||
|
public $_title = array();
|
||||||
|
public $alias = array();
|
||||||
|
public $constructor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Строим форму по ее структуре. Каждому типу соответствует определенный класс.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->constructor = array(
|
||||||
|
'input' => 'TInput',
|
||||||
|
'inputreq' => 'TInput', // input с проверкой на заполненность
|
||||||
|
|
||||||
|
'date' => 'TDate',
|
||||||
|
'datereq' => 'TDate',
|
||||||
|
'datetime' => 'TDateTime',
|
||||||
|
|
||||||
|
'color' => 'TColor',
|
||||||
|
'textarea' => 'TTextArea',
|
||||||
|
'text' => 'TTextArea',
|
||||||
|
'multiselect' => 'TSelectMany',
|
||||||
|
// 'selectmany' => 'TSelectMany',
|
||||||
|
'select1' => 'TSelectOne',
|
||||||
|
'select' => 'TSelectOne',
|
||||||
|
'questiontype'=> 'TQuestionType',
|
||||||
|
'secret' => 'TSecret',
|
||||||
|
'upload' => 'TUpload',
|
||||||
|
'image' => 'TUpload',
|
||||||
|
'checkbox' => 'TCheckbox',
|
||||||
|
'checkmany' => 'TSelectMany',
|
||||||
|
'hidden' => 'THidden',
|
||||||
|
'radio' => 'TSelectOne',
|
||||||
|
'filebrowser' => 'TComponentBrowserInput',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId()
|
||||||
|
{
|
||||||
|
return '_form_edit';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFieldClass($name, $class)
|
||||||
|
{
|
||||||
|
$this->constructor [$name] = $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет одно поле ввода на форму
|
||||||
|
*/
|
||||||
|
public function addField(array $init, $factory = null)
|
||||||
|
{
|
||||||
|
assert(isset($init['type']));
|
||||||
|
assert(isset($init['name']));
|
||||||
|
|
||||||
|
// print_r($init);
|
||||||
|
|
||||||
|
$constructor = $this->constructor[$init['type']];
|
||||||
|
$el = new $constructor($init, $factory);
|
||||||
|
if (!$el->type) {
|
||||||
|
$el->type = $init['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($init['hint'])) {
|
||||||
|
$el->hint = $init['hint'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->field [$init['name']] = $el;
|
||||||
|
return $el;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет список полей для формы
|
||||||
|
* @param array $list
|
||||||
|
*/
|
||||||
|
public function addFieldList(array $list, $factory = null)
|
||||||
|
{
|
||||||
|
foreach ($list as $init) {
|
||||||
|
$this->addField($init, $factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает ошибки после проверки
|
||||||
|
*/
|
||||||
|
function setError(Validator_Validator $validator)
|
||||||
|
{
|
||||||
|
foreach ($validator->getErrorMsg() as $name => $error)
|
||||||
|
{
|
||||||
|
$this->field[$name]->error = true;
|
||||||
|
$this->field[$name]->error_msg = $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFieldError($name, $message)
|
||||||
|
{
|
||||||
|
$this->field[$name]->error = true;
|
||||||
|
$this->field[$name]->error_msg = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает значения из масива
|
||||||
|
*/
|
||||||
|
function setValues(HttpRequest $request) {
|
||||||
|
foreach ($this->field as $key => $el) {
|
||||||
|
$value = $request->getRawData($this->method, $key);
|
||||||
|
$this->field[$key]->setValue($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Заполняет форму данными из обьекта
|
||||||
|
* @param object $data
|
||||||
|
* @param array $schema Связь между элементами формы и свойствами обьекта
|
||||||
|
*/
|
||||||
|
public function fill($data, array $schema)
|
||||||
|
{
|
||||||
|
foreach ($schema as $key => $conv) {
|
||||||
|
list($value, $type) = $conv;
|
||||||
|
$this->field [$key]->setValue(call_user_func(array('Primitive', 'from_' . $type), $data->$value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set($name, $value)
|
||||||
|
{
|
||||||
|
$this->field[$name]->setValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function execute()
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
* http://www.alternateinterior.com/2006/09/a-viewstate-for-php.html
|
* http://www.alternateinterior.com/2006/09/a-viewstate-for-php.html
|
||||||
* Управление состоянием между страницами
|
* Управление состоянием между страницами
|
||||||
*/
|
*/
|
||||||
class ViewState // extends Collection
|
class Form_ViewState // extends Collection
|
||||||
{
|
{
|
||||||
private $values = array();
|
private $values = array();
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ class ViewState // extends Collection
|
||||||
$this->values[$name] = $value;
|
$this->values[$name] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get()
|
function get($_rest)
|
||||||
{
|
{
|
||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
$result = $this->values;
|
$result = $this->values;
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'core/safecollection.php';
|
|
||||||
require_once 'core/session.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Неверный запрос
|
* Неверный запрос
|
||||||
*/
|
*/
|
||||||
|
|
@ -13,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.
|
||||||
|
|
@ -27,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Array Acces Interface */
|
function session(Session $value = null)
|
||||||
function offsetExists($offset)
|
|
||||||
{
|
{
|
||||||
|
if ($value) {
|
||||||
|
$this->_session = $value;
|
||||||
|
}
|
||||||
|
return $this->_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
function offsetGet($offset)
|
function set($key, /*.any.*/$value)
|
||||||
{
|
{
|
||||||
|
return parent::get('data')->set($key, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function offsetSet($offset, $value)
|
function export($key = 'data')
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetUnset($offset)
|
|
||||||
{
|
{
|
||||||
|
return parent::get($key)->export();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear()
|
function clear()
|
||||||
|
|
@ -128,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) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
13
src/Layout/Empty.php
Normal file
13
src/Layout/Empty.php
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Самый простой макет
|
||||||
|
*/
|
||||||
|
class Layout_Empty extends Filter_Filter
|
||||||
|
{
|
||||||
|
function execute(HttpRequest $request)
|
||||||
|
{
|
||||||
|
$text = $this->processor->execute($request);
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
@ -69,8 +69,7 @@ class LayoutManager extends Filter
|
||||||
if (call_user_func($condition[0], $request)) {
|
if (call_user_func($condition[0], $request)) {
|
||||||
$layout = $condition[1];
|
$layout = $condition[1];
|
||||||
$view = $layout->execute($request);
|
$view = $layout->execute($request);
|
||||||
|
if (is_object($view)) {
|
||||||
if ($view instanceof View_Composite) {
|
|
||||||
echo $view->render();
|
echo $view->render();
|
||||||
} else {
|
} else {
|
||||||
echo $view;
|
echo $view;
|
||||||
|
|
@ -81,13 +80,3 @@ class LayoutManager extends Filter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Самый простой макет
|
|
||||||
*/
|
|
||||||
class LayoutNone extends Filter
|
|
||||||
{
|
|
||||||
function execute(HttpRequest $request)
|
|
||||||
{
|
|
||||||
return $this->processor->execute($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -71,11 +69,6 @@ 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,11 +198,10 @@ 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('Невозможно отправить почту');
|
file_put_contents(Path::resolveFile("send.eml"), $this->eml());
|
||||||
// require_once "core/path.php";
|
throw new Exception('Невозможно отправить почту');
|
||||||
// file_put_contents(Path::resolveFile("data/email/send.eml"), $this->eml());
|
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
@ -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++) {
|
||||||
430
src/Path.php
Normal file
430
src/Path.php
Normal file
|
|
@ -0,0 +1,430 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс для работы с папками и путями
|
||||||
|
* Для итерации над файлами возможно лучше использовать SPL
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Path
|
||||||
|
{
|
||||||
|
const SEPARATOR = "/";
|
||||||
|
|
||||||
|
protected $path = array();
|
||||||
|
protected $url = array();
|
||||||
|
protected $absolute = false;
|
||||||
|
|
||||||
|
public function __construct($path)
|
||||||
|
{
|
||||||
|
// assert(is_string($path));
|
||||||
|
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает расширение файла
|
||||||
|
*
|
||||||
|
* @param string $fileName Полное имя файла
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function getExtension($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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Полное имя файла без расширения
|
||||||
|
*
|
||||||
|
* @param string $fileName Имя файла
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function skipExtension($fileName)
|
||||||
|
{
|
||||||
|
assert(is_string($fileName));
|
||||||
|
|
||||||
|
$path = pathinfo($fileName);
|
||||||
|
if ($path['dirname'] == ".") {
|
||||||
|
return $path['filename'];
|
||||||
|
} else {
|
||||||
|
return self::join($path['dirname'], $path['filename']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает имя файла без расширения
|
||||||
|
*
|
||||||
|
* @param string $fileName Полное имя файла
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function getFileName($fileName)
|
||||||
|
{
|
||||||
|
assert(is_string($fileName));
|
||||||
|
|
||||||
|
return pathinfo($fileName, PATHINFO_FILENAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Преобразует строку путя в массив
|
||||||
|
*
|
||||||
|
* @param string $path Путь
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function fromString ($path)
|
||||||
|
{
|
||||||
|
assert(is_string($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 static function optimize($path) //
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
foreach ($path as $n) {
|
||||||
|
switch ($n) {
|
||||||
|
// Может быть относительным или абсолютным путем
|
||||||
|
case "": break;
|
||||||
|
case ".": break;
|
||||||
|
case "..":
|
||||||
|
if (count($result) > 0) { array_pop($result); break; }
|
||||||
|
default:
|
||||||
|
array_push($result, $n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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'] : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Преобразует путь в строку
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
$result = (($this->absolute) ? '/' : '') . implode(self::SEPARATOR, $this->path);
|
||||||
|
$this->url['path'] = $result;
|
||||||
|
return self::makeUrl($this->url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет является ли папка родительской для другой папки
|
||||||
|
*
|
||||||
|
* @parma Path $path
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
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]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function _isParent($path1, $path2)
|
||||||
|
{
|
||||||
|
$path = new Path($path1);
|
||||||
|
return $path->isParent(new Path($path2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Находит путь относительно текущего путя
|
||||||
|
*
|
||||||
|
* @param string $name Полный путь к файлу
|
||||||
|
*
|
||||||
|
* @return string Относительный путь к файлу
|
||||||
|
*/
|
||||||
|
public function relPath($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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вычисляет относительный путь в виде строки
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обьединяет строки в путь соединяя необходимым разделителем
|
||||||
|
* fixme не обрабатывает параметры урла, решение Path::join(SITE_WWW_PATH) . '?param=pampam'
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function join($_rest)
|
||||||
|
{
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подбирает новое временное имя для файла
|
||||||
|
*
|
||||||
|
* @param string $dst Предпологаемое имя файла
|
||||||
|
*
|
||||||
|
* @return string Новое имя файла
|
||||||
|
*/
|
||||||
|
static function resolveFile($dst)
|
||||||
|
{
|
||||||
|
$i = 0;
|
||||||
|
$file = self::skipExtension($dst);
|
||||||
|
$suffix = self::getExtension($dst);
|
||||||
|
$temp = $dst;
|
||||||
|
while (file_exists($temp)) {
|
||||||
|
$i ++;
|
||||||
|
$temp = $file . "." . $i . "." . $suffix;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обьединяет строки в путь соединяя необходимым разделителем
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Использовать 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
119
src/Primitive.php
Normal file
119
src/Primitive.php
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Преобразование типов !!! Пересмотреть использование классов!!
|
||||||
|
* Класс преобразования типа значения поля класса в тип поля таблицы
|
||||||
|
* @package system
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Primitive {
|
||||||
|
// varchar
|
||||||
|
public static function to_varchar($value)
|
||||||
|
{
|
||||||
|
return ((string) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function from_varchar($value)
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int
|
||||||
|
public static function to_bool($value)
|
||||||
|
{
|
||||||
|
return filter_var($value, FILTER_VALIDATE_BOOLEAN);//(int)((bool) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function from_bool($value)
|
||||||
|
{
|
||||||
|
return ((bool) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// int
|
||||||
|
public static function to_int($value)
|
||||||
|
{
|
||||||
|
return ((int) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function from_int($value)
|
||||||
|
{
|
||||||
|
return ((string) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// date
|
||||||
|
public static function to_date($value)
|
||||||
|
{
|
||||||
|
$result = 0;
|
||||||
|
$tmp = explode("/", $value, 3);
|
||||||
|
if (!empty($tmp)) {
|
||||||
|
if (count($tmp) != 3) return $result;
|
||||||
|
|
||||||
|
$year = intval($tmp[2]);
|
||||||
|
$month = intval($tmp[1]);
|
||||||
|
$day = intval($tmp[0]);
|
||||||
|
|
||||||
|
if ($month != 0 && $day != 0 && $year != 0) {
|
||||||
|
if (checkdate($month, $day, $year)) {
|
||||||
|
return mktime(0, 0, 0, $month, $day, $year);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function to_datetime($value)
|
||||||
|
{
|
||||||
|
$result = 0;
|
||||||
|
|
||||||
|
$tmp = array();
|
||||||
|
if (preg_match('/(\d+)-(\d+)-(\d+)T(\d+):(\d+)Z/', $value, $tmp)) {
|
||||||
|
if (checkdate($tmp[2], $tmp[3], $tmp[1])) {
|
||||||
|
$result = mktime($tmp[4], $tmp[5], 0, $tmp[2], $tmp[3], $tmp[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function from_date($value)
|
||||||
|
{
|
||||||
|
if ($value > 0) {
|
||||||
|
return date("d/m/Y", $value);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function from_datetime($value)
|
||||||
|
{
|
||||||
|
if ($value > 0) {
|
||||||
|
return date("Y-m-d\TH:i\Z", $value);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// secure
|
||||||
|
public static function to_secure($value)
|
||||||
|
{
|
||||||
|
// Значение приабразуется во время сохранения в базе данных
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function from_secure($value)
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// array
|
||||||
|
public static function to_array($value)
|
||||||
|
{
|
||||||
|
return (is_array($value)) ? $value : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function from_array($value)
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
<?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
|
||||||
* http://www.phppatterns.com/docs/design/the_registry?s=registry
|
* http://www.phppatterns.com/docs/design/the_registry?s=registry
|
||||||
*/
|
*/
|
||||||
require_once 'core/settings.php';
|
|
||||||
|
|
||||||
class Registry extends Settings
|
class Registry extends Settings
|
||||||
{
|
{
|
||||||
|
|
@ -26,7 +26,7 @@ class Session
|
||||||
|
|
||||||
function start()
|
function start()
|
||||||
{
|
{
|
||||||
session_start();
|
@session_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
function stop()
|
function stop()
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'core/collection.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс реестра
|
* Класс реестра
|
||||||
* Реестр организован как ассоциативный многомерный массив
|
* Реестр организован как ассоциативный многомерный массив
|
||||||
|
|
@ -14,23 +12,31 @@ require_once 'core/collection.php';
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
@ -53,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;
|
||||||
|
|
@ -109,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();
|
||||||
|
|
@ -151,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
212
src/Setup.php
Normal file
212
src/Setup.php
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>
|
||||||
|
* $setup = new Setup('test.xml');
|
||||||
|
* $setup->set('target', 'dst');
|
||||||
|
* $setup->executeActions('install');
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
class Setup
|
||||||
|
{
|
||||||
|
protected $actions = array();
|
||||||
|
public $context = array();
|
||||||
|
protected $file;
|
||||||
|
protected $action;
|
||||||
|
protected $node;
|
||||||
|
protected $stack = array();
|
||||||
|
|
||||||
|
public $zip;
|
||||||
|
public $target;
|
||||||
|
|
||||||
|
public function __construct($file)
|
||||||
|
{
|
||||||
|
$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'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрация новых действия для установки
|
||||||
|
*/
|
||||||
|
public function registerAction($name, $action)
|
||||||
|
{
|
||||||
|
$this->actions[$name] = $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Установка переменных для шаблона
|
||||||
|
*/
|
||||||
|
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 команд
|
||||||
|
*/
|
||||||
|
function batchSQLZip(/*.Database.*/ $conn, $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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue