Учебно-демонстрационный сайт отеля с административной панелью и логикой бронирования. Запуск и инфраструктура — через Docker Compose (PHP 8.2 + Apache, Nginx как reverse proxy, MySQL 8).
- PHP 8.2 (Apache внутри контейнера).
- Nginx (reverse proxy, самоподписанный TLS).
- MySQL 8.
- phpMyAdmin (опционально, для управления БД).
- Docker + Docker Compose.
- Composer, PDO.
- PHPStan, PHP-CS-Fixer.
- HTML/CSS/JS (готовая тема, статические ассеты в
public/).
- Создайте файл окружения:
cp .env.example .env
- Автозапуск с открытием страниц (сразу откроет сайт, админку и phpMyAdmin):
./scripts/start.sh
Если нужен ручной запуск, используйте шаги ниже.
- Установите зависимости PHP (по желанию, для разработки):
docker compose run --rm web composer install
- Соберите и запустите сервисы:
docker compose up -d --build
- Откройте сайт и админку:
- http://localhost/
- https://localhost/ (самоподписанный сертификат)
- https://hotel.localhost/ (самоподписанный сертификат)
- Админка: http://localhost/admin/login.php
- phpMyAdmin: http://localhost:8081/
Файл .env:
DB_HOST=db
DB_NAME=hotel
DB_USER=hotel
DB_PASS=hotel
DB_PORT=3306
DB_ROOT_PASS=root
ADMIN_USER=hotel_admin
ADMIN_PASS=HotelDemo2024
DB_*— параметры подключения к MySQL.ADMIN_USER/ADMIN_PASS— учетные данные первого администратора, которые создаются при первом входе, если таблицаusersпустая.
Адрес: http://localhost/admin/login.php
Логин/пароль по умолчанию:
Логин: hotel_admin
Пароль: HotelDemo2024
Они берутся из .env (ADMIN_USER / ADMIN_PASS). Если нужно изменить учетные данные:
- обновите запись в таблице
users, либо - удалите всех пользователей из
usersи зайдите снова (будет создан новый админ из.env).
- Публичные страницы: главная, список номеров, карточка номера, контакты.
- Админка: категории, типы номеров, этажи, виды, типы санузлов, клиенты, сотрудники, бронирования, пользователи.
- Атрибуты номера: этаж, вид из номера, количество спальных мест, раздельный санузел, тип санузла.
- Бронирования:
- статусы
reserved/confirmed/cancelled; - проверка пересечений по датам;
- учет доступности по количеству (
quantity) у типа номера; - сумма бронирования считается автоматически, если
total = 0.
- статусы
- Аналитика и экспорт в Excel (CSV).
- Аналитика:
http://localhost/admin/analytics.php - Экспорт:
http://localhost/admin/exports.php
- Тексты и верстка публичных страниц:
public/index.php,public/rooms.php,public/rooms-single.php,public/contact.php. - Общие блоки сайта:
templates/site/header.php,templates/site/footer.php. - Админка и ее страницы:
public/admin/*.php. - Общие блоки админки:
templates/admin/header.php,templates/admin/footer.php. - PHP-логика:
src/, конфигурация и bootstrap:config/. - Статические ассеты:
public/css,public/js,public/images,public/fonts. - Исходники SCSS:
resources/scss/(сборщик не подключен, правьте CSS напрямую или подключите сборку отдельно). - Схема и начальные данные БД:
database/init.sql.
public/— публичный веб‑корень.public/admin/— админка.src/— PHP‑классы и логика.config/— bootstrap и окружение.database/— схема и сиды.docker/— настройки контейнеров и Nginx.templates/— общие шаблоны.resources/— исходники стилей (SCSS).scripts/— утилиты локального запуска.storage/— служебные файлы (логи и т.п.).composer.json,phpstan.neon,.php-cs-fixer.php— инструменты качества кода.
- Данные лежат в MySQL внутри Docker volume
db-data. - Администраторы хранятся в таблице
usersсpassword_hash(используетсяpassword_hash()). - Данные клиентов и сотрудников — таблицы
clientsиassociates. - Сессии — стандартные PHP-сессии (по умолчанию файловое хранение в контейнере).
- Для просмотра структуры БД можно использовать phpMyAdmin:
http://localhost:8081/.
Если база уже была создана раньше, проще пересоздать volume:
docker compose down -v
docker compose up -d --build
Если нужно сохранить данные, добавьте новые справочники и поля вручную (выполняйте команды по очереди, уже существующие можно пропустить):
docker compose exec -T db mysql -uroot -proot hotel -e "CREATE TABLE IF NOT EXISTS room_views (id INT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, PRIMARY KEY (id), UNIQUE KEY room_views_name_unique (name)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"
docker compose exec -T db mysql -uroot -proot hotel -e "CREATE TABLE IF NOT EXISTS bathroom_types (id INT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, PRIMARY KEY (id), UNIQUE KEY bathroom_types_name_unique (name)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"
docker compose exec -T db mysql -uroot -proot hotel -e "CREATE TABLE IF NOT EXISTS floors (id INT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, level INT NOT NULL, view_id INT UNSIGNED NOT NULL, PRIMARY KEY (id), UNIQUE KEY floors_level_unique (level)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"
docker compose exec -T db mysql -uroot -proot hotel -e "INSERT IGNORE INTO room_views (name) VALUES ('Город'), ('Парк'), ('Внутренний двор');"
docker compose exec -T db mysql -uroot -proot hotel -e "INSERT IGNORE INTO bathroom_types (name) VALUES ('Душевая кабина'), ('Ванна'), ('Ванна и душевая');"
docker compose exec -T db mysql -uroot -proot hotel -e \"INSERT IGNORE INTO floors (name, level, view_id) VALUES ('1 этаж', 1, 1), ('2 этаж', 2, 1), ('3 этаж', 3, 1);\"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE rooms ADD COLUMN floor_id INT UNSIGNED NOT NULL DEFAULT 1 AFTER quantity;"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE rooms ADD COLUMN view_id INT UNSIGNED NOT NULL DEFAULT 1 AFTER floor_id;"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE rooms ADD COLUMN bed_count INT UNSIGNED NOT NULL DEFAULT 1 AFTER view_id;"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE rooms ADD COLUMN bathroom_separate TINYINT(1) NOT NULL DEFAULT 0 AFTER bed_count;"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE rooms ADD COLUMN bathroom_type_id INT UNSIGNED NOT NULL DEFAULT 1 AFTER bathroom_separate;"
Также (при необходимости) примените миграции для статусов бронирований:
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE rooms ADD COLUMN quantity INT UNSIGNED NOT NULL DEFAULT 1 AFTER price;"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE bookings ADD COLUMN status ENUM('reserved','confirmed','cancelled') NOT NULL DEFAULT 'reserved' AFTER date_out;"
docker compose exec -T db mysql -uroot -proot hotel -e "CREATE INDEX bookings_room_status_dates_idx ON bookings (room_id, status, date_in, date_out);"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE rooms ADD CONSTRAINT rooms_quantity_chk CHECK (quantity >= 0);"
Если в БД уже есть проверка дат date_out >= date_in, замените на строгую:
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE bookings DROP CHECK bookings_dates_chk;"
docker compose exec -T db mysql -uroot -proot hotel -e "ALTER TABLE bookings ADD CONSTRAINT bookings_dates_chk CHECK (date_out > date_in);"
Полный сброс (удалит данные):
docker compose down -v
docker compose up -d --build
docker compose run --rm web composer stan
docker compose run --rm web composer cs
docker compose run --rm web composer cs:fix
- База инициализируется из
database/init.sqlпри первом запуске (пустой volume). - HTTPS использует самоподписанный сертификат — браузер покажет предупреждение.