Instalar y configurar Sonata Admin en Symfony 4


Un saludo a todos. Este art铆culo hablar谩 sobre Symfony 4 y Sonata Admin.


Durante el proceso de instalaci贸n, encontr茅 muchas imprecisiones en la documentaci贸n y la documentaci贸n en s铆 estaba dispersa en varios lugares. Aqu铆 considerar茅 todo el proceso, desde la creaci贸n del proyecto hasta la autorizaci贸n junto con la autenticaci贸n.


Algunas partes de la configuraci贸n se tomaron de la documentaci贸n oficial, otras se tomaron de los comentarios en GitHub, donde se discutieron los problemas de instalaci贸n. Los posibles obst谩culos y formas de evitarlos tambi茅n est谩n pintados.


Crear un proyecto de Symfony


$ composer create-project symfony/skeleton sonatademo 

 $ cd sonatademo 

Para usar el servidor web incorporado de Symfony, debe instalar el cliente de Symfony .


Empezamos


 $ symfony serve 

Seguimos el enlace http://127.0.0.1:8000/ y recibiremos el saludo est谩ndar de Symfony. Entonces todo funciona correctamente.



Instalar Sonata Admin


 $ composer require sonata-project/admin-bundle 

Sonata Admin y DB


Para interactuar con la base de datos, debe instalar una de las tres bibliotecas:



En este art铆culo estoy usando SonataDoctrineORMAdminBundle , que es m谩s que suficiente para trabajar con MySQL o Sqlite .


Instale SonataDoctrineORMAdminBundle .


 $ composer require sonata-project/doctrine-orm-admin-bundle 

Ahora configuremos el trabajo con Sqlite .


Abra el archivo .env y en la secci贸n ###> doctrine/doctrine-bundle ### change DATABASE_URL .


 DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" 

Dado que Symfony Flex hace casi todo el trabajo por nosotros durante la instalaci贸n, queda por hacer algunas manipulaciones para obtener el resultado final.


 # config/packages/framework.yaml framework: translator: { fallbacks: ['en'] } 

Llevamos a cabo


 $ composer dump-env dev 

Ahora seguimos el enlace http://127.0.0.1:8000/admin y vemos una interfaz administrativa est谩ndar vac铆a.



Creaci贸n de entidad


Creemos dos entidades, por ejemplo, conectadas por una relaci贸n de uno a muchos.


 <?php // src/Entity/City.php namespace App\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class City { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer", options={"unsigned":true}) */ private $id; /** * @var string * * @ORM\Column(type="string") */ private $title; /** * @var string * * @ORM\Column(type="text") */ private $description; /** * @var bool * * @ORM\Column(type="boolean") */ private $isBig = false; /** * @ORM\OneToMany(targetEntity="Address", mappedBy="city") */ private $addresses; public function __construct() { $this->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; } } 

 <?php // src/Entity/Address.php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Address { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer", options={"unsigned":true}) */ private $id; /** * @var string * * @ORM\Column(type="string") */ private $title; /** * @var string * * @ORM\Column(type="text") */ private $description; /** * @ORM\ManyToOne(targetEntity="City", inversedBy="addresses") */ private $city; /** * @return string */ public function getTitle(): ?string { return $this->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; } } 

Nos sincronizamos con la base de datos.


 bin/console doctrine:schema:create 

Configuraci贸n de entidad para administrador de sonata


Es necesario que cada entidad cree un archivo separado con una descripci贸n de c贸mo deber铆a funcionar Sonata Admin.


 <?php // src/Admin/CityAdmin.php namespace App\Admin; use App\Entity\Address; use App\Entity\City; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Form\Type\CollectionType; use Sonata\AdminBundle\Form\Type\ModelType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; final class CityAdmin extends AbstractAdmin { protected function configureFormFields(FormMapper $formMapper) { $formMapper->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'); } } 

 <?php // src/Admin/AddressAdmin.php namespace App\Admin; use App\Entity\City; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Form\Type\ModelType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; final class AddressAdmin extends AbstractAdmin { protected function configureFormFields(FormMapper $formMapper) { $formMapper->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'); } } 

Estas clases deben describirse en 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 } 

Si se producen errores al ingresar a la parte administrativa, por ejemplo, Unable to generate a URL for the named route , entonces debe borrar el cach茅 de la aplicaci贸n e intentar nuevamente.


 bin/console cache:clear 

Ahora, si hace clic en el enlace http://127.0.0.1:8000/admin , veremos una lista de dos elementos Address y City , donde puede ver listas y crear nuevas entidades.



Autorizaci贸n y Autenticaci贸n


Primero, cree una entidad de usuario.


 <?php // src/Entity/User.php namespace App\Entity; use Sonata\UserBundle\Entity\BaseUser as BaseUser; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="fos_user") */ class User extends BaseUser { /** * @ORM\Id * @ORM\Column(type="integer", options={"unsigned":true}) * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @return int */ public function getId() { return $this->id; } } 

Y al mismo tiempo crea la esencia del grupo de usuarios.


 <?php // src/Entity/Group.php namespace App\Entity; use Sonata\UserBundle\Entity\BaseGroup as BaseGroup; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="fos_group") */ class Group extends BaseGroup { /** * @ORM\Id * @ORM\Column(type="integer", options={"unsigned":true}) * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @return int */ public function getId() { return $this->id; } } 

Despu茅s configuramos Twig como un motor de plantillas.


 framework: ... templating: engines: ['twig'] 

Actualmente hay problemas con Symfony Flex y FOSUserBundle. Para m谩s detalles, vea los enlaces # 2562 , # 2708 y # 2801 .


Si bien estos problemas no se resuelven, debe realizar un par de manipulaciones adicionales antes de instalar 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 

Despu茅s de lo cual, puede instalar el paquete.


 $ composer require sonata-project/user-bundle 

Configuraci贸n de ACL


En Symfony 4, las ACL se movieron a un symfony/acl-bundle separado de symfony/acl-bundle . Por lo tanto, debe instalarse por separado.


 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 

Configurando Doctrina


 # config/packages/doctrine.yaml doctrine: orm: mappings: SonataUserBundle: ~ FOSUserBundle: ~ 

Configurar trabajo con correo


Dado que el trabajo con el correo no se considera en el marco de este art铆culo, indicaremos un c贸digo auxiliar en lugar de un servicio real.


 # config/packages/sonata_user.yaml sonata_user: mailer: fos_user.mailer.noop 

Integraci贸n de paquetes de usuarios en 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 

Ahora puede actualizar la ACL y la base de datos.


 $ bin/console acl:init 

 $ php bin/console doctrine:schema:update --force 

Crea un s煤per usuario. Especifique el nombre de demo y la contrase帽a de 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 

Para configurar correctamente nuestras clases de administrador, junto con la ACL, debe realizar cambios en la configuraci贸n.


 sonata_admin: ... security: handler: sonata.admin.security.handler.acl 

Despu茅s de ejecutar lo siguiente:


 $ 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"] 

Ahora, cuando intente ir a la direcci贸n http://127.0.0.1:8000/admin, se nos redirigir谩 a http://127.0.0.1:8000/admin/login .



Ingrese demo / demo y entre en la parte administrativa.



Resumen


Despu茅s de todas las manipulaciones, obtuvimos una parte administrativa funcional de Sonata Admin en Symfony 4 junto con autenticaci贸n y autorizaci贸n usando Sonata User + ACL.


Gracias a todos. Si tiene preguntas y comentarios, los escuchar茅 en los comentarios.

Source: https://habr.com/ru/post/460345/


All Articles