跳到内容

保存钩子

编辑此页

当 SonataAdmin 被提交处理时,会调用一些事件。一个是在任何持久层交互之前,另一个是在之后。此外,在提交和验证编辑和创建操作之间,会调用 preValidate 事件。事件命名如下

  • 新对象:preValidate($object) / prePersist($object) / postPersist($object)
  • 编辑的对象:preValidate($object) / preUpdate($object) / postUpdate($object)
  • 删除的对象:preRemove($object) / postRemove($object)

值得注意的是,无论是否存在任何实际的持久层事件,只要 Admin 成功提交,就会调用更新事件。这与 DoctrineORM 中的 preUpdatepostUpdate 事件以及可能其他一些持久层的使用不同。

例如:如果你提交一个编辑表单,而没有更改表单上的任何值,那么数据库中没有任何内容需要更改,并且 DoctrineORM 不会触发 Entity 类自身的 preUpdatepostUpdate 事件。但是,你的 Admin 类的 preUpdatepostUpdate 方法被调用,这可以被用来发挥你的优势。

注意

当在一个 Admin 中嵌入另一个 Admin 时,例如使用 sonata_type_admin 字段类型,子 Admin 的钩子不会被触发。

与 SonataUserBundle 一起使用的示例

SonataUserBundle 为你的 Symfony 项目提供身份验证功能,并与 Doctrine ORM、Doctrine ODM 兼容。

用户管理系统需要在更新用户密码或用户名时执行特定的调用。这就是如何使用 Admin 捆绑包通过使用 preUpdate 保存钩子来解决问题的方法

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
namespace Sonata\UserBundle\Admin\Entity;

use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Form\Type\ModelType;
use Sonata\UserBundle\Form\Type\SecurityRolesType;
use Sonata\UserBundle\Model\UserManagerInterface;

final class UserAdmin extends AbstractAdmin
{
    private UserManagerInterface $userManager;

    public function __construct(UserManagerInterface $userManager)
    {
        $this->userManager = $userManager;
    }

    protected function configureFormFields(FormMapper $form): void
    {
        $form
            ->with('General')
                ->add('username')
                ->add('email')
                ->add('plainPassword', 'text')
            ->end()
            ->with('Groups')
                ->add('groups', ModelType::class, ['required' => false])
            ->end()
            ->with('Management')
                ->add('roles', SecurityRolesType::class, ['multiple' => true])
                ->add('locked', null, ['required' => false])
                ->add('expired', null, ['required' => false])
                ->add('enabled', null, ['required' => false])
                ->add('credentialsExpired', null, ['required' => false])
            ->end()
        ;
    }

    public function preUpdate(object $user): void
    {
        $this->userManager->updateCanonicalFields($user);
        $this->userManager->updatePassword($user);
    }
}

在控制器中挂钩

你可能已经注意到,Admin 中存在的钩子不允许你与删除过程进行交互:你无法取消它。为了实现这一点,你应该知道还有一种方法可以在控制器中挂钩操作。

如果你定义一个继承自 CRUDController 的自定义控制器,你可以重新定义以下方法

  • 新对象:preCreate($object)
  • 编辑的对象:preEdit($object)
  • 删除的对象:preDelete($object)
  • 显示对象:preShow($object)
  • 列表对象:preList($object)

如果这些方法返回 Response,则该过程将被中断,并且响应将由控制器按原样返回(如果它返回 null,则该过程继续)。你可以使用 redirectTo($object) 方法生成重定向到对象显示页面的重定向。

注意

如果你需要禁止删除特定项目,你可以在 preDelete($object) 方法中进行检查。

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