创建自定义管理操作
这是一个为 SonataAdmin 创建自定义列表操作的完整工作示例。该示例基于 App
命名空间中现有的 CarAdmin
类。假设您已经有一个正在运行的管理服务。
方法
SonataAdmin 提供了一种非常直接的方式来添加您自己的自定义操作。
为此,我们需要
- 扩展
SonataAdmin:CRUD
控制器,并告知我们的管理类使用它 - 在我们的控制器中创建自定义操作
- 创建一个模板以在列表视图中显示该操作
- 在管理类中添加路由和新操作
扩展管理控制器
首先,您需要创建自己的控制器,扩展 SonataAdmin 的控制器
1 2 3 4 5 6 7 8 9 10
// src/Controller/CarAdminController.php
namespace App\Controller;
use Sonata\AdminBundle\Controller\CRUDController;
class CarAdminController extends CRUDController
{
// ...
}
默认情况下,管理类使用 SonataAdmin:CRUD
控制器,这是管理服务定义的第三个参数,您需要将其更改为您自己的控制器。
将管理类注册为服务
可以使用 XML
1 2 3 4 5
<!-- config/services.xml -->
<service id="app.admin.car" class="App\Admin\CarAdmin">
<tag name="sonata.admin" model_class="App\Entity\Car" controller="App\Controller\CarAdminController" manager_type="orm" group="Demo" label="Car"/>
</service>
或将其添加到您的 services.yaml
中
1 2 3 4 5 6 7
# config/services.yaml
services:
app.admin.car:
class: App\Admin\CarAdmin
tags:
- { name: sonata.admin, model_class: App\Entity\Car, controller: App\Controller\CarAdminController, manager_type: orm, group: Demo, label: Car }
有关服务配置的更多信息,请参阅 创建管理类 的步骤 3
在您的控制器中创建自定义操作
现在是时候在这里实际创建您的自定义操作了,对于此示例,我选择实现一个 clone
操作
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
// src/Controller/CarAdminController.php
namespace App\Controller;
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class CarAdminController extends CRUDController
{
/**
* @param $id
*/
public function cloneAction($id): Response
{
$object = $this->admin->getSubject();
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id: %s', $id));
}
// Be careful, you may need to overload the __clone method of your object
// to set its id to null !
$clonedObject = clone $object;
$clonedObject->setName($object->getName().' (Clone)');
$this->admin->create($clonedObject);
$this->addFlash('sonata_flash_success', 'Cloned successfully');
return new RedirectResponse($this->admin->generateUrl('list'));
}
}
如果您想将当前过滤器参数添加到重定向 URL,您可以将它们添加到 generateUrl()
方法中
1 2 3
return new RedirectResponse(
$this->admin->generateUrl('list', ['filter' => $this->admin->getFilterParameters()])
);
在这里,我们首先获取对象,查看它是否存在,然后克隆它并将克隆作为新对象插入。最后,我们设置一个闪存消息指示成功,并重定向到列表视图。
提示
如果您想在此处渲染某些内容,您可以创建任何新模板,扩展 sonata 布局并使用 sonata_admin_content
代码块。
1 2 3 4 5
{% extends '@SonataAdmin/standard_layout.html.twig' %}
{% block sonata_admin_content %}
Your content here
{% endblock %}
为新操作创建模板
您需要告诉 SonataAdmin 如何渲染您的新操作。您可以通过在您的自定义管理控制器的命名空间中创建一个 list__action_clone.html.twig
来做到这一点。
1 2 3
{# templates/CRUD/list__action_clone.html.twig #}
<a class="btn btn-sm" href="{{ admin.generateObjectUrl('clone', object) }}">clone</a>
现在 clone
不是已知的路由,我们在下一步中定义它。
整合在一起
现在剩下的是将您的自定义操作添加到管理类中。
您必须在 configureRoutes
中添加新路由
1 2 3 4 5 6 7
use Sonata\AdminBundle\Route\RouteCollectionInterface;
protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection
->add('clone', $this->getRouterIdParameter().'/clone');
}
这为我们提供了一个类似 ../admin/app/car/1/clone
的路由。您也可以编写 $collection->add('clone');
以获得类似 ../admin/app/car/clone?id=1
的路由
接下来,我们必须在 configureListFields
中添加操作,指定我们创建的模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14
protected function configureListFields(ListMapper $list): void
{
$list
->add(ListMapper::NAME_ACTIONS, null, [
'actions' => [
// ...
'clone' => [
'template' => '@App/CRUD/list__action_clone.html.twig',
],
],
]);
}
完整的 CarAdmin.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 29 30 31 32 33 34 35
// src/Admin/CarAdmin.php
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Route\RouteCollection;
final class CarAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection
->add('clone', $this->getRouterIdParameter().'/clone');
}
protected function configureListFields(ListMapper $list): void
{
$list
->addIdentifier('name')
->add('engine')
->add('rescueEngine')
->add('createdAt')
->add(ListMapper::NAME_ACTIONS, null, [
'actions' => [
'show' => [],
'edit' => [],
'delete' => [],
'clone' => [
'template' => '@App/CRUD/list__action_clone.html.twig',
]
]
]);
}
}
注意
如果您想通过在 twig 中使用 render 函数在模板中渲染自定义控制器操作,则需要添加 _sonata_admin
作为属性。例如; {{ render(controller('App
。这样做是因为在应该发生渲染的那一刻,通常设置此参数值的路由根本没有参与,然后您将收到错误“控制器 AppControllerXxxxCRUDController 和当前路由 '' 没有定义 _sonata_admin。”
没有实体的自定义操作
创建未连接到实体的操作也是可能的。让我们想象我们有一个导入操作。我们注册我们的路由
1 2 3 4 5 6
use Sonata\AdminBundle\Route\RouteCollectionInterface;
protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection->add('import');
}
和控制器操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// src/Controller/CarAdminController.php
namespace App\Controller;
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
final class CarAdminController extends CRUDController
{
public function importAction(Request $request): Response
{
// do your import logic
}
现在,我们可以将操作添加到添加按钮旁边,而不是将其添加到表单映射器。在您的管理类中,覆盖 configureActionButtons
方法
1 2 3 4 5 6
protected function configureActionButtons(array $buttonList, string $action, ?object $object = null): array
{
$buttonList['import'] = ['template' => 'import_button.html.twig'];
return $buttonList;
}
为该按钮创建一个模板
1 2 3 4 5
<li>
<a class="sonata-action-element" href="{{ admin.generateUrl('import') }}">
<i class="fas fa-level-up-alt"></i> {{ 'import_action'|trans({}, 'SonataAdminBundle') }}
</a>
</li>
您也可以将此操作添加到您的仪表板操作中,您必须覆盖管理类中的 getDashboardActions
方法,并且有两种方法可以添加操作
1 2 3 4 5 6
protected function configureDashboardActions(array $actions): array
{
$actions['import'] = ['template' => 'import_dashboard_button.html.twig'];
return $actions;
}
为该按钮创建一个模板
1 2 3
<a class="btn btn-link btn-flat" href="{{ admin.generateUrl('import') }}">
<i class="fas fa-level-up-alt"></i> {{ 'import_action'|trans({}, 'SonataAdminBundle') }}
</a>
或者您可以将值作为数组传递
1 2 3 4 5 6 7 8 9 10 11
protected function configureDashboardActions(array $actions): array
{
$actions['import'] = [
'label' => 'import_action',
'translation_domain' => 'SonataAdminBundle',
'url' => $this->generateUrl('import'),
'icon' => 'level-up-alt',
];
return $actions;
}