Backend, Frontend, Weekend
Работа над проектом на Laravel становится заметно эффективнее, если автоматизировать как можно больше этапов — от конфигурации окружения до проверки кода и тестирования. В этом материале я расскажу, как сделать рабочий процесс надёжным, уменьшить ручную рутину и поддерживать качество кода на высоком уровне.
Материал рассчитан на тех, кто уже знаком с Laravel и хочет внедрить в проект автоматические проверки, единый стиль кода, статику и готовую Docker-инфраструктуру. Я поделюсь используемыми инструментами, примерами конфигураций и реалистичными скриптами.
Я всегда начинаю проект с продуманной конфигурации Docker Compose — это дает сразу готовое изолированное окружение, минимизирует конфликты зависимостей и ускоряет старт работы. Обычно в моём составе используются следующие сервисы:
services:
app:
build: .
container_name: pet
user: root
depends_on:
- pgdb
- redis
- loki
env_file:
- .env
working_dir: /var/www/
volumes:
- .:/var/www
networks:
- pet
dns:
- 8.8.8.8
- 1.1.1.1
pgdb:
container_name: pgdb
image: postgres
tty: true
restart: always
environment:
- POSTGRES_DB=${DB_DATABASE}
- POSTGRES_USER=${DB_USERNAME}
- POSTGRES_PASSWORD=${DB_PASSWORD}
ports:
- ${PGDB_PORT}
volumes:
- ./docker/postgres:/var/lib/postgresql/data
networks:
- pet
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
ports:
- ${NGINX_PORT}
- "443:443"
volumes:
- .:/var/www
- ./docker/nginx:/etc/nginx/conf.d
- /etc/letsencrypt:/etc/letsencrypt:ro
environment:
- TZ=${SYSTEM_TIMEZONE}
depends_on:
- pgdb
- app
- pgadmin
networks:
- pet
pgadmin:
image: dpage/pgadmin4:latest
restart: always
depends_on:
- pgdb
environment:
- PGADMIN_DEFAULT_EMAIL=${PGADMIN_EMAIL}
- PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PASSWORD}
ports:
- ${PGADMIN_PORT}
networks:
- pet
redis:
image: redis:latest
container_name: redis
restart: always
ports:
- ${REDIS_PORT}
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
networks:
- pet
redisinsight:
image: redislabs/redisinsight:latest
container_name: redisinsight
ports:
- ${REDISINSIGHT_PORT}
volumes:
- ./docker/redisinsight:/db
restart: always
networks:
- pet
grafana:
image: grafana/grafana:latest
container_name: grafana
user: "472"
ports:
- ${GRAFANA_PORT}
environment:
- GF_SECURITY_ADMIN_USER=${GRAFANA_USER}
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- ./docker/grafana:/var/lib/grafana
depends_on:
- loki
networks:
- pet
queue:
build: .
image: docker_template:latest
container_name: laravel_queue
restart: always
depends_on:
- app
- redis
env_file:
- .env
working_dir: /var/www
volumes:
- .:/var/www
command: php artisan queue:work --sleep=3 --tries=3 --timeout=90
networks:
- pet
dns:
- 8.8.8.8
- 1.1.1.1
loki:
image: grafana/loki:latest
container_name: loki
ports:
- ${LOKI_PORT}
networks:
- pet
volumes:
pgdata:
networks:
pet:
driver: bridge
Каждый из этих сервисов разворачивается в отдельном контейнере. Такой подход даёт преимущества:
Совет: можно использовать готовый шаблон docker-compose.yml, который сразу поднимает все сервисы и настраивает базовые параметры Laravel.
Для автоматического форматирования и приведения к единому стилю я использую laravel/pint. Он позволяет:
Пример конфигурации pint.json
:
{
"preset": "psr12",
"exclude": [
"vendor",
"storage",
"node_modules",
"bootstrap/cache"
],
"rules": {
"array_syntax": {
"syntax": "short"
},
"binary_operator_spaces": {
"default": "single_space"
},
"braces": true,
"class_attributes_separation": {
"elements": {
"const": "one",
"method": "one",
"property": "one"
}
},
"no_unused_imports": true,
"ordered_imports": true,
"phpdoc_separation": true,
"phpdoc_align": true,
"single_quote": true,
"ternary_to_null_coalescing": true,
"trailing_comma_in_multiline": {
"after_heredoc": true
},
"types_spaces": {
"space": "none"
},
"phpdoc_no_empty_return": false,
"no_superfluous_phpdoc_tags": false,
"concat_space": {
"spacing": "one"
}
}
}
Такая конфигурация помогает стандартизировать стиль: синтаксис массивов, расположение операторов, форматирование импортов и PHPDoc.
Запуск Pint перед коммитом — хорошая практика, она поддерживает чистоту кода автоматически.
Чтобы ловить ошибки и потенциальные проблемы ещё на этапе разработки, я применяю комбинацию phpstan/phpstan и nunomaduro/larastan. Эти инструменты позволяют:
Пример конфигурации phpstan.neon
:
parameters:
level: 6
paths:
- app
- routes
excludePaths:
- vendor
- storage
- bootstrap
errorFormat: table
checkMissingVarTagTypehint: false
inferPrivatePropertyTypeFromConstructor: true
ignoreErrors:
- identifier: missingType.iterableValue
- identifier: missingType.generics
- '#referenced with incorrect case#'
includes:
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
Основные преимущества такого подхода:
Чтобы гарантировать, что все коммиты соответствуют стандартам, я применяю Git Hooks + shell-скрипты:
Pre-commit: проверка изменённых файлов обрабатываются только изменённые файлы (для скорости); запускаются Pint и PHPStan на этих файлах; при ошибках коммит блокируется до исправления.
Постепенное исправление старых ошибок особенно полезно на существующих проектах: допускаются коммиты, если количество ошибок в файле уменьшилось; таким образом проверка внедряется постепенно, без резкого прерывания работы команды.
Проверка наличия тестов
Скрипт проверяет, что для любого нового или изменённого класса создан соответствующий тест в директории tests. Например, если добавлен класс app/Services/UserService.php
, ожидается файл tests/Unit/Services/UserServiceTest.php
.
Проверка сборки Docker Отдельный скрипт останавливает текущие контейнеры, пересобирает стек и проверяет, что все сервисы поднялись корректно. Это позволяет убедиться, что изменения в конфигурации или коде не сломали окружение.
Скрипт для проверки с PHPStan (pre-commit / push)
#!/bin/bash
COMMAND="$1" # commit или push
if [ "$COMMAND" = "commit" ]; then
NEW_FILES=$(git diff --cached --name-only --diff-filter=A | grep '\.php$')
if [ -n "$NEW_FILES" ]; then
vendor/bin/phpstan analyse --no-progress --error-format=table $NEW_FILES || exit 1
fi
fi
BASELINE_FILE=".phpstan-error-count.json"
[ ! -f "$BASELINE_FILE" ] && echo "{}" > "$BASELINE_FILE"
if [ "$COMMAND" = "commit" ]; then
ALL_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$' || true)
elif [ "$COMMAND" = "push" ]; then
BRANCH=$(git rev-parse --abbrev-ref HEAD)
ALL_FILES=$(git diff --name-only origin/$BRANCH --diff-filter=ACM | grep '\.php$' || true)
fi
if [ -n "$ALL_FILES" ]; then
for FILE in $ALL_FILES; do
ERR_NEW=$(vendor/bin/phpstan analyse --error-format=raw --no-progress "$FILE" 2>/dev/null | grep -c '^')
ERR_OLD=$(jq -r --arg file "$FILE" '.[$file] // empty' "$BASELINE_FILE")
[ -z "$ERR_OLD" ] && ERR_OLD=$ERR_NEW
TARGET=$((ERR_OLD - 1))
[ "$TARGET" -lt 0 ] && TARGET=0
if [ "$ERR_NEW" -le "$TARGET" ]; then
jq --arg file "$FILE" --argjson errors "$ERR_NEW" '.[$file] = $errors' "$BASELINE_FILE" > tmp && mv tmp "$BASELINE_FILE"
else
echo "Ошибка статического анализа в $FILE: $ERR_NEW (допустимо ≤ $TARGET)"
vendor/bin/phpstan analyse --error-format=table "$FILE"
exit 1
fi
done
fi
exit 0
Скрипт для проверки Pint стиля
#!/bin/bash
COMMAND="$1"
if [ "$COMMAND" = "commit" ]; then
ALL_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$' || true)
elif [ "$COMMAND" = "push" ]; then
BRANCH=$(git rev-parse --abbrev-ref HEAD)
ALL_FILES=$(git diff --name-only origin/$BRANCH --diff-filter=ACM | grep '\.php$' || true)
fi
if [ -n "$ALL_FILES" ]; then
vendor/bin/pint --test $ALL_FILES
if [ $? -ne 0 ]; then
vendor/bin/pint $ALL_FILES
echo "$ALL_FILES" | xargs git add
exit 1
fi
fi
exit 0
Проверка наличия тестов для классов
Для достижения этой цели я использую скрипт, который проверяет наличие тестов для каждого PHP-класса, добавленного или изменённого в коммите.
Скрипт получает список изменённых и добавленных PHP-файлов и ищет соответствующий тестовый файл в директории tests.
Например, если в проекте есть класс app/Services/UserService.php, скрипт потребует создать файл теста tests/Unit/Services/UserServiceTest.php. Таким образом, любой новый или изменённый класс обязательно должен иметь соответствующий тест, что помогает поддерживать качество и надёжность кода.
Это скрипт, который постоянно дополняется, поэтому актуальную версию вы можете посмотреть здесь – https://github.com/prog-time/git-hooks
Проверка работы Docker сборки
Не менее важно регулярно проверять работу Docker сборки. Для этого я создаю отдельный shell-скрипт, который перезапускает все контейнеры и проверяет, что они успешно запустились. Такой подход позволяет убедиться, что изменения в конфигурации или коде не нарушили работу сервисов и приложение корректно поднимается в локальной среде.
Скрипт может автоматически останавливать текущие контейнеры, заново собирать их и запускать в фоне. После запуска выполняется проверка состояния через docker ps
или docker compose ps
, чтобы убедиться, что все контейнеры находятся в статусе healthy или up.
#!/bin/bash
echo "=== Остановка всех контейнеров ==="
docker-compose down
echo "=== Сборка контейнеров ==="
docker-compose build
echo "=== Запуск контейнеров в фоне ==="
docker-compose up -d
# Пауза для запуска сервисов
echo "=== Ждем 5 секунд для старта сервисов ==="
sleep 5
echo "=== Проверка состояния контейнеров ==="
# Получаем статус всех контейнеров
STATUS=$(docker-compose ps --services --filter "status=running")
if [ -z "$STATUS" ]; then
echo "Ошибка: ни один контейнер не запущен!"
exit 1
else
echo "Запущенные контейнеры:"
docker-compose ps
fi
# Дополнительно можно проверять HEALTHCHECK каждого контейнера
echo "=== Проверка состояния HEALTH ==="
docker ps --filter "health=unhealthy" --format "table {{.Names}}\t{{.Status}}"
echo "=== Скрипт завершен ==="
exit 0
Автоматизация разработки в Laravel — не просто модный тренд, а способ сделать вашу команду эффективнее, а проект — надежнее.
Основные принципы:
Если вы внедрите эти практики, вы:
Автоматизируйте рутинные задачи — и команда сможет сфокусироваться на настоящей ценности: создании функционала и развитии продукта.
Backend, Frontend, Weekend
Привет, сообщество Laravel!
По вашим многочисленным запросам я выпустил третий релиз TG Support Bot — бота для технической поддержки на Laravel. За последние месяцы проект получил вдвое больше звёзд на GitHub, что мотивирует развивать его дальше.
В этом обновлении — API для подключения внешних источников, новые консольные команды, Swagger-документация и другие улучшения.
TG Support Bot — это решение для организации поддержки клиентов через Telegram и ВКонтакте.
Поддержите проект ⭐ на GitHub: https://github.com/prog-time/tg-support-bot
Присоединяйтесь к Telegram-группе для обсуждения: https://t.me/pt_tg_support
Youtube: https://youtu.be/yNiNtFWOF2w
Rutube: https://rutube.ru/video/bdd0cc5ab4e13530fd7e0c2413931211/
ВК Видео: https://vkvideo.ru/video-141526561_456239132
Реализовано универсальное API для подключения:
Доступные методы API:
Как подключить:
php artisan app:generate-token {название_источника}
Подробнее в Wiki на GitHub
Добавлен генератор Swagger-документации:
php artisan swagger:generate
php artisan telegram:set-webhook — настройка вебхука Telegram через консоль php artisan app:generate-token — генерация API-токена
Обновление функционала зависит только от вас. Предлагайте свои идеи в Telegram группе и голосуйте за них в теме “Голосование”. Если ваша идея наберёт много положительных голосов, то она обязательно будет включена в базовый функционал бота для технической поддержки.
Спасибо за поддержку! Если у вас есть вопросы по интеграции — пишите в Issues или Telegram.
{message}