dhtmlxScheduler с PHP: Slim 3
В этом руководстве рассматриваются основные шаги по созданию планировщика на PHP с использованием Slim 3 Framework и REST API на серверной стороне.
Это руководство использует устаревшую версию Slim Framework v3.x. Для самой новой версии см. руководство Slim Framework v4.x.
Также доступны руководства по интеграции с другими платформами и фреймворками:
- dhtmlxScheduler с ASP.NET Core
- dhtmlxScheduler с ASP.NET MVC
- dhtmlxScheduler с Node.js
- dhtmlxScheduler с PHP
- dhtmlxScheduler с PHP:Laravel
- dhtmlxScheduler с PHP: Slim
- dhtmlxScheduler с SalesForce LWC
- dhtmlxScheduler с Ruby on Rails
- dhtmlxScheduler с dhtmlxConnector
При разработке PHP-приложений обычно используется готовый фреймворк, а не создание всего с нуля.
В данном случае используется Slim 3 вместе с REST API на сервере и MySQL для хранения данных. Операции CRUD будут реализованы через PDO, что обеспечивает гибкость и возможность использования с другими фреймворками.
Вы можете ознакомиться с полной демо-версией на GitHub. Следуйте пошаговым инструкциям для создания этого приложения.
Полный исходный код доступен на GitHub.
Шаг 1. Инициализация проекта
Создание проекта
В качестве отправной точки используйте skeleton application для Slim 3.
Начните с создания приложения с помощью Composer:
$ composer create-project slim/slim-skeleton scheduler-slim-howto
$ cd scheduler-slim-howto/
$ composer require illuminate/database "~5.1"
Шаг 2. Добавление Scheduler на страницу
Далее добавьте планировщик на страницу. Это включает два простых шага.
Создание view
Создайте файл scheduler.phtml в папке templates:
<!doctype html>
<html>
<head>
<title> Getting started with dhtmlxScheduler</title>
<meta charSet="utf-8"/>
<script src="https://cdn.dhtmlx.com/scheduler/edge/dhtmlxscheduler.js"></script>
<link href="https://cdn.dhtmlx.com/scheduler/edge/dhtmlxscheduler.css"
rel="stylesheet" type="text/css" charSet="utf-8">
<style>
html, body{
margin:0px;
padding:0px;
height:100%;
overflow:hidden;
}
</style>
</head>
<body>
<div id="scheduler_here" className="dhx_cal_container">
<div className="dhx_cal_navline">
<div className="dhx_cal_prev_button"> </div>
<div className="dhx_cal_next_button"> </div>
<div className="dhx_cal_today_button"></div>
<div className="dhx_cal_date"></div>
<div className="dhx_cal_tab" name="day_tab"></div>
<div className="dhx_cal_tab" name="week_tab"></div>
<div className="dhx_cal_tab" name="month_tab"></div>
</div>
<div className="dhx_cal_header"></div>
<div className="dhx_cal_data"></div>
</div>
<script>
scheduler.config.xml_date="%Y-%m-%d %H:%i";
scheduler.init('scheduler_here', new Date(2019,0,20), "week");
scheduler.load("/events");
var dp = scheduler.createDataProcessor("/events");
dp.setTransactionMode("REST"); // use to transfer data with REST
dp.init(scheduler);
</script>
</body>
</html>
Настройка маршрутов
Когда новая страница готова, настройте маршрут в src/routes.php, чтобы получить к ней доступ через браузер:
$app->get('/', function (Request $request, Response $response, array $args) {
return $this->renderer->render($response, 'scheduler.phtml', $args);
});
Теперь вы можете запустить приложение и увидеть отображение планировщика:

Шаг 3. Подготовка базы данных
На этом этапе планировщик пуст. Следующий шаг - создать базу данных и подключить её к приложению.
Создание базы данных
Вы можете создать базу данных через любой удобный MySQL-клиент или из консоли. Вот SQL для создания базы и таблицы событий календаря:
CREATE DATABASE IF NOT EXISTS `scheduler_howto_php`;
USE `scheduler_howto_php`;
DROP TABLE IF EXISTS `events`;
CREATE TABLE `events` (
`id` int(11) AUTO_INCREMENT,
`start_date` datetime NOT NULL,
`end_date` datetime NOT NULL,
`text` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET="utf8;"
Чтобы импортировать через консоль MySQL, сохраните вышеуказанный код в файл dump.sql и выполните:
$ mysql -uuser -ppass scheduler < mysql_dump.sql
Далее откройте src/settings.php, добавьте массив конфигурации базы данных и укажите свои учетные данные:
'pdo' => [
'engine' => 'mysql',
'host' => 'localhost',
'database' => 'scheduler_howto_php',
'username' => 'user',
'password' => 'pass',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => true,
],
]
Затем в src/dependencies.php добавьте экземпляр PDO в контейнер приложения:
// Добавление нового экземпляра PDO в контейнер
$container['database'] = function($container) {
$config = $container->get('settings')['pdo'];
$dsn = "{$config['engine']}:host="{$config["'host']};dbname="{$config["'database']};
charSet="{$config["'charset']}";
$username = $config['username'];
$password = $config['password'];
return new PDO($dsn, $username, $password, $config['options']);
};
Шаг 4. Загрузка данных
Планировщик уже настроен на вызов "/events" для получения событий. Теперь добавьте обработчик этого запроса, чтобы отдавать реальные данные.
Поскольку потребуется несколько обработчиков, группы маршрутов помогут их организовать.
Откройте src/routes.php и добавьте группу для "/events" с действием GET:
$app->group('/events', function () {
$this->get('', function (Request $request, Response $response, array $args) {
$db = $this->database;
$queryText = 'SELECT * FROM `events`';
$query = $db->prepare($queryText);
$query->execute();
$result = $query->fetchAll();
return $response->withJson($result);
});
});
После добавления событий в базу они появятся в планировщике.
Динамическая загрузка
На этом этапе планировщик загружает все события сразу, что допустимо для небольших наборов данных. Однако, если приложение используется для планирования или бронирования и старые записи не удаляются, количество событий быстро возрастет, что приведет к большим объемам данных при каждой загрузке страницы.
Динамическая загрузка позволяет запрашивать только события, видимые в текущем диапазоне дат. Каждый раз при смене вида гридом, планировщик получает только соответствующие данные.
Для этого на клиенте установите опцию setLoadMode в "day", "week" или "month":
scheduler.config.xml_date="%Y-%m-%d %H:%i";
scheduler.init("scheduler_here", new Date(2019, 0, 20), "week");
scheduler.setLoadMode("day");
scheduler.load("/events");
На сервере обработайте фильтры по датам следующим образом:
$app->group('/events', function () {
$this->get('', function (Request $request, Response $response, array $args) {
$db = $this->database;
$queryText = 'SELECT * FROM `events`';
$params = $request->getQueryParams(); /*!*/
$queryParams = []; /*!*/
if (isset($params['from']) && isset($params['to'])) {/*!*/
$queryText .= " WHERE `end_date`>=? AND `start_date` < ?;";/*!*/
$queryParams = [$params['from'], $params['to']];/*!*/
}/*!*/
$query = $db->prepare($queryText);
$query->execute($queryParams);/*!*/
$result = $query->fetchAll();
return $response->withJson($result);
});
});
Шаг 5. Сохранение изменений
Реализация серверных обработчиков
Теперь планировщик может читать данные с сервера. Следующий шаг - реализовать сохранение изменений в базу данных.
Клиент работает в режиме REST, отправляя запросы POST, PUT и DELETE для действий с событиями. Подробнее о формате запросов и маршрутах, используемых планировщиком.
Определите контроллер для обработки этих действий, настройте маршруты и включите сохранение на клиенте.
Добавьте обработчик POST в src/routes.php для вставки новых событий:
$this->post('', function (Request $request, Response $response, array $args) {
$db = $this->database;
$body = $request->getParsedBody();
$queryText = 'INSERT INTO `events` SET
`start_date`=?,
`end_date`=?,
`text`=?';
$queryParams = [
$body['start_date'],
$body['end_date'],
$body['text']
];
$query = $db->prepare($queryText);
$query->execute($queryParams);
$result = [
'tid' => $db->lastInsertId(),
'action' => 'inserted'
];
return $response->withJson($result);
});
При добавлении нового события сервер возвращает его ID в свойстве tid ответа. JSON-ответ может содержать дополнительные свойства, доступные на клиенте.
Аналогично, добавьте обработчик PUT для обновления событий:
$this->put('/{id}', function (Request $request, Response $response, array $args) {
$db = $this->database;
$id = $request->getAttribute('route')->getArgument('id');
$body = $request->getParsedBody();
$queryText = 'UPDATE `events` SET
`start_date`=?,
`end_date`=?,
`text`=?
WHERE `id`=?';
$queryParams = [
$body['start_date'],
$body['end_date'],
$body['text'],
$id
];
$query = $db->prepare($queryText);
$query->execute($queryParams);
$result = [
'action' => 'updated'
];
return $response->withJson($result);
});
И обработчик DELETE для удаления событий:
$this->delete('/{id}', function (Request $request, Response $response, array $args) {
$db = $this->database;
$id = $request->getAttribute('route')->getArgument('id');
$queryText = 'DELETE FROM `events` WHERE `id`=? ;';
$query = $db->prepare($queryText);
$query->execute([$id]);
$result = [
'action' => 'deleted'
];
return $response->withJson($result);
});