symfony - Sonata User Admin - 自定义字段依赖

标签 symfony fosuserbundle sonata-admin

我为 FOSUser 扩展了 SonataAdmin 类并添加了 2 个自定义字段(来自外部数据源的选择类型):CompanySector

我想让 Sector 依赖于 Company,所以如果用户选择公司,它会过滤可用的 Sectors。

虽然我想在页面加载时使用 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只能提供给y公司。因此,在我的管理员中,根据所选的公司,我必须显示可用的服务。为此,我需要做两件事:

首先用我的销售管理员创建一个动态表单,这样我就可以在服务器端为我的销售记录中指定的公司获得正确的服务。其次,我必须为我的公司表单元素创建一个自定义表单类型,这样当它被客户端的用户更改时,它会发送一个 ajax 请求以获得所选公司的正确服务。

对于我的第一个问题,我做了一些类似于您想要实现的事情,但我没有为我的服务元素创建特定的自定义类型,而是直接在管理中添加了事件监听器。

这是销售实体:

/**
 *
 * @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() 不起作用。相反,我通过 admin->getSubject() 方法传递它。然后,我不得不在事件监听器的函数中使用普通的 symfony 表单类型,而不是添加 sonataadmin 表单类型。

您提到的 Ajax 部分是另一个问题。表单构建器中分支添加方法的所有奇怪的事情都与这个问题的自定义字段类型有关。别担心。

关于symfony - Sonata User Admin - 自定义字段依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16526547/

相关文章:

oop - Symfony2 - 带有类和扩展类的 Validation.yml

php - FOSUserBundle 实体构造

symfony - Sonata AdminBundle - 如何更改到仪表板的路线?

Symfony 2 FOSFacebookBundle 登录前自定义重定向

php - 奏鸣曲管理员捆绑symfony

php - 奏鸣曲日期范围过滤器

php - Symfony 缓存 :clear Failed to remove directory

symfony - Symfony2中用于缓存的内部路由

php - Doctrine Migrations 项目是否与 Doctrine MongoDB 兼容?

Symfony2 和 FOSUserBUndle - 强制用户更改密码