Rinat Sarmuldin. email--> ura07srr@gmail.com
✔ Контроль доступа через Voter ✔ Реляционная БД ✔ Отсутствие логики в UI ✔ Чёткая архитектура ✔ Поддержка расширяемости ✔ Минималистичный интерфейс
В проекте настроено полноценное тестовое окружение Symfony (test environment) с отдельной PostgreSQL базой данных, миграциями и фикстурами. Реализованы functional-тесты безопасности, проверяющие корректную работу firewall и редиректов для неаутентифицированных пользователей. Конфигурация PHPUnit выполняется через phpunit.xml с явным определением DATABASE_URL, что обеспечивает стабильный и воспроизводимый запуск тестов.
Inventory App — учебный курсовой проект, реализующий систему управления инвентарями (реестрами объектов).
Основной акцент сделан на архитектуру backend-приложения, модель данных и контроль доступа, а не на визуальную часть.
Проект реализован с использованием Symfony 6.4 LTS и соответствует требованиям курсовой работы.
Реализовать backend-приложение с корректной архитектурой, серверным контролем доступа и расширяемой моделью данных.
- Реализовать управление инвентарями и их элементами
- Разграничить права доступа пользователей
- Обеспечить контроль доступа на уровне сервера
- Поддержать расширяемость (кастомные поля, кастомные ID)
- Соблюсти требования курсовой работы
- PHP 8.2
- Symfony 6.4 LTS
- Doctrine ORM
- PostgreSQL
- Twig
- Symfony Security (Voters)
Проект построен с чётким разделением ответственности.
Слой
Назначение
Controller
Обработка HTTP-запросов
Entity
Доменная модель
Repository
Работа с БД
DTO
Передача данных
Service
Бизнес-логика
Security / Voter
Контроль доступа
Twig
Отображение данных
Бизнес-логика не размещается в шаблонах и контроллерах.
- User — пользователь системы
- Inventory — инвентарь (реестр)
- InventoryItem — элемент инвентаря
- InventoryAccess — ACL-права пользователей
- CustomField — кастомные поля
- Discussion / Like — обсуждения и лайки
- Реляционная модель
- Нет JSON-хранилищ
- Нет динамического создания таблиц
- Используются индексы и UNIQUE-ограничения
- Связи описаны через Doctrine ORM
Тип
Описание
Guest
Неавторизованный пользователь
User
Обычный пользователь
Owner
Владелец инвентаря
Admin
Администратор
Создаются через Doctrine Fixtures.
Администратор
- Email:
admin@test.com - Пароль:
admin123
Пользователь
- Email:
user@test.com - Пароль:
user123
Контроль доступа реализован на серверной стороне с использованием Symfony Security Voters.
- INVENTORY_VIEW
- INVENTORY_CREATE_ITEM
- INVENTORY_EDIT_ITEM
- INVENTORY_DELETE_ITEM
- INVENTORY_MANAGE_ACCESS
- DISCUSSION_WRITE
Условие
Права
Guest + public inventory
Только VIEW
User + чужой inventory
Только VIEW
Owner
Полный доступ
Admin
Полный доступ
InventoryAccess READ
VIEW
InventoryAccess WRITE
CREATE / EDIT / DELETE
Публичность инвентаря не даёт права на изменение данных.
Реализовано:
- Создание инвентарей
- Просмотр публичных и собственных инвентарей
- Управление доступом пользователей
- Привязка к владельцу
Каждый инвентарь содержит:
- владельца
- статус публичности
- элементы
- кастомные поля
Поддерживаются операции:
- Просмотр
- Создание
- Редактирование
- Удаление
Все действия защищены ACL-проверками через InventoryVoter.
Реализована архитектурная поддержка кастомных полей:
- фиксированное количество
- типизация
- расширяемость без изменения схемы БД
Реализована backend-поддержка:
- обсуждений
- лайков
- серверных ACL-проверок
UI используется только для демонстрации архитектуры.
- Минималистичный интерфейс
- Нейтральная (серая) цветовая схема
- Кнопки действий отображаются только при наличии прав
- В шаблонах отсутствует бизнес-логика
UI не влияет на безопасность — все проверки выполняются на сервере.
Данный документ описывает развёртывание проекта, настройку базы данных, а также запуск и назначение всех unit и functional тестов.
Документация подготовлена с учётом требований и не противоречит архитектуре проекта.
- PHP 8.2
- Composer
- PostgreSQL 15+
- Git
- (опционально) Symfony CLI
php -v
composer -V
psql --version
2. Установка проекта
2.1 Клонирование репозитория
git clone <REPOSITORY_URL>
cd inventory-app
2.2 Установка зависимостей
composer install
3. Настройка базы данных
Проект использует PostgreSQL + Doctrine ORM.
Для тестов используется отдельная test-база, что соответствует best practice и требованиям.
3.1 Создание пользователя и баз данных (один раз)
В PostgreSQL:
CREATE USER inventory_user WITH PASSWORD 'strongpassword';
CREATE DATABASE inventory_app OWNER inventory_user;
CREATE DATABASE inventory_app_test OWNER inventory_user;
3.2 Настройка окружения
.env
DATABASE_URL="postgresql://inventory_user:strongpassword@127.0.0.1:5432/inventory_app?serverVersion=15&charset=utf8"
.env.test
DATABASE_URL="postgresql://inventory_user:strongpassword@127.0.0.1:5432/inventory_app_test?serverVersion=15&charset=utf8"
APP_ENV=test
APP_DEBUG=0
4. Подготовка базы данных
4.1 Применение миграций (dev / prod)
php bin/console doctrine:migrations:migrate
4.2 Применение миграций для тестовой БД
php bin/console doctrine:migrations:migrate --env=test
4.3 Загрузка фикстур (только test)
rm -rf var/cache/test
php bin/console doctrine:fixtures:load --env=test --no-interaction
Фикстуры создают:
admin@test.com / admin123
user@test.com / user123
public inventory (ADMIN)
private inventory (ADMIN)
discussion + likes
⚠️ Фикстуры используются исключительно для тестов и не влияют на production-логику.
5. Запуск тестов
5.1 🔹 Запуск всех тестов одной командой
APP_DEBUG=0 ./vendor/bin/phpunit
5.2 🔹 Только Unit-тесты
APP_DEBUG=0 ./vendor/bin/phpunit tests/Unit --testdox
5.3 🔹 Только Functional-тесты
APP_DEBUG=0 ./vendor/bin/phpunit tests/Functional --testdox
5.4 🔹 Запуск конкретного теста
APP_DEBUG=0 ./vendor/bin/phpunit tests/Unit/Security/InventoryEditOwnerVoterTest.php --testdox
6. Описание тестов =>
6.1 Unit-тесты (Business Logic)
Unit-тесты проверяют чистую бизнес-логику, без HTTP и без базы данных.
🔹 InventoryVoter (ACL)
Проверяемые правила:
Admin — полный доступ
Owner — полный доступ
Guest — только просмотр public inventory
READ — только VIEW
WRITE — items + discussion
MANAGE_ACCESS — только owner / admin
Это ключевая бизнес-логика проекта.
🔹 InventoryEditOwnerVoterTest
Проверяет, что владелец inventory может редактировать его.
🔹 InventoryEditForeignUserVoterTest
Проверяет, что обычный пользователь не может редактировать чужой inventory.
🔹 InventoryEditAdminVoterTest
Проверяет, что admin может редактировать любой inventory.
🔹 InventoryEditWriteAccessVoterTest
Проверяет, что пользователь с WRITE-доступом может редактировать inventory.
🔹 InventoryManageAccessOwnerVoterTest
Проверяет, что только owner может управлять ACL.
🔹 InventoryManageAccessAdminVoterTest
Проверяет, что admin может управлять ACL любого inventory.
🔹 InventoryDiscussion*VoterTest
Проверяется доступ к discussion:
Owner — может писать
Admin — может писать
WRITE — может писать
READ — не может писать
Guest — не может писать
6.2 Functional-тесты (User Scenarios)
Functional-тесты проверяют реальное поведение приложения через HTTP.
🔹 Login / Logout
Пользователь может войти
Пользователь выходит
После logout доступ запрещён
🔹 AccessControlTest
Guest не может зайти в защищённые страницы.
🔹 InventoryOwnerVoterTest
User не может открыть private inventory другого пользователя (403).
🔹 DiscussionGuestTest
Guest не может писать сообщения в discussion через HTTP.
Functional-тесты подтверждают корректную работу unit-логики в реальном приложении, без дублирования бизнес-правил.- APP_ENV=test php bin/console cache:clear
&& APP_ENV=test php bin/console doctrine:schema:validate
&& APP_ENV=test ./vendor/bin/phpunit
Located in tests/Unit. They validate isolated business logic and security rules without HTTP layer. Run:
- php bin/phpunit tests/Unit
(Functional-тест проверяет поведение приложения через HTTP: маршруты, контроллеры и систему безопасности, как при реальном использовании).
Located in tests/Functional. They test application behavior via real HTTP requests, including routing, controllers and security.
Run:
- php bin/phpunit tests/Functional
- php bin/phpunit
- Enable PostgreSQL-16 module in OSPanel.
- Start the module and check logs (
logs/postgresql.log) if it fails.
cd C:OSPanelmodulesdatabasesPostgreSQL-16bin
pg_ctl -D "C:OSPanelmodulesdatabasesPostgreSQL-16data" start
Verify listening port
* netstat -ano | findstr 5432
Expected: LISTENING on 127.0.0.1:5432 or 127.0.1.x:5432.
⚙️ 2. Configure PostgreSQL Network Access
postgresql.conf
listen_addresses = '*'
port = 5432
pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
local all all md5
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
Restart PostgreSQL after changes.
🐘 3. Enable PHP PostgreSQL Extensions (PHP 8.2)
Edit php.ini for CLI (used by bin/console):
Path example:
C:OSPanelmodulesphpPHP-8.2php.ini
Enable:
extension=pdo_pgsql
extension=pgsql
Restart OSPanel and verify:
php -m | findstr pgsql
Expected: pdo_pgsql, pgsql.
🗄️ 4. Create Database and User, Grant Permissions
Connect as superuser:
cd C:OSPanelmodulesdatabasesPostgreSQL-16bin
psql -U postgres -h 127.0.0.1 -p 5432
SQL commands:
CREATE USER inventory_test WITH PASSWORD 'strongpassword';
CREATE DATABASE inventory_app_test OWNER inventory_test;
GRANT USAGE ON SCHEMA public TO inventory_test;
GRANT CREATE ON SCHEMA public TO inventory_test;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO inventory_test;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO inventory_test;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO inventory_test;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO inventory_test;
🔗 5. Symfony and Doctrine Configuration
.env.test
APP_ENV=test
APP_DEBUG=0
DATABASE_URL="pgsql://inventory_test:strongpassword@127.0.0.1:5432/inventory_app_test?serverVersion=16&charset=utf8"
config/packages/doctrine.yaml
doctrine:
dbal:
driver: pdo_pgsql
url: '%env(resolve:DATABASE_URL)%'
profiling_collect_backtrace: '%kernel.debug%'
use_savepoints: true
orm:
auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true
report_fields_where_declared: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'AppEntity'
alias: App
when@test:
doctrine:
dbal:
dbname_suffix: ''
🧪 6. PHPUnit Configuration
phpunit.xml.dist
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<php>
<env name="KERNEL_CLASS" value="AppKernel"/>
<env name="APP_ENV" value="test"/>
<env name="APP_DEBUG" value="0"/>
</php>
</phpunit>
▶️ 7. Run Migrations and Tests (Windows)
Set environment variables
CMD:
set APP_ENV=test
php bin/console cache:clear
PowerShell:
$env:APP_ENV="test"
php bin/console cache:clear
Database setup
php bin/console doctrine:database:create --env=test
php bin/console doctrine:migrations:migrate --env=test
Run tests
php bin/phpunit
php bin/phpunit tests/Unit
🛠️ 8. Troubleshooting
could not find driver → Enable pdo_pgsql and pgsql in php.ini.
connection refused → PostgreSQL not running or listening on different IP. Fix listen_addresses and pg_hba.conf.
permission denied for schema public → Grant schema rights to inventory_test.
You must set the KERNEL_CLASS → Add <env name="KERNEL_CLASS" value="AppKernel"/> in phpunit.xml.dist.
✅ 9. Final Checklist
PostgreSQL running and listening on port 5432.
PHP extensions pdo_pgsql and pgsql enabled.
Database inventory_app_test created, user inventory_test has full rights.
Doctrine configured with pdo_pgsql driver.
PHPUnit configured with KERNEL_CLASS and test env.
Commands run successfully with APP_ENV=test.