PHP: Как создать календарь событий на PHP с библиотекой FullCalendar JS

Календарь событий - это мощный инструмент, позволяющий отслеживать предстоящие события, расписания, встречи и сроки.
Я использую плагин FullCalendar для создания макета календаря и придания ему динамичности с помощью PHP и MySQL. Плагин не зависит от какой-либо библиотеки, отзывчив и автоматически вписывается на страницу. Для его настройки и управления доступны различные типы опций и событий.
В этом уроке я покажу, как можно создать событие, обновить и удалить существующее событие, а также загрузить события в jаvascript библиотеке FullCalendar, используя PHP AJAX и MySQL.
В примере я использую FullCalendar v6 и библиотеку sweetAlert для отображения окна оповещения о добавлении/редактировании событий.
1. Структура таблицы
В примере я использую таблицу events
. Она имеет следующую структуру:
CREATE TABLE `events` (
`id` int(10) NOT NULL,
`title` varchar(190) NOT NULL,
`description` text NOT NULL,
`start_date` date NOT NULL,
`end_date` date NOT NULL
);
ALTER TABLE `events`
ADD PRIMARY KEY (`id`);
ALTER TABLE `events`
MODIFY `id` int(10) NOT NULL AUTO_INCREMENT;
2. Конфигурация базы данных
Создайте файл config.php
для конфигурации базы данных.
Готовый код
<?php
$host = "localhost"; /* Host name */
$user = "root"; /* User */
$password = ""; /* Password */
$dbname = "tutorial"; /* Database name */
$con = mysqli_connect($host, $user, $password,$dbname);
// Check connection
if (!$con) {
die("Connection failed: " . mysqli_connect_error());
}
3. Скачайте и подключите библиотеки
- Скачайте библиотеки Fullcalendar и sweetAlert.
- Также подключите библиотеку jQuery для отправки AJAX-запросов.
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<!-- Fullcalendar -->
<script type="text/jаvascript" src="fullcalendar-6.1.4/dist/index.global.min.js"></script>
<!-- Sweetalert -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
4. HTML
Создайте файл index.php
Сохраните текущую дату в переменную $currentData
, она используется для установки начальной даты FullCalendar. Создайте <div id='calendar'></div>
для инициализации FullCalendar()
.
Готовый код:
<?php
$currentData = date('Y-m-d');
?>
<!-- Calendar Container -->
<div id='calendar-container'>
<div id='calendar'></div>
</div>
5. Файл PHP - Выборка всех событий
Создайте файл fetchevents.php
для загрузки списка всех созданных событий в FullCalendar.
Получите все записи из таблицы events
и присвойте их переменной $eventsList
. Переберите список $eventsList
и инициализируйте массив $response
с eventid, названием, описанием, датой начала и окончания.
Верните $response
в формате JSON.
Готовый код:
<?php
include "config.php";
// Получение всех записей
$sql = "SELECT * FROM events";
$eventsList = mysqli_query($con,$sql);
$response = array();
while($row = mysqli_fetch_assoc($eventsList)){
$response[] = array(
"eventid" => $row['id'],
"title" => $row['title'],
"description" => $row['description'],
"start" => $row['start_date'],
"end" => $row['end_date'],
);
}
echo json_encode($response);
exit;
6. Файл PHP - Обработка запросов AJAX
Создайте файл ajaxfile.php
Отсюда обработайте 4 запроса:
- addEvent - Добавить новое событие
- moveEvent - Обновить дату события
- editEvent - Обновить детали события
- deleteEvent - Удалить событие
$request == 'addEvent'
Прочитайте данные методом POST и присвойте их переменным. Если значения переменных не пусты, то вставьте новую запись в таблицу событий.
Сохраните идентификатор последней вставки в переменной $eventid и 1 в $status. Инициализируйте массив $response ключами eventid, status и message. Присвойте $eventid ключу eventid, 1 - статусу, а сообщение об успехе - ключу message.
Если запись не была вставлена, то в массиве $response Array сохраните 0 для статуса и сообщение об ошибке для ключа message.
Верните массив $response в формате JSON.
$request == 'moveEvent'
Считайте новые даты методом POST и обновите идентификатор события. Если $eventid > 0 и $start_date и $end_date не пустые, проверьте, существует ли $eventid в таблице events
или нет. Если существует, то обновите поля start_date и end_date и присвойте 1 значению $status. В массиве $response сохраните 1 в ключе status и сообщение об успехе в ключе message.
Если запись не обновилась, то сохраните 0 для ключа status и сообщение об ошибке для ключа message.
Верните массив $response в формате JSON.
$request == 'editEvent'
Считывание информации о событии методом POST и обновление идентификатора события. Если $eventid > 0 и $title и $description не пустые, проверьте, существует ли $eventid в таблице events
или нет. Если существует, то обновите значения полей title и description в таблице events
новым значением POST.
Присвойте 1 значение $status и сохраните 1 в ключе status, а сообщение об успехе - в ключе message в массиве $response.
Если запись не обновилась, то сохраните 0 для ключа status и сообщение об ошибке для ключа message.
Верните массив $response в формате JSON.
$request == 'deleteEvent'
Считайте идентификатор события POST и проверьте, является ли он > 0 или нет. Если да, то проверьте, существует ли запись в таблице events
с идентификатором $eventid.
Удалите запись, если она существует, и присвойте $status значение 1. В массиве $response сохраните 1 в ключе status и сообщение об успехе в ключе message.
Если запись не удалена, присвойте 0 ключу status и сообщение об ошибке ключу message в массиве $response.
Верните массив $response в формате JSON.
Готовый код:
<?php
include "config.php";
$request = "";
// Чтение значения
if(isset($_POST['request'])){
$request = $_POST['request'];
}
// Добавить новое событие
if($request == 'addEvent'){
// POST-данные
$title = ""; $description = "";
$start_date = ""; $end_date = "";
if(isset($_POST['title'])){
$title = $_POST['title'];
}
if(isset($_POST['description'])){
$description = $_POST['description'];
}
if(isset($_POST['start_date'])){
$start_date = $_POST['start_date'];
}
if(isset($_POST['start_date'])){
$end_date = $_POST['end_date'];
}
$response = array();
$status = 0;
if(!empty($title) && !empty($description) && !empty($start_date) && !empty($end_date) ){
// Вставить запись
$sql = "INSERT INTO events(title,description,start_date,end_date) VALUES('".$title."','".$description."','".$start_date."','".$end_date."')";
if(mysqli_query($con,$sql)){
$eventid = mysqli_insert_id($con);
$status = 1;
$response['eventid'] = $eventid;
$response['status'] = 1;
$response['message'] = 'Event created successfully.';
}
}
if($status == 0){
$response['status'] = 0;
$response['message'] = 'Event not created.';
}
echo json_encode($response);
exit;
}
// Переместить событие
if($request == 'moveEvent'){
// POST-данные
$eventid = 0;
$start_date = ""; $end_date = "";
if(isset($_POST['eventid']) && is_numeric($_POST['eventid'])){
$eventid = $_POST['eventid'];
}
if(isset($_POST['start_date'])){
$start_date = $_POST['start_date'];
}
if(isset($_POST['end_date'])){
$end_date = $_POST['end_date'];
}
$response = array();
$status = 0;
// Проверить идентификатор события
$sql = "SELECT id FROM events WHERE id=".$eventid;
$result = mysqli_query($con,$sql);
if(mysqli_num_rows($result)){
// Обновить запись
$sql = "UPDATE events SET start_date='".$start_date."',end_date='".$end_date."' WHERE id=".$eventid;
if(mysqli_query($con,$sql)){
$status = 1;
$response['status'] = 1;
$response['message'] = 'Event date updated successfully.';
}
}
if($status == 0){
$response['status'] = 0;
$response['message'] = 'Event date not updated.';
}
echo json_encode($response);
exit;
}
// Обновить событие
if($request == 'editEvent'){
// POST-данные
$eventid = 0;
if(isset($_POST['eventid']) && is_numeric($_POST['eventid'])){
$eventid = $_POST['eventid'];
}
if(isset($_POST['title'])){
$title = $_POST['title'];
}
if(isset($_POST['description'])){
$description = $_POST['description'];
}
$response = array();
if($eventid > 0 && !empty($title) && !empty($description) ){
// Проверить идентификатор события
$sql = "SELECT id FROM events WHERE id=".$eventid;
$result = mysqli_query($con,$sql);
if(mysqli_num_rows($result)){
// Обновить запись
$sql = "UPDATE events SET title='".$title."', description='".$description."' WHERE id=".$eventid;
if(mysqli_query($con,$sql)){
$status = 1;
$response['status'] = 1;
$response['message'] = 'Event updated successfully.';
}
}
}
if($status == 0){
$response['status'] = 0;
$response['message'] = 'Event not updated.';
}
echo json_encode($response);
exit;
}
// Удалить событие
if($request == 'deleteEvent'){
// POST-данные
$eventid = 0;
if(isset($_POST['eventid']) && is_numeric($_POST['eventid'])){
$eventid = $_POST['eventid'];
}
$response = array();
$status = 0;
if($eventid > 0){
// Проверить идентификатор события
$sql = "SELECT id FROM events WHERE id=".$eventid;
$result = mysqli_query($con,$sql);
if(mysqli_num_rows($result)){
// Удалить запись
$sql = "DELETE FROM events WHERE id=".$eventid;
if(mysqli_query($con,$sql)){
$status = 1;
$response['status'] = 1;
$response['message'] = 'Event deleted successfully.';
}
}
}
if($status == 0){
$response['status'] = 0;
$response['message'] = 'Event not deleted.';
}
echo json_encode($response);
exit;
}
7. jQuery
Инициализируйте FullCalendar на <div id='calendar'></div>
.
Здесь я указал следующие параметры
- initialDate - По умолчанию FullCalendar показывает текущий месяц, но вы также можете указать дату в формате yyyy-mm-dd.
- height - По умолчанию FullCalendar занимает весь экран, но вы можете изменить его высоту с помощью этого параметра. Я установил значение 600px.
- selectable - Разрешить выбор события. Значение по умолчанию - true.
- editable - Разрешить перетаскивание события на другую дату. Значение по умолчанию - false.
- dayMaxEvents - Показывать кнопку "Больше", если на дату назначено много событий. Значение по умолчанию - false.
- events - Загрузить существующие события. Укажите файл, из которого нужно загрузить события. Установите значение fetchevents.php.
- select - Это событие срабатывает при нажатии на день. Используется для добавления нового события путем отображения всплывающего окна для ввода деталей события.
Отображение окна подтверждения sweetAlert, которое имеет текстовое поле для ввода названия события и текстовую область для ввода описания.
Если кнопка подтверждения нажата, то считываются введенные значения и дата начала и окончания события. Отправьте AJAX POST запрос на ajaxfile.php, передайте запрос: 'addEvent' и информацию о событии. При успешном обратном вызове проверьте статус ответа. Если он равен 1, значит запись успешно вставлена в базу данных MySQL, используя calendar.addEvent(); создаем событие.
Здесь я также устанавливаю eventid, который используется для обновления/удаления записи.
Отображение предупреждающего сообщения в соответствии с response.status.
- eventDrop - Это событие срабатывает при перетаскивании элемента в календаре. С помощью этого события обновляется дата события.
Прочитать выбранное событие - eventid, новую дату начала и окончания. Отправьте AJAX POST запрос на ajaxfile.php, передайте запрос: 'moveEvent', обновите id события и даты.
- eventClick - Это событие срабатывает при нажатии на существующее событие. С его помощью можно обновить/удалить событие.
Прочитайте eventid, название и описание. Создайте окно подтверждения sweetAlert, которое имеет 3 кнопки - Обновить, Удалить и Отменить. Установите значения заголовка и описания в текстовом поле и текстовой области.
Редактирование события
Если result.isConfirmed равен true, значит кнопка обновления нажата. Считайте введенные значения и отправьте AJAX POST запрос на ajaxfile.php, передайте запрос: 'editEvent', обновите id события, новое название и описание. При успешном вызове, если response.status == 1, то повторно получаем все события, вызывая - calendar.refetchEvents(); и выводим сообщение об ответе.
Удаление события
Если result.isDenied равен true, это означает, что кнопка удаления нажата. Отправьте AJAX POST запрос на ajaxfile.php, передайте запрос: 'deleteEvent', id удаляемого события. При успешном выполнении запроса, если response.status == 1, удалите событие из календаря, вызвав - arg.event.remove(); и выведите сообщение об ответе.
Готовый код:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialDate: '<?= $currentData ?>',
height: '600px',
selectable: true,
editable: true,
dayMaxEvents: true, // allow "more" link when too many events
events: 'fetchevents.php', // Fetch all events
select: function(arg) { // Create Event
// Alert box to add event
Swal.fire({
title: 'Add New Event',
showCancelButton: true,
confirmButtonText: 'Create',
html:
'<input id="eventtitle" class="swal2-input" placeholder="Event name" style="width: 84%;" >' +
'<textarea id="eventdescription" class="swal2-input" placeholder="Event description" style="width: 84%; height: 100px;"></textarea>',
focusConfirm: false,
preConfirm: () => {
return [
document.getElementById('eventtitle').value,
document.getElementById('eventdescription').value
]
}
}).then((result) => {
if (result.isConfirmed) {
var title = result.value[0].trim();
var description = result.value[1].trim();
var start_date = arg.startStr;
var end_date = arg.endStr;
if(title != '' && description != ''){
// AJAX - Add event
$.ajax({
url: 'ajaxfile.php',
type: 'post',
dаta: {request: 'addEvent',title: title,description: description,start_date: start_date,end_date: end_date},
dataType: 'json',
success: function(response){
if(response.status == 1){
// Add event
calendar.addEvent({
eventid: response.eventid,
title: title,
description: description,
start: arg.start,
end: arg.end,
allDay: arg.allDay
})
// Alert message
Swal.fire(response.message,'','success');
}else{
// Alert message
Swal.fire(response.message,'','error');
}
}
});
}
}
})
calendar.unselect()
},
eventDrop: function (event, delta) { // Move event
// Event details
var eventid = event.event.extendedProps.eventid;
var newStart_date = event.event.startStr;
var newEnd_date = event.event.endStr;
// AJAX request
$.ajax({
url: 'ajaxfile.php',
type: 'post',
dаta: {request: 'moveEvent',eventid: eventid,start_date: newStart_date, end_date: newEnd_date},
dataType: 'json',
async: false,
success: function(response){
console.log(response);
}
});
},
eventClick: function(arg) { // Edit/Delete event
// Event details
var eventid = arg.event._def.extendedProps.eventid;
var description = arg.event._def.extendedProps.description;
var title = arg.event._def.title;
// Alert box to edit and delete event
Swal.fire({
title: 'Edit Event',
showDenyButton: true,
showCancelButton: true,
confirmButtonText: 'Update',
denyButtonText: 'Delete',
html:
'<input id="eventtitle" class="swal2-input" placeholder="Event name" style="width: 84%;" value="'+ title +'" >' +
'<textarea id="eventdescription" class="swal2-input" placeholder="Event description" style="width: 84%; height: 100px;">' + description + '</textarea>',
focusConfirm: false,
preConfirm: () => {
return [
document.getElementById('eventtitle').value,
document.getElementById('eventdescription').value
]
}
}).then((result) => {
if (result.isConfirmed) { // Update
var newTitle = result.value[0].trim();
var newDescription = result.value[1].trim();
if(newTitle != ''){
// AJAX - Edit event
$.ajax({
url: 'ajaxfile.php',
type: 'post',
dаta: {request: 'editEvent',eventid: eventid,title: newTitle, description: newDescription},
dataType: 'json',
async: false,
success: function(response){
if(response.status == 1){
// Refetch all events
calendar.refetchEvents();
// Alert message
Swal.fire(response.message, '', 'success');
}else{
// Alert message
Swal.fire(response.message, '', 'error');
}
}
});
}
} else if (result.isDenied) { // Delete
// AJAX - Delete Event
$.ajax({
url: 'ajaxfile.php',
type: 'post',
dаta: {request: 'deleteEvent',eventid: eventid},
dataType: 'json',
async: false,
success: function(response){
if(response.status == 1){
arg.event.remove();
// Alert message
Swal.fire(response.message, '', 'success');
}else{
// Alert message
Swal.fire(response.message, '', 'error');
}
}
});
}
})
}
});
calendar.render();
});
В примере я использовал плагин sweetAlert для отображения всплывающего окна для ввода и отображения информации. Вы также можете использовать любой другой плагин.
Вы должны создать отдельный файл для сбора всех событий. Невозможно управлять ими из одного файла для обработки всех действий Fullcalendar - обновления/удаления. Это вызовет проблемы при повторной выборке событий после редактирования события.
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.