Symfony 4/ Sonata: Tạo Giao Diện Lồng Nhau

Chúng ta sẽ xem cách xây dựng một giao diện quản trị bao gồm nhiều bảng có quan hệ Many2Many.

Hãy xem lại ví dụ của chúng ta về giao diện nhiều/nhiều có sẵn tại đây
Chúng ta có một bảng khu vực, bao gồm nhiều yếu tố từ bảng phòng ban. Trên những phòng ban này, chúng ta có các cơ quan.
Để hoàn thiện, và để ý nghĩa cho chuỗi dữ liệu này, chúng ta thêm một bảng zx_credential, đại diện cho nhân viên bán hàng.
Dưới đây là chuỗi dữ liệu của chúng ta: Nhân viên bán hàng->Khu vực->Phòng ban->Cơ quan.

data model workbench

Đối với dự án của chúng ta, chúng ta đã mô hình hóa toàn bộ cơ sở dữ liệu thông qua MysqWorkbench, và xuất schema sang MySql.

Tất cả những gì còn lại là xuất các thực thể (với getters và setters), và tạo CRUD Sonata

php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity
php bin/console make:entity --regenerate App
php bin/console make:sonata:admin App/Entity/ZxZone
php bin/console make:sonata:admin App/Entity/ZxCredential
php bin/console make:sonata:admin App/Entity/Agences
php bin/console make:sonata:admin App/Entity/Departement
php bin/console cache:clear

Vì hình thức, chúng ta đổi tên bảng "zx_credential" thành "Truy cập Thương mại".
Trong tệp service.yaml, chỉ cần sửa đổi đối số "Label".

    admin.zx_credential:
        class: App\Admin\ZxCredentialAdmin
        arguments: [~, App\Entity\ZxCredential, App\Controller\ZxCredentialAdminController]
        tags:
            - { name: sonata.admin, manager_type: orm, group: admin, label: "Accès commerciaux" }
        public: true
Sélection_131

Cho đến nay, không có gì bất thường. Nhưng điều chúng ta muốn là có một giao diện với toàn bộ chuỗi dữ liệu được liên kết với nhau, để khi chúng ta chỉnh sửa một nhân viên bán hàng, chúng ta có tùy chọn đi thẳng vào cấu hình của khu vực của họ, sau đó là phòng ban của họ, rồi đến cơ quan của họ.
Để làm điều này, chúng ta sẽ xác định các liên kết bảng với nhau thông qua một cuộc gọi đến phương thức "addChild" trong dịch vụ CRUD của chúng ta. Và chúng ta sẽ xác định các bảng con của mỗi bảng.
Để quá trình này hoạt động, chúng ta phải xác định dịch vụ con, cũng như trường cha mẹ được sử dụng cho liên kết.

Trong liên kết ZxCredential->ZxZone của chúng ta, chúng ta có trường sau trong thực thể con của chúng ta (ZxZone):

Sélection_133

Vì vậy, đây là cái được sử dụng cho liên kết, và mà chúng ta sẽ sử dụng trong cấu hình của chúng ta.

    admin.zx_credential:
        class: App\Admin\ZxCredentialAdmin
        arguments: [~, App\Entity\ZxCredential, App\Controller\ZxCredentialAdminController]
        calls:
            - [addChild, ["@admin.zx_zone", 'zxCredential']] 
        tags:
            - { name: sonata.admin, manager_type: orm, group: admin, label: "Accès commerciaux" }
        public: true

Cấu hình hoàn chỉnh trông như thế này:

   admin.departement:
        class: App\Admin\DepartementAdmin
        arguments: [~, App\Entity\Departement, ~]
        calls:
            - [addChild, ["@admin.agences","departement"]] 
        tags:
            - { name: sonata.admin, manager_type: orm, group: admin, label: Departement }
        public: true
        
    admin.zx_zone:
        class: App\Admin\ZxZoneAdmin
        arguments: [~, App\Entity\ZxZone, App\Controller\ZxZoneAdminController]
        calls:
            - [addChild, ["@admin.departement", "zxZone"]] 
        tags:
            - { name: sonata.admin, manager_type: orm, group: admin, label: Zones }
        public: true

    admin.zx_credential:
        class: App\Admin\ZxCredentialAdmin
        arguments: [~, App\Entity\ZxCredential, App\Controller\ZxCredentialAdminController]
        calls:
            - [addChild, ["@admin.zx_zone", 'zxCredential']] 
        tags:
            - { name: sonata.admin, manager_type: orm, group: admin, label: "Accès commerciaux" }
        public: true

    admin.agences:
        class: App\Admin\AgencesAdmin
        arguments: [~, App\Entity\Agences, ~]
        tags:
            - { name: sonata.admin, manager_type: orm, group: admin, label: Agences }
        public: true

Ở giai đoạn này, tất cả các bảng của chúng ta đều được liên kết, nhưng chúng ta sẽ cần phải cấu hình menu để điều hướng giữa chúng.
Để làm điều này, chúng ta sẽ thêm phương thức configureSideMenu trong admin bán hàng ZxCredentialAdmin của chúng ta.
Hãy cẩn thận, nó ở điểm nhập của giao diện mà bạn phải cấu hình menu. Vì vậy, toàn bộ chuỗi Nhân viên bán hàng->Khu vực->Phòng ban->Cơ quan sẽ được thực hiện trong Nhân viên bán hàng.

Bước đầu tiên, chúng ta thêm các uses trong tất cả giao diện admin của chúng ta, để việc đó được hoàn tất.

<?php

declare(strict_types=1);

namespace App\Admin;

use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

/*gestion de nos interfaces imbriquées*/
use Knp\Menu\ItemInterface as MenuItemInterface;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Route\RouteCollection;

Tiếp theo, chúng ta thêm liên kết đầu tiên của chúng ta đến quản lý khu vực, từ giao diện Zx_Credential.

   protected function configureSideMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null): void
    {
        if (!$childAdmin && !\in_array($action, ['edit'], true)) {
            return;
        }
         
        $admin = $this->isChild() ? $this->getParent() : $this;
        $id = $admin->getRequest()->get('id');
        $label=$this->hasSubject() && null !== $this->getSubject()->getLabel() ? $this->getSubject()->getLabel():null;
        

    
        $menu->addChild(
            'Configuration de l\'accès commercial : '.$label,
            $admin->generateMenuUrl('edit', ['id' => $id])
             
            );
    
        $child=$menu->addChild( 'Listes des zones',
            [
                'uri' => $admin->generateUrl('admin.zx_zone.list', ['id' => $id])
            ]);
        
        
        
    }
    

Cơ bản, điều bạn cần nhớ, và điều không rõ trong tài liệu, là tuyến đường để cấu hình. Chúng ta cần tên của tuyến đường, sau đó là id.
Đối với id, đơn giản, đối với một cấp độ đầu tiên, nó luôn là:

$id = $admin->getRequest()->get('id');

Và đối với tuyến đường, luôn là cùng một điều, đó là tên của dịch vụ theo sau là loại xem. Vì vậy ở đây admin.zx_zone.list
Điều này mang lại cho chúng ta:

$child=$menu->addChild( 'Listes des zones',
            [
                'uri' => $admin->generateUrl('admin.zx_zone.list', ['id' => $id])
            ]);
commercial_zone-1

Ở giai đoạn này, chúng ta có giao diện lồng nhau đầu tiên của mình. Đối với những cái tiếp theo, chúng ta sẽ lặp lại cấu hình.
Điều tiếp theo không được giải thích trong tài liệu vì nó là logic hiển nhiên. Nhưng bạn có thể tìm kiếm trong một thời gian dài nếu bạn không hiểu hoạt động của việc lồng các giao diện.
Điều quan trọng là phải hiểu rằng mọi thứ đều được thực hiện từ giao diện đầu tiên. Việc bao gồm các nút menu và xây dựng các tuyến đường.
Cái đầu tiên, sau đó là cái đầu tiên+cái thứ hai, sau đó là cái đầu tiên+cái thứ hai+cái thứ ba.

Giao diện luôn phải được xây dựng trong giao diện đầu tiên của chúng ta, cho mỗi bước. Đối với điều này, chúng ta cần phải lấy id ở mỗi giai đoạn, và xây dựng tuyến đường.
Và để lấy các khóa, mẹo là để kiểm tra các tuyến đường được tạo bởi symfony, qua lệnh debug:router

php bin/console debug:router
---------------------------------------------------------- ---------- -------- ------ ------------------------------------------------------------------------------------------------------------- 
  Name                                                       Method     Scheme   Host   Path                                                                                                         
 ---------------------------------------------------------- ---------- -------- ------ ------------------------------------------------------------------------------------------------------------- 
  _preview_error                                             ANY        ANY      ANY    /_error/{code}.{_format}                                                                                     
  _wdt                                                       ANY        ANY      ANY    /_wdt/{token}                                                                                                
  _profiler_home                                             ANY        ANY      ANY    /_profiler/                                                                                                  
  _profiler_search                                           ANY        ANY      ANY    /_profiler/search                                                                                            
  _profiler_search_bar                                       ANY        ANY      ANY    /_profiler/search_bar                                                                                        
  _profiler_phpinfo                                          ANY        ANY      ANY    /_profiler/phpinfo                                                                                           
  _profiler_search_results                                   ANY        ANY      ANY    /_profiler/{token}/search/results                                                                            
  _profiler_open_file                                        ANY        ANY      ANY    /_profiler/open                                                                                              
  _profiler                                                  ANY        ANY      ANY    /_profiler/{token}                                                                                           
  _profiler_router                                           ANY        ANY      ANY    /_profiler/{token}/router                                                                                    
  _profiler_exception                                        ANY        ANY      ANY    /_profiler/{token}/exception                                                                                 
  _profiler_exception_css                                    ANY        ANY      ANY    /_profiler/{token}/exception.css   
  admin_app_departement_list                                 ANY        ANY      ANY    /admin/app/departement/list                                                                                  
  admin_app_departement_create                               ANY        ANY      ANY    /admin/app/departement/create                                                                                
  admin_app_departement_batch                                ANY        ANY      ANY    /admin/app/departement/batch                                                                                 
  admin_app_departement_edit                                 ANY        ANY      ANY    /admin/app/departement/{id}/edit                                                                             
  admin_app_departement_delete                               ANY        ANY      ANY    /admin/app/departement/{id}/delete                                                                           
  admin_app_departement_show                                 ANY        ANY      ANY    /admin/app/departement/{id}/show                                                                             
  admin_app_departement_export                               ANY        ANY      ANY    /admin/app/departement/export                                                                                
  admin_app_departement_agences_list                         ANY        ANY      ANY    /admin/app/departement/{id}/agences/list                                                                     
  admin_app_departement_agences_create                       ANY        ANY      ANY    /admin/app/departement/{id}/agences/create                                                                   
  admin_app_departement_agences_batch                        ANY        ANY      ANY    /admin/app/departement/{id}/agences/batch                                                                    
  admin_app_departement_agences_edit                         ANY        ANY      ANY    /admin/app/departement/{id}/agences/{childId}/edit                                                           
  admin_app_departement_agences_delete                       ANY        ANY      ANY    /admin/app/departement/{id}/agences/{childId}/delete                                                         
  admin_app_departement_agences_show                         ANY        ANY      ANY    /admin/app/departement/{id}/agences/{childId}/show                                                           
  admin_app_departement_agences_export                       ANY        ANY      ANY    /admin/app/departement/{id}/agences/export                                                                   
  admin_app_zxcredential_list                                ANY        ANY      ANY    /admin/app/zxcredential/list                                                                                 
  admin_app_zxcredential_create                              ANY        ANY      ANY    /admin/app/zxcredential/create                                                                               
  admin_app_zxcredential_batch                               ANY        ANY      ANY    /admin/app/zxcredential/batch                                                                                
  admin_app_zxcredential_edit                                ANY        ANY      ANY    /admin/app/zxcredential/{id}/edit                                                                            
  admin_app_zxcredential_delete                              ANY        ANY      ANY    /admin/app/zxcredential/{id}/delete                                                                          
  admin_app_zxcredential_show                                ANY        ANY      ANY    /admin/app/zxcredential/{id}/show                                                                            
  admin_app_zxcredential_export                              ANY        ANY      ANY    /admin/app/zxcredential/export                                                                               
  admin_app_zxcredential_zxzone_list                         ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/list                                                                     
  admin_app_zxcredential_zxzone_create                       ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/create                                                                   
  admin_app_zxcredential_zxzone_batch                        ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/batch                                                                    
  admin_app_zxcredential_zxzone_edit                         ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/edit                                                           
  admin_app_zxcredential_zxzone_delete                       ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/delete                                                         
  admin_app_zxcredential_zxzone_show                         ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/show                                                           
  admin_app_zxcredential_zxzone_export                       ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/export                                                                   
  admin_app_zxcredential_zxzone_departement_list             ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/list                                               
  admin_app_zxcredential_zxzone_departement_create           ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/create                                             
  admin_app_zxcredential_zxzone_departement_batch            ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/batch                                              
  admin_app_zxcredential_zxzone_departement_edit             ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/edit                                
  admin_app_zxcredential_zxzone_departement_delete           ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/delete                              
  admin_app_zxcredential_zxzone_departement_show             ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/show                                
  admin_app_zxcredential_zxzone_departement_export           ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/export                                             
  admin_app_zxcredential_zxzone_departement_agences_list     ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/list                        
  admin_app_zxcredential_zxzone_departement_agences_create   ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/create                      
  admin_app_zxcredential_zxzone_departement_agences_batch    ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/batch                       
  admin_app_zxcredential_zxzone_departement_agences_edit     ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/{childChildChildId}/edit    
  admin_app_zxcredential_zxzone_departement_agences_delete   ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/{childChildChildId}/delete  
  admin_app_zxcredential_zxzone_departement_agences_show     ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/{childChildChildId}/show    
  admin_app_zxcredential_zxzone_departement_agences_export   ANY        ANY      ANY    /admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/export                      
  admin_app_agences_list                                     ANY        ANY      ANY    /admin/app/agences/list                                                                                      
  admin_app_agences_create                                   ANY        ANY      ANY    /admin/app/agences/create                                                                                    
  admin_app_agences_batch                                    ANY        ANY      ANY    /admin/app/agences/batch                                                                                     
  admin_app_agences_edit                                     ANY        ANY      ANY    /admin/app/agences/{id}/edit                                                                                 
  admin_app_agences_delete                                   ANY        ANY      ANY    /admin/app/agences/{id}/delete                                                                               
  admin_app_agences_show                                     ANY        ANY      ANY    /admin/app/agences/{id}/show    

Và sự chú ý đặc biệt của chúng tôi sẽ tập trung vào tuyến đường admin_app_zxcredential_zxzone_departement_agences_list của chúng tôi, nơi chứa toàn bộ chuỗi dữ liệu của chúng tôi.
Nó bao gồm các bảng của chúng tôi với tên của các id mà chúng tôi sẽ truy xuất để xây dựng các tuyến đường của các giao diện của chúng tôi.
/admin/app/zxcredential/{id}/zxzone/{childId}/departement/{childChildId}/agences/list
zxcredential: id
zxzone: childId
departement: childChildId

Vì vậy, bằng cách kiểm tra sự hiện diện của các biến này trong các URL đến của chúng tôi, chúng tôi sẽ có thể xác định độ sâu của giao diện của chúng tôi và xây dựng các menu tương ứng.

Đối với các tuyến đường, nó đơn giản, cho mỗi giai đoạn, chúng tôi thêm tuyến đường hiện tại được phân cách bởi một dấu ống |:
zxcredential: admin.zx_zone.list
zxzone: admin.zx_zone|admin.departement.list
departement: admin.zx_zone|admin.departement|admin.agences.list

Điều này cho chúng ta:

   protected function configureSideMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null): void
    {
        if (!$childAdmin && !\in_array($action, ['edit'], true)) {
            return;
        }
         
        $admin = $this->isChild() ? $this->getParent() : $this;
        $id = $admin->getRequest()->get('id');
        $label=$this->hasSubject() && null !== $this->getSubject()->getLabel() ? $this->getSubject()->getLabel():null;
        

    
        $menu->addChild(
            'Configuration de l\'accès commercial : '.$label,
            $admin->generateMenuUrl('edit', ['id' => $id])
             
            );
    
        $child=$menu->addChild( 'Listes des zones',
            [
                'uri' => $admin->generateUrl('admin.zx_zone.list', [
                    'id' => $id
                    
                ])
            ]);
        
        if(!empty($admin->getRequest()->get('childId'))){
            $child=$menu->addChild( 'Listes des departements',
                [
                    'uri' => $admin->generateUrl('admin.zx_zone|admin.departement.list', [
                        'id' => $id, 
                        'childId' => $admin->getRequest()->get('childId')
                        
                    ])
                ]);
        }
        if(!empty($admin->getRequest()->get('childChildId'))){
            $child=$menu->addChild( 'Listes des agences',
                [
                    'uri' => $admin->generateUrl('admin.zx_zone|admin.departement|admin.agences.list', [
                        'id' => $id, 
                        'childId' => $admin->getRequest()->get('childId'),
                        'childChildId' => $admin->getRequest()->get('childChildId')
                    ])
                ]);
        }

    }

Giao diện của chúng tôi giờ đã hoàn chỉnh:

commercial_to_agence