跳到内容

高级配置

编辑此页

服务配置

当您创建一个新的 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.xmlservices.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 的基类及其子类 StudentTeacher

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_parameterstranslation_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>
Custom action buttons

禁用内容拉伸

您可以禁用 htmlbodysidebar 元素拉伸。默认情况下,这些容器被强制为全高。如果您使用自定义布局或不需要这种行为,请将 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
本作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可协议获得许可。
目录
    版本