索纳塔用户管理-自定义字段的依赖性[英] Sonata User Admin - Custom field dependency

本文是小编为大家收集整理的关于索纳塔用户管理-自定义字段的依赖性的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我已经扩展了fosuser的Sonataadmin类,并添加了2个自定义字段(来自外部数据源的选择类型):Company和Sector

我想制作Sector依赖Company,因此,如果用户选择了一个过滤可用扇区的公司.

i虽然在页面加载时使用Formevents进行过滤,但我什至不知道如何获得当前表单的Company值.

这是我的自定义SectorType

的一部分
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->addEventListener(FormEvents::PRE_SET_DATA
    , function(FormEvent $event) {
        $data = $event->getData();
        $form = $event->getForm();
        // Need to get the company value here if set
    });
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'choices' => $this->getSectors(),
    ));
}

public function getSectors()
{
    $sects = array();
    // Need to pass the selected company value to my getList
    // (which gets the list of sector as you can imagine)
    if (($tmp_sects = $this->ssrs->getList('Sector'))) {
        foreach ($tmp_sects as $sect) {
            $label = $sect['id'] ? $sect['label'] : '';
            $sects[$sect['id']] = $label;
        }
    }
    return $sects;
}

所以问题是:

如何从我的自定义SectorType?

中获取选定的Company

之后,我需要能够用Ajax刷新该行业,但这将是另一个问题

推荐答案

我也有类似的问题.我需要创建一个销售实体,必须与企业实体以及许多与服务实体的关系与许多关系相关联.这是销售实体:

问题是根据所选择的公司提供的服务.例如,服务A和B只能向X公司提供.服务B和C只能向公司提供.因此,在我的管理员中,根据所选择的公司,我必须显示可用的服务.对于这些我需要做2件事:

首先使用我的销售管理员创建动态表格,因此在服务器端,我可以为我的销售记录中指定的公司提供正确的服务.其次,我必须为我的公司表单元素创建一种自定义表单类型,以便当客户端的用户更改它时,它将发送AJAX请求,以获取适合公司的正确服务.

对于我的第一个问题,我做了类似于您要实现的目标,但是我没有为我的服务元素创建特定的自定义类型,而是直接在管理员中添加了de Event Listerer.

这是销售实体:

/**
 *
 * @ORM\Table(name="sales")
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks()
 */
class Sale
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
     public $id;
    /**
     * @ORM\ManyToOne(targetEntity="Branch")
     * @ORM\JoinColumn(name="branch_id", referencedColumnName="id", nullable = false)
     * @Assert\NotBlank(message = "Debe especificar una empresa a la cual asignar el precio de este exámen!")
     */
    private $branch;

    /** Unidirectional many to many
     * @ORM\ManyToMany(targetEntity="Service")
     * @ORM\JoinTable(name="sales_services",
     *      joinColumns={@ORM\JoinColumn(name="sale_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")}
     *      )
     * @Assert\Count(min = "1", minMessage = "Debe especificar al menos un servicio a realizar!")
     */
    private $services;


    public function __construct() {
        $this->services = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set branch
     *
     * @param Astricom\NeurocienciasBundle\Entity\Branch $branch
     */
     //default value always have to be null, because when validation constraint is set to notblank, 
     //if default is not null, before calling the validation constraint an error will pop up explaining
     //that no instance of Branch was passed to the $branch argument.
    public function setBranch(\Astricom\NeurocienciasBundle\Entity\Branch $branch = null)
    {
        $this->branch = $branch;
    }

    /**
     * Get branch
     *
     * @return Astricom\NeurocienciasBundle\Entity\Branch 
     */
    public function getBranch()
    {
        return $this->branch;
    }

     /**
     * Add service
     *
     * @param \Astricom\NeurocienciasBundle\Entity\Service|null $service
     */
    public function addServices(\Astricom\NeurocienciasBundle\Entity\Service $service = null)
    {
        $this->services[] = $service;
    }

    /**
     * Get services
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getServices()
    {
        return $this->services;
    }


    /**
     * Sets the creation date
     *
     * @param \DateTime|null $createdAt
     */
    public function setCreatedAt(\DateTime $createdAt = null)
    {
        $this->createdAt = $createdAt;
    }

    /**
     * Returns the creation date
     *
     * @return \DateTime|null
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Sets the last update date
     *
     * @param \DateTime|null $updatedAt
     */
    public function setUpdatedAt(\DateTime $updatedAt = null)
    {    
        $this->updatedAt = $updatedAt;
    }

因此,在管理员形式的构建器中:

protected function configureFormFields(FormMapper $formMapper)  {
    $em = $this->container->get('doctrine')->getEntityManager();
    $branchQuery = $em->createQueryBuilder();

    $branchQuery->add('select', 'b')
       ->add('from', 'Astricom\NeurocienciasBundle\Entity\Branch b')
       ->add('orderBy', 'b.name ASC');

    $formMapper
      ->with('Empresa/Sucursal')
         ->add('branch','shtumi_ajax_entity_type',array('required' => true, 'label'=>'Empresa/Sucursal','error_bubbling' => true, 'empty_value' => 'Seleccione una empresa/sucursal', 'empty_data'  => null, 'entity_alias'=>'sale_branch', 'attr'=>array('add_new'=>false), 'model_manager' => $this->getModelManager(), 'class'=>'Astricom\NeurocienciasBundle\Entity\Branch', 'query' => $branchQuery)) 
      ->end()
    ;

    $builder = $formMapper->getFormBuilder();
    $factory = $builder->getFormFactory(); 
    $sale = $this->getSubject();
    $builder->addEventListener(FormEvents::PRE_SET_DATA, 
        function(DataEvent $event) use ($sale,$factory, $em) {

            $form = $event->getForm();
            $servicesQuery = $em->createQueryBuilder();
            $servicesQuery->add('select','s')
                ->add('from','Astricom\NeurocienciasBundle\Entity\Service s');

            if (!$sale || !$sale->getId()) {
                $servicesQuery
                    ->where($servicesQuery->expr()->eq('s.id', ':id'))
                    ->setParameter('id', 0);
            }
            else {
                $servicesQuery
                    ->join('s.branch', 'b')
                    ->where($servicesQuery->expr()->eq('b.id', ':id'))
                    ->setParameter('id', $sale->getBranch()->getId());
            }

            $form->add($factory->createNamed('services','entity',null,array('required' => true, 'label'=>'Servicios','error_bubbling' => true, 'attr'=>array('show_value_label'=>true),'class'=>'Astricom\NeurocienciasBundle\Entity\Service','multiple'=>true,'expanded'=>true,'query_builder'=>$servicesQuery)));
        }
    );
}

诀窍是传递表单数据.在EVET-> GETDATA()的情况下,在Ever侦听器的函数中使用evet-> getData().相反,我通过admin-> getSubject()方法传递了它.然后,我不必在侦听器的函数中添加SonataAdmin表单类型,而是必须使用普通的Symfony表单类型.

您提到的Ajax部分是另一个问题.形式构建器中的分支添加方法上的所有怪异事物都与此问题的自定义字段类型有关.不用担心.

本文地址:https://www.itbaoku.cn/post/2090769.html

问题描述

I have extended the SonataAdmin class for FOSUser and added 2 custom fields (choice type from external data source): Company and Sector

I'd like to make Sector dependent on Company, so if the user selects a Company it filters the available Sectors.

I though about using FormEvents for filtering at page load, but I don't even know how to get the Company value of the current form.

Here is a part of my custom SectorType

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->addEventListener(FormEvents::PRE_SET_DATA
    , function(FormEvent $event) {
        $data = $event->getData();
        $form = $event->getForm();
        // Need to get the company value here if set
    });
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'choices' => $this->getSectors(),
    ));
}

public function getSectors()
{
    $sects = array();
    // Need to pass the selected company value to my getList
    // (which gets the list of sector as you can imagine)
    if (($tmp_sects = $this->ssrs->getList('Sector'))) {
        foreach ($tmp_sects as $sect) {
            $label = $sect['id'] ? $sect['label'] : '';
            $sects[$sect['id']] = $label;
        }
    }
    return $sects;
}

So the question is:

How to get the selected Company from my custom SectorType ?


After that I'll need to be able to refresh the Sector with Ajax, but that will be another question

推荐答案

I had a similar problem. I needed to create a sale entity that needed to be associated in a many to one relationship with an enterprise entity and a many to many relationship with services entities. Here is the Sale Entity:

The thing is that services where available depending on the companies chosen. For instance services a and b could only be provided to company x. And services b and c could only be provided to company y. So in my admin, depending on the chosen company I had to display the available services. For these I needed to do 2 things:

First create a dynamic form with my sale admin, so that on the server side I could get the right services available for the company specified in my sale record. And second, I had to create a custom form type for my company form element, so that when it was changed by the user on the client side, It would send an ajax request to get the right services for the company chosen.

For my first problem, I did something similar to what you were trying to achieve, but instead of creating an specific custom type for my services element, I added de event listener directly in the admin.

Here is the Sale entity:

/**
 *
 * @ORM\Table(name="sales")
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks()
 */
class Sale
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
     public $id;
    /**
     * @ORM\ManyToOne(targetEntity="Branch")
     * @ORM\JoinColumn(name="branch_id", referencedColumnName="id", nullable = false)
     * @Assert\NotBlank(message = "Debe especificar una empresa a la cual asignar el precio de este exámen!")
     */
    private $branch;

    /** Unidirectional many to many
     * @ORM\ManyToMany(targetEntity="Service")
     * @ORM\JoinTable(name="sales_services",
     *      joinColumns={@ORM\JoinColumn(name="sale_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")}
     *      )
     * @Assert\Count(min = "1", minMessage = "Debe especificar al menos un servicio a realizar!")
     */
    private $services;


    public function __construct() {
        $this->services = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set branch
     *
     * @param Astricom\NeurocienciasBundle\Entity\Branch $branch
     */
     //default value always have to be null, because when validation constraint is set to notblank, 
     //if default is not null, before calling the validation constraint an error will pop up explaining
     //that no instance of Branch was passed to the $branch argument.
    public function setBranch(\Astricom\NeurocienciasBundle\Entity\Branch $branch = null)
    {
        $this->branch = $branch;
    }

    /**
     * Get branch
     *
     * @return Astricom\NeurocienciasBundle\Entity\Branch 
     */
    public function getBranch()
    {
        return $this->branch;
    }

     /**
     * Add service
     *
     * @param \Astricom\NeurocienciasBundle\Entity\Service|null $service
     */
    public function addServices(\Astricom\NeurocienciasBundle\Entity\Service $service = null)
    {
        $this->services[] = $service;
    }

    /**
     * Get services
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getServices()
    {
        return $this->services;
    }


    /**
     * Sets the creation date
     *
     * @param \DateTime|null $createdAt
     */
    public function setCreatedAt(\DateTime $createdAt = null)
    {
        $this->createdAt = $createdAt;
    }

    /**
     * Returns the creation date
     *
     * @return \DateTime|null
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Sets the last update date
     *
     * @param \DateTime|null $updatedAt
     */
    public function setUpdatedAt(\DateTime $updatedAt = null)
    {    
        $this->updatedAt = $updatedAt;
    }

So then in the Admin form builder:

protected function configureFormFields(FormMapper $formMapper)  {
    $em = $this->container->get('doctrine')->getEntityManager();
    $branchQuery = $em->createQueryBuilder();

    $branchQuery->add('select', 'b')
       ->add('from', 'Astricom\NeurocienciasBundle\Entity\Branch b')
       ->add('orderBy', 'b.name ASC');

    $formMapper
      ->with('Empresa/Sucursal')
         ->add('branch','shtumi_ajax_entity_type',array('required' => true, 'label'=>'Empresa/Sucursal','error_bubbling' => true, 'empty_value' => 'Seleccione una empresa/sucursal', 'empty_data'  => null, 'entity_alias'=>'sale_branch', 'attr'=>array('add_new'=>false), 'model_manager' => $this->getModelManager(), 'class'=>'Astricom\NeurocienciasBundle\Entity\Branch', 'query' => $branchQuery)) 
      ->end()
    ;

    $builder = $formMapper->getFormBuilder();
    $factory = $builder->getFormFactory(); 
    $sale = $this->getSubject();
    $builder->addEventListener(FormEvents::PRE_SET_DATA, 
        function(DataEvent $event) use ($sale,$factory, $em) {

            $form = $event->getForm();
            $servicesQuery = $em->createQueryBuilder();
            $servicesQuery->add('select','s')
                ->add('from','Astricom\NeurocienciasBundle\Entity\Service s');

            if (!$sale || !$sale->getId()) {
                $servicesQuery
                    ->where($servicesQuery->expr()->eq('s.id', ':id'))
                    ->setParameter('id', 0);
            }
            else {
                $servicesQuery
                    ->join('s.branch', 'b')
                    ->where($servicesQuery->expr()->eq('b.id', ':id'))
                    ->setParameter('id', $sale->getBranch()->getId());
            }

            $form->add($factory->createNamed('services','entity',null,array('required' => true, 'label'=>'Servicios','error_bubbling' => true, 'attr'=>array('show_value_label'=>true),'class'=>'Astricom\NeurocienciasBundle\Entity\Service','multiple'=>true,'expanded'=>true,'query_builder'=>$servicesQuery)));
        }
    );
}

The trick thing was to pass the forms data. It doesn't work to use evet->getData() in the event listener's function. Instead I passed it through the admin->getSubject() method. Then instead of adding a sonataadmin form type, inside the event listener's function, I had to use a plain symfony form type.

The Ajax part as you mentioned is another question. All the weird things on the branch add method in the form builder is related to a customized field type for this matter. Don't worry about it.