我有一个类似的问题。我需要创建一个销售实体,该实体需要与企业实体以多对一关系关联,并与服务实体以多对多关系关联。这是销售实体:
问题是可用的服务取决于所选择的公司。例如,服务 a 和 b 只能提供给公司 x。并且服务 b 和 c 只能提供给公司 y。因此,在我的管理员中,根据选择的公司,我必须显示可用的服务。对于这些,我需要做两件事:
首先使用我的销售管理员创建一个动态表单,以便在服务器端我可以为我的销售记录中指定的公司获得正确的服务。其次,我必须为我的公司表单元素创建一个自定义表单类型,这样当客户端的用户更改它时,它会发送一个 ajax 请求来为所选公司获取正确的服务。
对于我的第一个问题,我做了一些类似于您想要实现的事情,但是我没有为我的服务元素创建特定的自定义类型,而是直接在管理中添加了 de 事件侦听器。
这是销售实体:
/**
*
* @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 部分是另一个问题。表单构建器中的分支添加方法上的所有奇怪的东西都与此问题的自定义字段类型有关。别担心。