覆盖方法或 EventListener:在 EasyAdmin 中第一次停止创建过程并显示警告?

Override Method or EventListener: stop creation process and show warning just the first time in EasyAdmin?

我在我的 SF 3.3 项目中使用 EasyAdmin,但我需要实现一些与 EasyAdmin 的构建方式不同的东西。看看下面的图片:

您可能会注意到,一个用户可以在多个 GroupingRole 中。获得这些信息的挑战是:

我想用这种方法实现的是提醒管理员该用户已经加入任何其他组,但不会阻止他创建记录。

我已经通过重写该实体的 prePersist 方法实现了其中的一部分(见下文):

class AdminController extends BaseAdminController
{
    /**
     * Check if the users has been assigned to any group
     */
    protected function prePersistGroupingRoleEntity($entity)
    {
        $usersToGroupRoleEntities = $this->em->getRepository('CommonBundle:UsersToGroupRole')->findAll();
        $usersToGroupRole         = [];

        /** @var UsersToGroupRole $groupRole */
        foreach ($usersToGroupRoleEntities as $groupRole) {
            $usersToGroupRole[$groupRole->getGroupingRoleId()][] = $groupRole->getUsersId();
        }

        $usersInGroup = [];

        /** @var Users $userEntity */
        foreach ($entity->getUsersInGroup() as $userEntity) {
            foreach ($usersToGroupRole as $group => $users) {
                if (\in_array($userEntity->getId(), $users, true)) {
                    $usersInGroup[$group][] = $userEntity->getId();
                }
            }
        }

        $groupingRoleEnt = $this->em->getRepository('CommonBundle:GroupingRole');
        $usersEnt        = $this->em->getRepository('CommonBundle:Users');

        $message = [];
        foreach ($usersInGroup as $group => $user) {
            foreach($user as $usr) {
                $message[] = sprintf(
                    'The user %s already exists in %s group!',
                    $usersEnt->find($usr)->getEmail(),
                    $groupingRoleEnt->find($group)->getName()
                );
            }
        }
    }
}

我不知道如何停止创建记录,而是仅在第一次单击按钮时显示警告,因为第二次并发出警告我应该允许创建记录.

任何人都可以给我一些想法and/or建议吗?

更新:添加实体信息

除了上面显示的代码之外,还有参与此过程的实体:

/**
 * @ORM\Entity
 * @ORM\Table(name="grouping_role")
 */
class GroupingRole
{
    /**
     * @ORM\Id
     * @ORM\Column(name="id", type="integer",unique=true,nullable=false)
     * @ORM\GeneratedValue
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="role_name", type="string", nullable=false)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="role_description", type="string", nullable=false)
     */
    private $description;

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Schneider\QuoteBundle\Entity\Distributor", inversedBy="groupingRole")
     * @ORM\JoinTable(name="grouping_to_role",
     *   joinColumns={
     *     @ORM\JoinColumn(name="grouping_role_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="DistributorID", referencedColumnName="DistributorID", nullable=false)
     *   }
     * )
     *
     * @Assert\Count(
     *      min = 1,
     *      minMessage = "You must select at least one Distributor"
     * )
     */
    private $distributorGroup;

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="CommonBundle\Entity\Users", inversedBy="usersGroup")
     * @ORM\JoinTable(name="users_to_group_role",
     *   joinColumns={
     *     @ORM\JoinColumn(name="grouping_role_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="users_id", referencedColumnName="users_id", nullable=false)
     *   }
     * )
     *
     * @Assert\Count(
     *      min = 1,
     *      minMessage = "You must select at least one user"
     * )
     */
    private $usersInGroup;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->distributorGroup = new ArrayCollection();
        $this->usersInGroup     = new ArrayCollection();
    }
}

/**
 * @ORM\Entity()
 * @ORM\Table(name="users_to_group_role")
 */
class UsersToGroupRole
{
    /**
     * @var int
     *
     * @ORM\Id()
     * @ORM\Column(type="integer",nullable=false)
     * @Assert\Type(type="integer")
     * @Assert\NotNull()
     */
    protected $usersId;

    /**
     * @var int
     *
     * @ORM\Id()
     * @ORM\Column(type="integer", nullable=false)
     * @Assert\Type(type="integer")
     * @Assert\NotNull()
     */
    protected $groupingRoleId;
}

在 EasyAdminBundle 中使用表单验证方法的一个小例子:

class AdminController extends EasyAdminController
{
    // ...

    protected function create<EntityName>EntityFormBuilder($entity, $view)
    {
        $builder = parent::createEntityFormBuilder($entity, $view);

        $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
            $data = $event->getData();

            $flag = false;
            if (isset($data['flag'])) {
                $flag = $data['flag'];
                unset($data['flag']);
            }
            $key = md5(json_encode($data));

            if ($flag !== $key) {
                $event->getForm()->add('flag', HiddenType::class, ['mapped' => false]);
                $data['flag'] = $key;
                $event->setData($data);
            }
        });

        return $builder;
    }

    protected function get<EntityName>EntityFormOptions($entity, $view)
    {
        $options = parent::getEntityFormOptions($entity, $view);

        $options['validation_groups'] = function (FormInterface $form) {
            if ($form->has('flag')) {
                return ['Default', 'CheckUserGroup'];
            }

            return ['Default'];
        };

        $options['constraints'] = new Callback([
            'callback' => function($entity, ExecutionContextInterface $context) {
                // validate here and adds the violation if applicable.

                $context->buildViolation('Warning!')
                    ->atPath('<field>')
                    ->addViolation();
            },
            'groups' => 'CheckUserGroup',
        ]);

        return $options;
    }
}

请注意,PRE_SUBMIT 事件在验证过程发生之前触发。

flag 字段是在提交表单后第一次(动态)添加的,因此添加了验证组 CheckUserGroup 并且回调约束完成了它的工作。后来第二次提交的数据中包含flag hash(如果数据没有变化),没有添加flag字段,所以也没有添加验证组,保存实体(同上)如果回调约束第一次没有添加违规)。

此外(如果您愿意)您可以在目标实体的自定义表单类型中执行所有这些操作。