Использование xPDO без MODX
Некоторое время назад подписался помочь хорошему проекту Критиканство в написании парсера для автоматической загрузки скриншотов игр.
Админка Критиканства создавалась в разное время разными специалистами и выглядит немного разрозненной. Тоже касается и таблиц базы данных — каждый разработчик мудрил с ними по своему.
Сам сайт сделан очень олдскульно и «чисто для себя». То есть, работает быстро, но все что можно зашито прямо в php код. Никаких ORM, никаких шаблонов, только то, что нужно.
Для разработки парсера мне предоставили полную свободу действий, поэтому я набросал новую версию админки с использованием шаблонов, xPDO и других любимых методик.
Последняя версия xPDO доступна в репозитории на github. Нужно создать конфигурационный файл, прописать туда данные для коннекта к БД, определить константы и запустить xPDO.
Вот примерный конфиг:
А вот файл index.php
xPDO подключен — можно писать схему, генерировать по ней модель таблиц и работать в привычном окружении. Продолжение файла будет ниже, а пока вот вам скрипт генерации модели:
Понятное дело, схема-файлы ничем не отличаются от таковых в MODX.
Так как modx.class.php у меня нет, пришлось написать основные методы в собственном классе. Логика простая, index.php получает запрос, определяет ajax это или нет, и в зависимости от этого передаёт дальше: в loadPage(), или в handleAjax().
Первый метод грузит нужный php файл из специальной директории, оформляет его шаблоном и вставляет пейсхолдеры, а второй обрабатывает ajax запрос и отдаёт json ответ. Короче говоря, MODXmini.
Итак, продолжение index.php
Метод getChunk загружает чанки с жесткого диска, а не из БД. Внутри файлов-страниц можно использовать основной класс, xPDO и вообще делать там что угодно. В принципе, это как бы файловые сниппеты.
Этой заметкой я хочу показать, что можно использовать основные возможность MODX без него самого.
Если вам не нужна админка, юзеры, права доступа, ресурсы, а нужна только быстрая и удобная работа с БД, вокруг которой вы строите свой проект — xPDO может помочь. Конечно, нужно написать роутинг самостоятельно, но в итоге вы получаете быстрый, легкий и MODX-совместимый движок.
Возможно, стоит потом сделать репозиторий с этим MODXmini проектом — вдруг еще понадобится. Ну и стало ясно, что pdoTools стоит немного доработать, чтобы он не так был завязан на переменные MODX.
Кстати говоря, вот скриншоты того, что у меня получилось:
«Критиканство» — это крупнейший в российском сегменте интернета агрегатор критических отзывов на фильмы и игры. В нашей базе более 150 печатных и интернет-изданий, а количество рецензий на момент запуска (на март 2013 года) составило более 60 000.Этот проект был запущен ребятами с прекрасного сайта kino-govno.com, к которому я питаю очень теплые чувства. Шутка ли, его создали авторы из лучшего журнала про игры — Game.EXE, который я до дыр зачитывал еще в школе.
Админка Критиканства создавалась в разное время разными специалистами и выглядит немного разрозненной. Тоже касается и таблиц базы данных — каждый разработчик мудрил с ними по своему.
Сам сайт сделан очень олдскульно и «чисто для себя». То есть, работает быстро, но все что можно зашито прямо в php код. Никаких ORM, никаких шаблонов, только то, что нужно.
Для разработки парсера мне предоставили полную свободу действий, поэтому я набросал новую версию админки с использованием шаблонов, xPDO и других любимых методик.
Запуск xPDO
Последняя версия xPDO доступна в репозитории на github. Нужно создать конфигурационный файл, прописать туда данные для коннекта к БД, определить константы и запустить xPDO.
Вот примерный конфиг:
$database_type = 'mysql';
$database_server = 'localhost';
$database_user = 'databaseadmin';
$database_password = 'databasepassword';
$database_connection_charset = 'utf8';
$dbase = 'mydatabase';
$table_prefix = '';
$database_dsn = 'mysql:host=localhost;dbname=mydatabase;charset=utf8';
$config_options = array();
$driver_options = array();
if (!defined('PROJECT_NAME')) {
define('PROJECT_NAME', 'MyProject');
}
if (!defined('PROJECT_NAME_LOWER')) {
define('PROJECT_NAME_LOWER', strtolower(PROJECT_NAME));
}
if (!defined('PROJECT_BASE_PATH')) {
define('PROJECT_BASE_PATH', '/var/www/data/www/');
}
if (!defined('PROJECT_CORE_PATH')) {
define('PROJECT_CORE_PATH', PROJECT_BASE_PATH . 'core/');
}
if (!defined('PROJECT_ELEMENTS_PATH')) {
define('PROJECT_ELEMENTS_PATH', PROJECT_CORE_PATH . 'elements/');
}
А вот файл index.php
require 'core/config/config.inc.php';
require PROJECT_CORE_PATH . 'xpdo/xpdo.class.php';
$xpdo = new xPDO($database_dsn, $database_user, $database_password, $config_options, $driver_options);
$xpdo->setLogLevel(xPDO::LOG_LEVEL_ERROR);
$xpdo->setLogTarget('HTML');
xPDO подключен — можно писать схему, генерировать по ней модель таблиц и работать в привычном окружении. Продолжение файла будет ниже, а пока вот вам скрипт генерации модели:
<?php
require dirname(dirname(__FILE__)) . '/config/config.inc.php';
require PROJECT_CORE_PATH . 'xpdo/xpdo.class.php';
$xpdo = new xPDO($database_dsn, $database_user, $database_password, $config_options, $driver_options);
$xpdo->setLogLevel(xPDO::LOG_LEVEL_INFO);
$xpdo->setLogTarget('HTML');
$model = PROJECT_CORE_PATH . 'model/';
$map = $model . PROJECT_NAME_LOWER . '/mysql';
$xml = $model . '/schema/' . PROJECT_NAME_LOWER.'.mysql.schema.xml';
/** @var xPDOManager $manager */
$manager = $xpdo->getManager();
/** @var xPDOGenerator $generator */
$generator = $manager->getGenerator();
rrmdir($map);
$generator->parseSchema($xml, $model);
$xpdo->log(xPDO::LOG_LEVEL_INFO, 'Model generated.');
/**
* Recursive directory remove
*
* @param $dir
*/
function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($dir . "/" . $object) == "dir") {
rrmdir($dir . "/" . $object);
}
else {
unlink($dir . "/" . $object);
}
}
}
reset($objects);
rmdir($dir);
}
}
Понятное дело, схема-файлы ничем не отличаются от таковых в MODX.
Роутинг
Так как modx.class.php у меня нет, пришлось написать основные методы в собственном классе. Логика простая, index.php получает запрос, определяет ajax это или нет, и в зависимости от этого передаёт дальше: в loadPage(), или в handleAjax().
Первый метод грузит нужный php файл из специальной директории, оформляет его шаблоном и вставляет пейсхолдеры, а второй обрабатывает ajax запрос и отдаёт json ответ. Короче говоря, MODXmini.
Итак, продолжение index.php
$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
require PROJECT_CORE_PATH . 'model/myproject/myproject.class.php';
/** @var MyProject $myproject */
$myproject = $xpdo->getService('MyProject', 'myproject', PROJECT_MODEL_PATH . 'myproject/', array());
$request = empty($_REQUEST['q'])
? 'home'
: $_REQUEST['q'];
$tmp = explode('/', $request);
$page = current($tmp);
$params = array_splice($tmp, 1);
session_start();
if ($isAjax && !empty($_POST['action'])) {
$response = $myproject->handleAjax($_POST['action']);
$response = preg_replace('/\[\[.*?\]\]/', '', json_encode($response));
@session_write_close();
exit($response);
}
else {
ob_start();
$output = $myproject->loadPage($page, $params);
echo preg_replace('/\[\[.*?\]\]/', '', $output);
@session_write_close();
}
Метод loadPage:public function loadPage($page, $params = array()) {
$page = strtolower($page);
if (!file_exists(PROJECT_ELEMENTS_PATH . 'page/' . $page . '.inc.php')) {
$page = 'home';
}
switch ($page) {
case 'game':
$template = 'game';
break;
default:
$template = 'base';
}
$_REQUEST['page'] = $page;
$_REQUEST['request'] = $params;
$xpdo = $this->xpdo;
$myproject = $this;
echo include PROJECT_ELEMENTS_PATH . 'page/' . $page . '.inc.php';
$content = ob_get_clean();
if (is_bool($content)) {
$content = '';
}
$this->setPlaceholders(array(
'content' => $content,
'Header' => $this->getChunk('header'),
'Navbar' => $this->getChunk('navbar'),
'Footer' => $this->getChunk('footer'),
));
$tpl = $this->getChunk($template, $this->placeholders, PROJECT_ELEMENTS_PATH . 'templates/');
$pls = $this->makePlaceholders($this->placeholders);
$output = str_replace($pls['pl'], $pls['vl'], $tpl);
$output = str_replace(array('[^t^]', '[^q^]', '[^qt^]'), array(
sprintf("%2.4f s", microtime(true) - $this->startTime),
$xpdo->executedQueries,
sprintf("%2.4f s", $this->xpdo->queryTime)
), $output);
return $output;
}
Метод getChunk загружает чанки с жесткого диска, а не из БД. Внутри файлов-страниц можно использовать основной класс, xPDO и вообще делать там что угодно. В принципе, это как бы файловые сниппеты.
Заключение
Этой заметкой я хочу показать, что можно использовать основные возможность MODX без него самого.
Если вам не нужна админка, юзеры, права доступа, ресурсы, а нужна только быстрая и удобная работа с БД, вокруг которой вы строите свой проект — xPDO может помочь. Конечно, нужно написать роутинг самостоятельно, но в итоге вы получаете быстрый, легкий и MODX-совместимый движок.
Возможно, стоит потом сделать репозиторий с этим MODXmini проектом — вдруг еще понадобится. Ну и стало ясно, что pdoTools стоит немного доработать, чтобы он не так был завязан на переменные MODX.
Кстати говоря, вот скриншоты того, что у меня получилось:
Комментарии: 20
Тоже скоро будет задача подобного парсера. И весь modx там тоже, в общем-то, ни к чему.
Так что, спасибо, пригодится!)
Как всегда радуешь =)
p.s. это поэтому ты стал частью КГ? =)
Так что, спасибо, пригодится!)
Как всегда радуешь =)
p.s. это поэтому ты стал частью КГ? =)
Ага, поэтому =)
Круто, поздравляю!
А если не секрет, какие плюшки и обязанности появляются у участника администрации кг? Просто интересно :-)
А если не секрет, какие плюшки и обязанности появляются у участника администрации кг? Просто интересно :-)
Пока никаких, кроме малиновых штанов.
Кстати говоря, за работу я денег тоже пока не брал — все по дружбе.
Кстати говоря, за работу я денег тоже пока не брал — все по дружбе.
По крайней мере, первый шаг к тому, чтобы стать участником подкаста, уже сделан xD
Понятно, что делалось скорее всего под задачу, да и скрипт всего лишь, но я бы какой роутинг подкрутил бы толковый. Вообще интересно было бы сделать возможность загружать xpdo как пакет для compser.
www.kritikanstvo.ru/top/movies/best/alltime/genres/95/ прокручиваю в низ там остается очень большое поле пустое. Стоит только нажать f12 (консоль разработчика) оно исчезает.
Передал авторам!
Для роутинга, классная библиотека nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html
Классная ORM, по мне так лучшая из тех с какими я работал github.com/laravel/framework/tree/master/src/Illuminate/Database Работает быстро, настраивается просто, схем не требует, поддерживает разнообразные связи, различные мутаторы и т.п. Советую просто обратить внимание
Классная ORM, по мне так лучшая из тех с какими я работал github.com/laravel/framework/tree/master/src/Illuminate/Database Работает быстро, настраивается просто, схем не требует, поддерживает разнообразные связи, различные мутаторы и т.п. Советую просто обратить внимание
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.