Install and configure Sonata Admin on Symfony 4
Welcome all. This article will talk about Symfony 4 and Sonata Admin.
During the installation process, I encountered a lot of inaccuracies in the documentation and the documentation itself was scattered in several places. Here I will consider the whole process, from the creation of the project to the authorization along with authentication.
Some parts of the settings were taken from the official documentation, some were taken from the comments on GitHub, where the installation problems were discussed. Possible pitfalls and ways around them are also painted.
Creating a symfony project
$ composer create-project symfony/skeleton sonatademo
$ cd sonatademo
To use the Symfony Embedded Web Server, you must install the Symfony Client .
We start.
$ symfony serve
We follow the link http://127.0.0.1:8000/ and we will receive the standard Symfony greeting. So everything works correctly.
Install Sonata Admin
$ composer require sonata-project/admin-bundle
Sonata Admin and DB
In order to interact with the database, you need to install one of three libraries:
- SonataDoctrineORMAdminBundle (integration with Doctrine ORM);
- SonataDoctrineMongoDBAdminBundle (integration with Doctrine MongoDB ODM);
- SonataDoctrinePhpcrAdminBundle (integration with Doctrine PHPCR ODM).
In this article, I use SonataDoctrineORMAdminBundle
what is more than enough to work with MySQL
or Sqlite
.
Install SonataDoctrineORMAdminBundle
.
$ composer require sonata-project/doctrine-orm-admin-bundle
Now set up work with Sqlite
.
Open the .env file and ###> doctrine/doctrine-bundle ###
change it in the section DATABASE_URL
.
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
Since Symfony Flex does almost all the work for us during the installation, it remains to do a few manipulations to get the final result.
# config/packages/framework.yaml
framework:
translator: { fallbacks: ['en'] }
We carry out
$ composer dump-env dev
Now we follow the link http://127.0.0.1:8000/admin and we see an empty standard administrative interface.
Entity Creation
Let's create two entities for example, connected by a one-to-many relationship.
addresses = new ArrayCollection();
}
public function getAddresses()
{
return $this->addresses;
}
/**
* @return string
*/
public function getTitle(): ?string
{
return $this->title;
}
/**
* @param string $title
* @return City
*/
public function setTitle(string $title): City
{
$this->title = $title;
return $this;
}
/**
* @return string
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @param string $description
* @return City
*/
public function setDescription(string $description): City
{
$this->description = $description;
return $this;
}
/**
* @return bool
*/
public function isBig(): ?bool
{
return $this->isBig;
}
/**
* @param bool $isBig
* @return City
*/
public function setIsBig(bool $isBig): City
{
$this->isBig = $isBig;
return $this;
}
public function __toString()
{
return $this->title;
}
}
title;
}
/**
* @param string $title
* @return Address
*/
public function setTitle(string $title): Address
{
$this->title = $title;
return $this;
}
/**
* @return string
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @param string $description
* @return Address
*/
public function setDescription(string $description): Address
{
$this->description = $description;
return $this;
}
/**
* @return City
*/
public function getCity(): ?City
{
return $this->city;
}
/**
* @param City $city
* @return Address
*/
public function setCity(City $city)
{
$this->city = $city;
return $this;
}
public function __toString()
{
return $this->title;
}
}
We synchronize with the database.
bin/console doctrine:schema:create
Entity Configuration for Sonata Admin
It is necessary for each entity to create a separate file with a description of how Sonata Admin should work.
add('title', TextType::class);
$formMapper->add('description', TextareaType::class);
$formMapper->add('isBig', CheckboxType::class);
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper->add('title');
$datagridMapper->add('isBig');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->addIdentifier('title');
$listMapper->addIdentifier('isBig');
}
}
add('title', TextType::class);
$formMapper->add('description', TextareaType::class);
$formMapper->add('city', ModelType::class, [
'class' => City::class,
'property' => 'title',
]);
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper->add('title');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->addIdentifier('title');
}
}
These classes need to be described in service.yaml
.
# config/service.yaml
services:
...
App\Admin\CityAdmin:
arguments: [~, App\Entity\City, ~]
tags:
- { name: sonata.admin, manager_type: orm, label: City }
App\Admin\AddressAdmin:
arguments: [~, App\Entity\Address, ~]
tags:
- { name: sonata.admin, manager_type: orm, label: Address }
If errors occur when entering the administrative part, for example Unable to generate a URL for the named route
, then you need to clean the application cache and try again.
bin/console cache:clear
Теперь, если перейти по ссылке http://127.0.0.1:8000/admin увидим список из двух элементов Address
и City
, где можно просматривать списки и создавать новые сущности.
Авторизация и аутентификация
Для начала создадим сущность пользователя.
id;
}
}
И заодно создадим сущность группы пользователя.
id;
}
}
После настроим Twig как движок шаблонов.
framework:
...
templating:
engines: ['twig']
На данный момент есть проблемы с работой Symfony Flex и FOSUserBundle. Более подробно можно узнать по ссылкам #2562, #2708 и #2801.
Пока данные проблемы не решены, нужно сделать пару дополнительных манипуляций перед установкой Sonata User Bundle
.
# config/service.yaml
services:
...
mailer:
alias: fos_user.mailer.noop
public: true
# config/packages/fos_user.yaml
fos_user:
db_driver: orm
firewall_name: main
user_class: App\Entity\User
registration:
confirmation:
enabled: false
from_email:
address: '%env(MAILER_USER_ADDRESS)%'
sender_name: '%env(MAILER_USER_NAME)%'
service:
user_manager: sonata.user.orm.user_manager
mailer: 'fos_user.mailer.noop'
group:
group_class: App\Entity\Group
group_manager: sonata.user.orm.group_manager
После чего, можно устанавливать бандл.
$ composer require sonata-project/user-bundle
Настройка ACL
В Symfony 4 ACL вынесли в отдельный бандл symfony/acl-bundle
. Поэтому его нужно отдельно установить.
composer require symfony/acl-bundle
# config/packages/sonata_user.yaml
sonata_user:
security_acl: true
manager_type: orm
# config/packages/acl.yaml
acl:
connection: default
Настройка Doctrine
# config/packages/doctrine.yaml
doctrine:
orm:
mappings:
SonataUserBundle: ~
FOSUserBundle: ~
Настройка работы с почтой
Так как в рамках этой статьи работа с почтой не рассматриватеся, то укажем заглушку вместо реального сервиса.
# config/packages/sonata_user.yaml
sonata_user:
mailer: fos_user.mailer.noop
Интеграция User Bundle в Sonata Admin
# config/routes.yaml
sonata_user_admin_security:
resource: '@SonataUserBundle/Resources/config/routing/admin_security.xml'
prefix: /admin
sonata_user_admin_resetting:
resource: '@SonataUserBundle/Resources/config/routing/admin_resetting.xml'
prefix: /admin/resetting
# config/packages/security.yaml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
providers:
fos_userbundle:
id: fos_user.user_provider.username
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# -> custom firewall for the admin area of the URL
admin:
pattern: /admin(.*)
context: user
form_login:
provider: fos_userbundle
login_path: /admin/login
use_forward: false
check_path: /admin/login_check
failure_path: null
logout:
path: /admin/logout
target: /admin/login
anonymous: true
# -> end custom configuration
# default login area for standard users
# This firewall is used to handle the public login area
# This part is handled by the FOS User Bundle
main:
pattern: .*
context: user
form_login:
provider: fos_userbundle
login_path: /login
use_forward: false
check_path: /login_check
failure_path: null
logout: true
anonymous: true
access_control:
# Admin login page needs to be accessed without credential
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Secured part of the site
# This config requires being logged for the whole site and having the admin role for the admin part.
# Change these rules to adapt them to your needs
- { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
- { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
# config/packages/sonata_user.yaml
sonata_user:
...
class:
user: App\Entity\User
group: App\Entity\Group
Теперь можно обновить ACL и БД.
$ bin/console acl:init
$ php bin/console doctrine:schema:update --force
Создаем супер пользователя. Указываем имя demo
и пароль demo
.
$ bin/console fos:user:create --super-admin
Please choose a username:demo
Please choose an email:demo@demo.com
Please choose a password:
Created user demo
Для корректной настройки наших Admin классов вместе с ACL нужно внести изменения в настройки.
sonata_admin:
...
security:
handler: sonata.admin.security.handler.acl
После запустить следующее:
$ bin/console sonata:admin:setup-acl
Starting ACL AdminBundle configuration
> install ACL for App\Admin\AddressAdmin
- add role: ROLE_APP\ADMIN\ADDRESSADMIN_GUEST, permissions: ["LIST"]
- add role: ROLE_APP\ADMIN\ADDRESSADMIN_STAFF, permissions: ["LIST","CREATE"]
- add role: ROLE_APP\ADMIN\ADDRESSADMIN_EDITOR, permissions: ["OPERATOR","EXPORT"]
- add role: ROLE_APP\ADMIN\ADDRESSADMIN_ADMIN, permissions: ["MASTER"]
> install ACL for App\Admin\CityAdmin
- add role: ROLE_APP\ADMIN\CITYADMIN_GUEST, permissions: ["LIST"]
- add role: ROLE_APP\ADMIN\CITYADMIN_STAFF, permissions: ["LIST","CREATE"]
- add role: ROLE_APP\ADMIN\CITYADMIN_EDITOR, permissions: ["OPERATOR","EXPORT"]
- add role: ROLE_APP\ADMIN\CITYADMIN_ADMIN, permissions: ["MASTER"]
> install ACL for sonata.user.admin.user
- add role: ROLE_SONATA_USER_ADMIN_USER_GUEST, permissions: ["LIST"]
- add role: ROLE_SONATA_USER_ADMIN_USER_STAFF, permissions: ["LIST","CREATE"]
- add role: ROLE_SONATA_USER_ADMIN_USER_EDITOR, permissions: ["OPERATOR","EXPORT"]
- add role: ROLE_SONATA_USER_ADMIN_USER_ADMIN, permissions: ["MASTER"]
> install ACL for sonata.user.admin.group
- add role: ROLE_SONATA_USER_ADMIN_GROUP_GUEST, permissions: ["LIST"]
- add role: ROLE_SONATA_USER_ADMIN_GROUP_STAFF, permissions: ["LIST","CREATE"]
- add role: ROLE_SONATA_USER_ADMIN_GROUP_EDITOR, permissions: ["OPERATOR","EXPORT"]
- add role: ROLE_SONATA_USER_ADMIN_GROUP_ADMIN, permissions: ["MASTER"]
Теперь при попытке зайти по адресу http://127.0.0.1:8000/admin нас перенаправит на http://127.0.0.1:8000/admin/login.
Вводим demo/demo и попадаем в административную часть.
Итоги
После всех манипуляций мы получили работающую административную часть Sonata Admin на Symfony 4 вместе с аутентификацией и авторизацией c помощью Sonata User + ACL.
Thanks to all. If you have questions and comments, I will listen to them in the comments.