架构
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.underscore
是 SonataAdminBundle
提供的服务,但你可以使用你自己的服务。
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
都包含关于字段映射的各种详细信息。其中一些与它们使用的操作无关,例如 name
或 type
,而另一些仅在特定操作中使用。更多信息可以在 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
类,按需延迟加载它们(以减少开销),并将它们中的每一个匹配到一个组。它还负责处理顶级模板文件、管理面板标题和徽标。