【问题标题】:Easy Admin 3 (Symfony 4) AssociationField in OneToOne relationship shows already associated entitiesOneToOne 关系中的 Easy Admin 3 (Symfony 4) AssociationField 显示已经关联的实体
【发布时间】:2021-07-04 07:32:46
【问题描述】:

将 Symfony 4.4 与 Easy Admin 3 一起使用:
我有一对一的关系

class Usuario
{
...
    /**
     * @ORM\OneToOne(targetEntity=Hora::class, inversedBy="usuario", cascade={"persist", "remove"})
     */
    private $hora;
...
}
class Hora
{
...
    /**
     * @ORM\OneToOne(targetEntity=Usuario::class, mappedBy="hora", cascade={"persist", "remove"})
     */
    private $usuario;
...
}

我有一个用于 Usuario 的 CRUD 控制器:

class UsuarioCrudController extends AbstractCrudController
{
    public function configureFields(string $pageName): iterable
    {
    ...
    return [
    ...
            AssociationField::new('hora', 'Hora'),
        ];

一切似乎都还好,但在“Usuario”的管理表单中,“hora”字段显示了数据库中的所有值,甚至那些已经分配给其他“Usuario”实体的值:
我想要下拉控件仅显示未分配的值,加上实际“Usuario”实体的值,因此控件易于使用。

使用 easyadmin 执行此操作的正确方法是什么?

我已经设法在 UsuarioCrudController 类中使用 $this->getDoctrine()->setFormTypeOptions([ "choices" => 对该字段进行编码以仅显示未关联的“Hora”值,

但我无法访问正在管理的实际实体,也无法访问 UsuarioCrudController 类(可能无法访问),也无法访问 Usuario 类(我在这里尝试过 __construct(EntityManagerInterface $entityManager) 无济于事,因为该值没有好像被注入了,不知道为什么)。

【问题讨论】:

    标签: symfony dependency-injection doctrine-orm easyadmin easyadmin3


    【解决方案1】:

    fwiw,可以在 Symfony easyadmin CrudController 的 configureFields() 方法中访问正在编辑的实际实体using

    if ( $pageName === 'edit' ) {
        ...
        $this->get(AdminContextProvider::class)->getContext()->getEntity()->getInstance()
        ...
    

    这样,在 configureFields() 中我可以添加代码来过滤我的实体:

    $horas_libres = $this->getDoctrine()->getRepository(Hora::class)->findFree();
    

    然后也添加实际的实体值,这就是我想要做的

    array_unshift( $horas_libres, 
    $this->get(AdminContextProvider::class)->getContext()->getEntity()->getInstance()->getHora() );
    

    现在可以使用“选择”在返回的数组中构造字段:

    return [ ...
                AssociationField::new('hora', 'Hora')->setFormTypeOptions([
                    "choices" => $horas_libres
                ]),
           ]
    

    【讨论】:

    • 请分享更多细节。这如何解决原来的问题?
    • 好的,所有细节都已添加。欢迎以“Symfony 方式”改进此代码的任何帮助:-)
    • 这个关于如何从上下文访问实体的提示非常有帮助!它应该在官方文档中的某处提及。谢谢!
    【解决方案2】:

    可以通过覆盖 EasyAdmin 方法或侦听 EasyAdmin 事件来自定义 Easy admin 中的一些内容。

    Example of methods:

    public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
    public function createEntity(string $entityFqcn)
    public function createEditForm(EntityDto $entityDto, KeyValueStore $formOptions, AdminContext $context): FormInterface
    //etc..
    

    Example of events:

    use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
    use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityDeletedEvent;
    use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityPersistedEvent;
    use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
    use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
    use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
    use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityPersistedEvent;
    use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityUpdatedEvent;
    

    您可以覆盖easy admin createEditFormBuildercreateNewFormBuilder 方法,这样您就可以访问当前表单数据并修改您的hora 字段。

    类似:

     use Symfony\Bridge\Doctrine\Form\Type\EntityType;
     use Symfony\Component\Form\FormBuilderInterface;
     use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
     use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
     
     public function createEditFormBuilder(EntityDto $entityDto, KeyValueStore $formOptions, AdminContext $context): FormBuilderInterface {
        $formBuilder = parent::createEditFormBuilder($entityDto, $formOptions, $context);
    
        $unassignedValues = $this->yourRepo->findUnassignedValues();
        $data = $context->getEntity()->getInstance();
        if(isset($data) && $data->getHora()){
            //if your repo return an ArrayCollection
            $unassignedValues = $unassignedValues->add($data->getHora());
        }
        // if 'class' => 'App\Entity\Hora' is not passed as option, an error is raised (see //github.com/EasyCorp/EasyAdminBundle/issues/3095):
        //      An error has occurred resolving the options of the form "Symfony\Bridge\Doctrine\Form\Type\EntityType": The required option "class" is missing.
        $formBuilder->add('hora', EntityType::class, ['class' => 'App\Entity\Hora', 'choices' => $unassignedValues]);
    
        return $formBuilder;
    }
    

    目前,easyadmin3 仍然缺乏文档,所以有时最好的方法是查看 admin 的操作方式。

    【讨论】:

    • 谢谢,但也许我必须做更多的事情?:Compile Error: Could not check compatibility between App\Controller\Admin\UsuarioCrudController::createFormBuilder($data = NULL, array $options = Array): App\Controller\Admin\FormBuilderInterface and Symfony\Bundle\FrameworkBundle\Controller\AbstractController::createFormBuilder($data = NULL, array $options = Array): Symfony\Component\Form\FormBuilderInterface, because class App\Controller\Admin\FormBuilderInterface is not available。在 UsuarioCrudController.php 中添加 use App\Controller\Admin\FormBuilderInterface; 并不能解决这个问题。
    • 你好像是FormBuilderInterface的导入错误,你可以试试我更新的代码(你需要修改才能让它工作)
    • 是的,你是对的,(: FormBuilderInterface 是必要的),正确的导入是use Symfony\Component\Form\FormBuilderInterface;。但是现在,我如何显示该字段?如果我不使用configureFields(),它不会出现,如果我使用它,AssociationField::new('hora', 'Hora') 会显示与以前相同的内容。我应该只使用AssociationField 来查看更改吗?
    • 同时使用 configureFields 和覆盖 createFormBuilder 有效,您只是在表单构建器中修改表单时覆盖了表单,所以关键是像常规表单一样修改 createFormBuilder 中的 hora 字段在 symfony 中
    • 非常感谢,使用 createEditFormBuilder() 运行正常!我想知道为什么下拉控件没有像使用 AssociationField::new() 方法时那样的搜索字段:-o
    猜你喜欢
    • 2021-12-13
    • 2014-01-10
    • 2020-11-26
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    • 1970-01-01
    • 2015-11-14
    相关资源
    最近更新 更多