تثبيت وتكوين Sonata Admin على Symfony 4


تحية للجميع. سيتحدث هذا المقال عن Symfony 4 و Sonata Admin.


أثناء عملية التثبيت ، واجهت الكثير من الأخطاء في الوثائق وكانت الوثائق نفسها منتشرة في عدة أماكن. سأدرس هنا العملية برمتها ، من إنشاء المشروع إلى الترخيص إلى جانب المصادقة.


بعض أجزاء الإعدادات مأخوذة من الوثائق الرسمية ، وبعضها مأخوذ من التعليقات على جيثب ، حيث نوقشت مشاكل التثبيت. ورسمت أيضا المزالق المحتملة والطرق من حولهم.


إنشاء مشروع symfony


$ composer create-project symfony/skeleton sonatademo 

 $ cd sonatademo 

لاستخدام Symfony Embedded Web Server ، يجب عليك تثبيت Symfony Client .


نبدأ.


 $ symfony serve 

نتبع الرابط http://127.0.0.1:8000/ وسنتلقى تحية Symfony القياسية. لذلك كل شيء يعمل بشكل صحيح.



تثبيت سوناتا الادارية


 $ composer require sonata-project/admin-bundle 

سوناتا الادارية و DB


للتفاعل مع قاعدة البيانات ، تحتاج إلى تثبيت إحدى المكتبات الثلاث:



في هذه المقالة ، SonataDoctrineORMAdminBundle ، وهو أكثر من كاف للعمل مع MySQL أو Sqlite .


تثبيت SonataDoctrineORMAdminBundle .


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

الآن دعونا تكوين العمل مع Sqlite .


افتح ملف .env وفي القسم ###> doctrine/doctrine-bundle ### تغيير DATABASE_URL .


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

نظرًا لأن Symfony Flex تقوم بجميع الأعمال التي نقوم بها تقريبًا أثناء عملية التثبيت ، فلا يزال يتعين علينا القيام ببعض التلاعب للحصول على النتيجة النهائية.


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

نقوم بها


 $ composer dump-env dev 

الآن نتبع الرابط http://127.0.0.1:8000/admin ونرى واجهة إدارية قياسية فارغة.



خلق الكيان


لنقم بإنشاء كيانين ، على سبيل المثال ، مرتبطان بعلاقة رأس بأطراف.


 <?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; } } 

نحن نتزامن مع قاعدة البيانات.


 bin/console doctrine:schema:create 

تكوين الكيان لبرنامج Sonata Admin


من الضروري لكل كيان إنشاء ملف منفصل مع وصف لكيفية عمل 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'); } } 

هذه الفئات تحتاج إلى وصف في 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 } 

في حالة حدوث أخطاء عند إدخال الجزء الإداري ، على سبيل المثال Unable to generate a URL for the named route ، فأنت بحاجة إلى مسح ذاكرة التخزين المؤقت للتطبيق والمحاولة مرة أخرى.


 bin/console cache:clear 

الآن ، إذا قمت بالنقر فوق الارتباط http://127.0.0.1:8000/admin ، فسوف نرى قائمة من عنصرين Address City ، حيث يمكنك عرض القوائم وإنشاء كيانات جديدة.



الترخيص والمصادقة


أولاً ، قم بإنشاء كيان مستخدم.


 <?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; } } 

وفي الوقت نفسه إنشاء جوهر مجموعة المستخدم.


 <?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; } } 

بعد أن نقوم بتكوين 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 

تكوين العقيدة


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

إعداد العمل مع البريد


نظرًا لأن العمل مع البريد لا يعتبر ضمن إطار هذه المقالة ، فسوف نشير إلى كعب روتين بدلاً من خدمة حقيقية.


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

تكامل حزمة المستخدم في 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 لاسم وكلمة المرور.


 $ 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 

لتكوين فئات المسؤول بشكل صحيح ، بالإضافة إلى قائمة التحكم في الوصول ، تحتاج إلى إجراء تغييرات على الإعدادات.


 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 .



أدخل التجريبي / التجريبي والدخول في الجزء الإداري.



النتائج


بعد كل عمليات التلاعب ، حصلنا على جزء إداري فعال من Sonata Admin في Symfony 4 جنبًا إلى جنب مع المصادقة والترخيص باستخدام Sonata User + ACL.


شكرا لكم جميعا إذا كان لديك أسئلة وتعليقات ، سوف أستمع إليهم في التعليقات.

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


All Articles