跳到内容

架构

编辑此页

SonataAdminBundle 的架构主要受到 Django Admin Project 的启发,Django Admin Project 确实是一个伟大的项目。更多信息可以在 Django Project Website 上找到。

如果你按照“创建 Admin”页面上的说明进行操作,那么现在应该已经有了一个 Admin 类和一个 Admin 服务。在本章中,我们将更深入地讨论它的工作原理。

Admin 类

Admin 类将特定模型映射到 SonataAdminBundle 提供的丰富的 CRUD 界面。换句话说,使用你的 Admin 类,你可以配置 SonataAdminBundle 在每个 CRUD 操作中为关联模型显示的内容。到目前为止,你已经在“创建 Admin”页面中看到了 3 个这些操作:列表、筛选和表单(用于创建/编辑)。但是,一个完全配置的 Admin 类可以定义更多操作

操作 描述
列表 列表中显示的字段
筛选 可用于筛选列表的字段
表单 用于创建/编辑实体的字段
显示 用于显示实体的字段
批量操作 可以对一组实体执行的操作(例如,批量删除)

Sonata\AdminBundle\Admin\AbstractAdmin 类用于通过扩展它来映射你的模型。但是,Sonata\AdminBundle\Admin\AdminInterface 的任何实现都可以用于定义 Admin 服务。对于每个 Admin 服务,以下必需的依赖项由 bundle 自动注入

描述
配置池 配置池,其中存储所有 Admin 类实例
模型管理器 处理与你的持久层相关的特定代码(例如 Doctrine ORM)
数据源 处理与 sonata exporter 相关的代码
表单构建器 使用 Symfony FormBuilder 为编辑/创建视图构建表单
显示构建器 构建显示字段
列表构建器 构建列表字段
数据网格构建器 构建筛选字段
请求 接收到的 http 请求
路由构建器 允许你为新操作添加路由,并删除默认操作的路由
路由生成器 生成不同的 URL
安全处理器 处理模型实例和操作的权限
验证器 处理模型验证
翻译器 生成翻译
标签翻译策略 生成标签时使用的策略
菜单工厂 根据当前操作生成侧边菜单

注意

这些依赖项中的每一个都用于一个特定的任务,上面已简要描述。如果你想了解更多关于它们如何使用,请查看相应的文档章节。在大多数情况下,你无需担心它们的底层实现。

所有这些依赖项都有默认值,你可以在声明你的任何 Admin 服务时覆盖这些默认值。这是通过调用匹配的 setter 来完成的

1
2
3
4
5
6
7
services:
    app.admin.post:
        class: App\Admin\PostAdmin
        calls:
            - [setLabelTranslatorStrategy, ['@sonata.admin.label.strategy.underscore']]
        tags:
            - { name: sonata.admin, model_class: App\Entity\Post, manager_type: orm, group: 'Content', label: 'Post' }

在这里,我们声明了与“创建 Admin”章节中相同的 Admin 服务,但使用了不同的标签翻译策略,替换了默认的策略。请注意,sonata.admin.label.strategy.underscoreSonataAdminBundle 提供的服务,但你可以使用你自己的服务。

CRUD控制器

CRUDController 包含可用于操作模型实例的操作,例如创建、列表、编辑或删除。它使用 Admin 类来确定其行为,例如在编辑表单中显示哪些字段,或如何构建列表视图。在 CRUDController 内部,你可以通过 $admin 变量访问 Admin 类实例。

注意

CRUD 是 “创建、读取、更新和删除” 的首字母缩写

CRUDController 与任何其他 Symfony 控制器没有什么不同,这意味着你可以使用所有常用的选项,例如从依赖注入容器 (DIC) 获取服务。

如果你决定扩展 CRUDController 以添加新操作或更改现有操作的行为,这将特别有用。你可以通过将控制器作为第 3 个参数传递来指定在声明 Admin 服务时要使用的控制器。例如,将控制器设置为 App\Controller\PostAdminController

1
2
3
4
5
6
7
services:
    app.admin.post:
        class: App\Admin\PostAdmin
        calls:
            - [setTranslationDomain, ['App']]
        tags:
            - { name: sonata.admin, model_class: App\Entity\Post, controller: App\Controller\PostAdminController, manager_type: orm, group: 'Content', label: 'Post' }

在扩展 CRUDController 时,请记住 Admin 类已经有一组自动注入的依赖项,这些依赖项在实现多种场景时非常有用。请参考现有的 CRUDController 操作示例,了解如何充分利用它们。

在你的重载 CRUDController 中,你也可以重载这些方法,以限制来自 SonataAdmin 的重复代码数量: preCreate: 从 createAction 调用 preEdit: 从 editAction 调用 preDelete: 从 deleteAction 调用 preShow: 从 showAction 调用 * preList: 从 listAction 调用

这些方法在检查访问权限并在从数据库检索对象后调用。如果需要在某些条件下将用户重定向到其他页面,可以使用它们。

字段定义

你的 Admin 类定义了你的模型的哪些字段将在你的 CRUDController 中定义的每个操作中可用。因此,对于每个操作,都会生成一个字段映射列表。这些列表是使用 FieldDescriptionCollection 类实现的,该类存储 FieldDescriptionInterface 的实例。以我们之前的 PostAdmin 类示例为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// src/Admin/PostAdmin.php

namespace App\Admin;

use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use App\Entity\User;

final class PostAdmin extends AbstractAdmin
{
    // Fields to be shown on create/edit forms
    protected function configureFormFields(FormMapper $form): void
    {
        $form
            ->add('title', TextType:class, [
                'label' => 'Post Title'
            ])
            ->add('author', EntityType::class, [
                'class' => User::class
            ])

            // "privateNotes" field will be rendered only if the authenticated
            // user is granted with the "ROLE_ADMIN_MODERATOR" role
            ->add('privateNotes', null, [], [
                'role' => 'ROLE_ADMIN_MODERATOR'
            ])

            // if no type is specified, SonataAdminBundle tries to guess it
            ->add('body')

            // conditionally add "status" field if the subject already exists
            // `ifFalse()` is also available to build this kind of condition
            ->ifTrue($this->hasSubject())
                ->add('status')
            ->ifEnd()

            // ...
        ;
    }

    // Fields to be shown on filter forms
    protected function configureDatagridFilters(DatagridMapper $datagrid): void
    {
        $datagrid
            ->add('title')
            ->add('author')
            ->add('privateNotes', null, [], [
                'role' => 'ROLE_ADMIN_MODERATOR'
            ])
        ;
    }

    // Fields to be shown on lists
    protected function configureListFields(ListMapper $list): void
    {
        $list
            ->addIdentifier('title')
            ->add('slug')
            ->add('author')
            ->add('privateNotes', null, [
                'role' => 'ROLE_ADMIN_MODERATOR'
            ])
        ;
    }

    // Fields to be shown on show action
    protected function configureShowFields(ShowMapper $show): void
    {
        $show
            ->add('id')
            ->add('title')
            ->add('slug')
            ->add('author')
            ->add('privateNotes', null, [
                'role' => 'ROLE_ADMIN_MODERATOR'
            ])
        ;
    }
}

在内部,提供的 Admin 类将使用这三个函数来创建三个 FieldDescriptionCollection 实例

  • $formFieldDescriptions,包含四个(以及有条件地五个)FieldDescriptionInterface 实例,分别用于标题、作者、正文和 privateNotes(以及状态,如果满足条件)
  • $filterFieldDescriptions,包含三个 FieldDescriptionInterface 实例,分别用于标题、作者和 privateNotes
  • $listFieldDescriptions,包含四个 FieldDescriptionInterface 实例,分别用于标题、slug、作者和 privateNotes
  • $showFieldDescriptions,包含五个 FieldDescriptionInterface 实例,分别用于 id、标题、slug、作者和 privateNotes

实际的 FieldDescription 实现由你在安装过程中选择的存储抽象 bundle 提供,基于 SonataAdminBundle 提供的 BaseFieldDescription 抽象类。

每个 FieldDescription 都包含关于字段映射的各种详细信息。其中一些与它们使用的操作无关,例如 nametype,而另一些仅在特定操作中使用。更多信息可以在 BaseFieldDescription 类文件中找到。

在大多数情况下,你实际上不需要自己处理 FieldDescription。但是,重要的是你要知道它的存在以及它的使用方式,因为它位于 SonataAdminBundle 的核心。

模板

与大多数操作一样,CRUDController 操作使用视图文件来呈现其输出。SonataAdminBundle 提供了即用型视图以及自定义它们的方法。

当前的实现使用 Twig 作为模板引擎。所有模板都位于 bundle 的 Resources/views 目录中。

有两个基本模板,其中一个最终用于每个操作

  • @SonataAdmin/standard_layout.html.twig
  • @SonataAdmin/ajax_layout.html.twig

顾名思义,一个用于标准调用,另一个用于 AJAX。

子文件夹包含用于 SonataAdminBundle 特定部分的 Twig 文件

区块
SonataBlockBundle 区块视图。默认情况下只有一个,它在仪表板上显示所有映射的类
按钮
按钮,例如你可以在多个 CRUD 操作中看到的“添加新的”或“删除
CRUD
每个 CRUD 操作的基本视图,以及每种字段类型的多个字段视图
表单
与表单渲染相关的视图
助手
一个视图,提供简短的对象描述,作为 SonataAdminBundle 提供的特定表单字段类型的一部分
分页器
与分页相关的视图文件

这些将在特定的“模板”部分中更详细地讨论,你还将在其中找到有关如何配置 SonataAdminBundle 以使用你的模板而不是默认模板的说明。

管理 Admin 服务

你的 Admin 服务定义在 Symfony 加载时解析,并由 Pool 类处理。此类作为 DIC 中的 sonata.admin.pool 服务提供,处理 Admin 类,按需延迟加载它们(以减少开销),并将它们中的每一个匹配到一个组。它还负责处理顶级模板文件、管理面板标题和徽标。

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本