高级配置
服务配置
当您创建一个新的 Admin 服务时,您可以配置它的依赖项,默认情况下注入的服务有
依赖项 | 服务 ID |
---|---|
model_manager | sonata.admin.manager.%manager-type% |
data_source | sonata.admin.data_source.%manager-type% |
form_contractor | sonata.admin.builder.%manager-type%_form |
show_builder | sonata.admin.builder.%manager-type%_show |
list_builder | sonata.admin.builder.%manager-type%_list |
datagrid_builder | sonata.admin.builder.%manager-type%_datagrid |
translator | translator |
configuration_pool | sonata.admin.pool |
router | router |
validator | validator |
security_handler | sonata.admin.security.handler |
menu_factory | knp_menu.factory |
route_builder | sonata.admin.route.path_info | sonata.admin.route.path_info_slashes |
label_translator_strategy | sonata.admin.label.strategy.form_component |
注意
%manager-type%
需要替换为管理器类型(orm, doctrine_mongodb...),默认的 route_builder 取决于它。
您可以通过 2 种方式在您的服务配置文件(services.xml
或 services.yaml
)中定义依赖项
使用标签属性(不太详细)
1 2 3 4 5 6 7 8 9 10 11 12 13
# config/services.yaml
app.admin.project:
class: App\Admin\ProjectAdmin
tags:
-
name: sonata.admin
model_class: App\Entity\Project
manager_type: orm
group: 'Project'
label: 'Project'
label_translator_strategy: 'sonata.admin.label.strategy.native'
route_builder: 'sonata.admin.route.path_info'
使用方法调用(更详细)
1 2 3 4 5 6 7 8 9
# config/services.yaml
app.admin.project:
class: App\Admin\ProjectAdmin
calls:
- [setLabelTranslatorStrategy, ['@sonata.admin.label.strategy.native']]
- [setRouteBuilder, ['@sonata.admin.route.path_info']]
tags:
- { name: sonata.admin, model_class: App\Entity\Project, manager_type: orm, group: 'Project', label: 'Project' }
如果您想修改将要注入的服务,请将以下代码添加到您的应用程序配置文件中
1 2 3 4 5 6 7
# config/packages/sonata_admin.yaml
admins:
sonata_admin:
sonata.order.admin.order: # id of the admin service this setting is for
model_manager: # dependency name, from the table above
sonata.order.admin.order.manager # customised service id
创建自定义 RouteBuilder
要创建您自己的 RouteBuilder,请创建 PHP 类并将其注册为服务
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
namespace App\Route;
use Sonata\AdminBundle\Builder\RouteBuilderInterface;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Route\PathInfoBuilder;
use Sonata\AdminBundle\Route\RouteCollectionInterface;
final class EntityRouterBuilder implements RouteBuilderInterface
{
private PathInfoBuilder $pathInfoBuilder;
public function __construct(PathInfoBuilder $pathInfoBuilder)
{
$this->pathInfoBuilder = $pathInfoBuilder;
}
public function build(AdminInterface $admin, RouteCollectionInterface $collection)
{
$this->pathInfoBuilder->build($admin, $collection);
$collection->add('yourSubAction');
// The create button will disappear, delete functionality will be disabled as well
// No more changes needed!
$collection->remove('create');
$collection->remove('delete');
}
}
1 2 3 4 5 6 7
# config/services.yaml
services:
app.admin.entity_route_builder:
class: App\Route\EntityRouterBuilder
arguments:
- '@sonata.admin.audit.manager'
继承的类
您可以使用服务配置注入子类来管理继承的类。
让我们考虑一个名为 Person
的基类及其子类 Student
和 Teacher
1 2 3 4 5 6 7 8 9 10 11 12
# config/services.yaml
app.admin.person:
class: App\Admin\PersonAdmin
calls:
-
- setSubClasses
-
student: App\Entity\Student
teacher: App\Entity\Teacher
tags:
- { name: sonata.admin, model_class: App\Entity\Person, manager_type: orm, group: "admin", label: "Person" }
您需要更改表单的配置方式,以便将这些新的子类考虑在内
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// src/Admin/PersonAdmin.php
protected function configureFormFields(FormMapper $form): void
{
$subject = $this->getSubject();
$form
->add('name')
;
if ($subject instanceof Teacher) {
$form->add('course', 'text');
}
elseif ($subject instanceof Student) {
$form->add('year', 'integer');
}
}
标签菜单
ACL
虽然菜单链接的路由可能受到保护,但标签菜单不会自动为您检查 ACL。链接仍将显示,除非您使用 hasAccess()
方法手动检查它
1 2 3 4 5 6 7 8 9 10 11 12 13 14
protected function configureTabMenu(MenuItemInterface $menu, string $action, ?AdminInterface $childAdmin = null): void
{
// Link will always appear even if it is protected by ACL
$menu->addChild($this->trans('Show'), [
'uri' => $admin->generateUrl('show', [$admin->getIdParameter() => $id])
]);
// Link will only appear if access to ACL protected URL is granted
if ($this->hasAccess('edit')) {
$menu->addChild($this->trans('Edit'), [
'uri' => $admin->generateUrl('edit', [$admin->getIdParameter() => $id])
]);
}
}
下拉菜单
默认情况下,您可以在标签菜单中使用下拉菜单。这可以通过使用 `'dropdown' => true` 属性来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// src/Admin/PersonAdmin.php
protected function configureTabMenu(MenuItemInterface $menu, string $action, ?AdminInterface $childAdmin = null): void
{
// other tab menu stuff ...
$menu->addChild('comments', ['attributes' => ['dropdown' => true]]);
$menu['comments']->addChild('list', [
'uri' => $admin->generateUrl('listComment', [$admin->getIdParameter() => $id])
]);
$menu['comments']->addChild('create', [
'uri' => $admin->generateUrl('addComment', [$admin->getIdParameter() => $id])
]);
}
如果您想以不同的方式使用标签菜单,您可以替换菜单模板
1 2 3 4 5
# config/packages/sonata_admin.yaml
sonata_admin:
templates:
tab_menu_template: "@App/Admin/own_tab_menu_template.html.twig"
翻译
标签翻译参数和域可以通过分别使用与项目关联的额外数据数组的 label_translation_parameters
和 translation_domain
键进行自定义
1 2 3 4
$menuItem->setExtras([
'label_translation_parameters' => ['myparam' => 'myvalue'],
'translation_domain' => 'My domain',
]);
您还可以在菜单根目录上设置翻译域,子项将继承它
1
$menu->setExtra('translation_domain', 'My domain');
过滤器参数
您可以添加或覆盖标签菜单的过滤器参数
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
use Knp\Menu\ItemInterface as MenuItemInterface;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\Form\Type\EqualType;
final class DeliveryAdmin extends AbstractAdmin
{
protected function configureTabMenu(MenuItemInterface $menu, string $action, ?AdminInterface $childAdmin = null): void
{
if (!$childAdmin && !in_array($action, ['edit', 'show', 'list'])) {
return;
}
if ($action == 'list') {
// Get current filter parameters
$filterParameters = $this->getFilterParameters();
// Add or override filter parameters
$filterParameters['status'] = [
'type' => EqualType::TYPE_IS_EQUAL, // => 1
'value' => Delivery::STATUS_OPEN,
];
// Add filters to uri of tab
$menu->addChild('List open deliveries', [
'uri' => $this->generateUrl('list', ['filter' => $filterParameters])
]);
return;
}
}
}
操作菜单
您可以通过覆盖以下方法为特定操作的操作菜单添加自定义项
1 2 3 4 5 6 7 8 9 10 11 12 13
public function configureActionButtons(AdminInterface $admin, array $list, string $action, ?object $object = null): array
{
if (in_array($action, ['show', 'edit', 'acl']) && $object) {
$buttonList['custom'] = [
'template' => '@App/Button/custom_button.html.twig',
];
}
// Remove history action
unset($buttonList['history']);
return $buttonList;
}
您的自定义 twig 文件
1 2 3 4 5 6 7 8
{# @App/Button/custom_button.html.twig #}
<li>
<a href="{{ admin.generateObjectUrl('custom', object) }}">
<i class="fa fa-cogs" aria-hidden="true"></i>
Custom
</a>
</li>

禁用内容拉伸
您可以禁用 html
、body
和 sidebar
元素拉伸。默认情况下,这些容器被强制为全高。如果您使用自定义布局或不需要这种行为,请将 no-stretch
类添加到 <html>
标签。
1 2 3
{# templates/standard_layout.html.twig #}
{% block html_attributes %}class="no-js no-stretch"{% endblock %}
自定义操作访问管理
您可以通过在您的 Admin 类中覆盖 `getAccessMapping` 方法并返回带有附加条目的数组来自定义 CRUDController 中的访问系统
1 2 3 4 5 6 7 8 9 10 11 12
// src/Admin/CustomAdmin.php
final class CustomAdmin extends AbstractAdmin
{
protected function getAccessMapping(): array
{
return [
'myCustomFoo' => 'EDIT',
'myCustomBar' => ['EDIT', 'LIST'],
];
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// src/Controller/CustomCRUDController.php
final class CustomCRUDController extends CRUDController
{
public function myCustomFooAction(): Response
{
$this->admin->checkAccess('myCustomFoo');
// If you can't access to EDIT role for the linked admin, an AccessDeniedException will be thrown
// ...
}
public function myCustomBarAction($object): Response
{
$this->admin->checkAccess('myCustomBar', $object);
// If you can't access to EDIT AND LIST roles for the linked admin, an AccessDeniedException will be thrown
// ...
}
}
您还可以完全自定义您想要如何处理您的访问管理,方法是为特定的 Admin 类创建自定义 SecurityHandler 服务
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
// src/Security/Handler/CustomSecurityHandler.php
use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface;
final class CustomSecurityHandler implements SecurityHandlerInterface
{
public function isGranted(AdminInterface $admin, $attributes, ?object $object = null): bool
{
return $this->customAccessLogic();
}
public function getBaseRole(AdminInterface $admin): string
{
return '';
}
public function buildSecurityInformation(AdminInterface $admin): array
{
return [];
}
public function createObjectSecurity(AdminInterface $admin, object $object): void
{
}
public function deleteObjectSecurity(AdminInterface $admin, object $object): void
{
}
}
使用 `security_handler` 标签指向您的特定 Admin 类的自定义 SecurityHandler 服务
1 2 3 4 5 6 7 8
# config/services.yaml
services:
# ...
admin.custom:
class: App\Admin\CustomAdmin
tags:
- { name: sonata.admin, model_class: App\Entity\Custom, manager_type: orm, label: Category, security_handler: App\Security\Handler\CustomSecurityHandler }
您还可以在您的自定义 SecurityHandler 中使用默认的 SecurityHandler(在全局配置中定义)
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
// src/Security/Handler/CustomSecurityHandler.php
use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface;
final class CustomSecurityHandler implements SecurityHandlerInterface
{
private SecurityHandlerInterface $defaultSecurityHandler;
public function __construct(SecurityHandlerInterface $defaultSecurityHandler)
{
$this->defaultSecurityHandler = $defaultSecurityHandler;
}
public function isGranted(AdminInterface $admin, $attributes, ?object $object = null): bool
{
// Custom access logic
if (...) {
return false;
}
// Default access logic
return $this->defaultSecurityHandler->isGranted($admin, $attributes, $object);
}
// ...
}
1 2 3 4 5 6 7
# config/services.yaml
services:
# ...
App\Security\Handler\CustomSecurityHandler:
arguments:
- '@sonata.admin.security.handler'
如果您有很多使用默认 SecurityHandler 服务的 SecurityHandler 服务,您可以定义服务别名
1 2 3 4 5
# config/services.yaml
services:
# ...
Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface: '@sonata.admin.security.handler'
这样,您无需定义每个自定义 SecurityHandler 服务来指定默认的 SecurityHandler 服务作为参数。
使用您自己的自定义控制器作为默认控制器
默认情况下,当未指定控制器时,CRUDController
是使用的控制器。您可以通过在配置中添加以下内容来修改此设置
1 2 3 4
# config/packages/sonata_admin.yaml
sonata_admin:
default_controller: App\Controller\DefaultCRUDController