所有
我想询问是否可以在一个页面上使用多个表单(现在每个选择选项)而不是多个选择字段。
情况是:我的用户与@ManyToMany双向关联服务和'user_services'关系存储表,但扩展了其他字段,如min_price
,max_price
等与UserService Doctrine Entity类。
我认为在我的特定情况下更好的用户体验是使用带有一个保存按钮的复选框,服务名称和价格字段的表格布局,但我无法获得如何创建多个表单,其中每个表单对应于例如,选择列表中的一个选项,后跟此选项的其他字段。
感谢。
答案 0 :(得分:1)
在这种情况下,我认为你应该使用collection
类型,它可以用来处理多对多的关系。
如果我理解的话,您希望处理给定user_services
的{{1}}列表。
然后你必须做这样的事情:
user
(加上其min_price,max_price等):UserServiceType
class UserServiceType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('min_price', 'currency')
->add('max_price', 'currency')
;
}
public function getDefaultOptions()
{
return array('data_class' => 'Entity\UserService');
}
}
// app/config/config.yml (for example)
services:
user_service_type:
class: UserServiceType
tags:
- { name: form.type, alias: user_service }
来处理此集合:UserType
答案 1 :(得分:0)
想象一下,你有很多服务,你想要显示它们
你会做什么?
我的解决方案:
控制器:
class DefaultController extends Controller
{
public function indexAction(Request $request)
{
/** @var $em \Doctrine\ORM\EntityManager */
$em = $this->get('doctrine.orm.entity_manager');
$services = $em->getRepository('ThestudioscheduleProfileBundlesServiceBundle:Service')->findAll();
$user = $this->get('security.context')->getToken()->getUser();
$form = $this->createForm(new UserServiceType($services, $user->getServiceDetails()));
if ('POST' == $request->getMethod()) {
$form->bindRequest($request);
if ($form->isValid()) {
$data = $form->getData();
$em->getConnection()->beginTransaction();
try {
foreach ($data['services'] as $serviceDetails) {
// if service is selected
if ($serviceDetails['id']) {
$serviceDetails['details']->setUser($user);
$serviceDetails['details']->setService($em->getRepository('ThestudioscheduleProfileBundlesServiceBundle:Service')->find($serviceDetails['service']));
$serviceDetails['details'] = $em->merge($serviceDetails['details']);
} else {
// if the entity is exist but user unchecked it - delete it
if ($serviceDetails['details']->getId()) {
$serviceDetails['details'] = $em->merge($serviceDetails['details']);
$em->remove($serviceDetails['details']);
}
}
}
$em->flush();
$em->getConnection()->commit();
// TODO: display success message to user
return $this->redirect($this->generateUrl('ThestudioscheduleProfileBundlesServiceBundle_homepage'));
} catch (\Exception $e) {
$em->getConnection()->rollback();
$em->close();
var_export($e->getMessage());die;
// TODO: log exception
// TODO: display something to user about error
}
}
}
return $this->render('ThestudioscheduleProfileBundlesServiceBundle:Default:index.html.twig', array(
'form' => $form->createView()
));
}
}
UserServiceType:
class UserServiceType extends AbstractType
{
private $services;
private $userServiceDetails;
public function __construct($services, $userServiceDetails)
{
$this->services = $services;
$this->userServiceDetails = $userServiceDetails;
}
/**
* @param \Symfony\Component\Form\FormBuilder $builder
* @param array $options
* @return void
*/
public function buildForm(FormBuilder $builder, array $options)
{
// all application services
$builder->add('services', 'collection');
foreach ($this->services as $key => $service) {
$serviceType = new ServiceType($service, null);
foreach ($this->userServiceDetails as $details) {
if ($service == $details->getService()) {
$serviceType->setUserServiceDetails($details);
}
}
$builder->get('services')->add('service_' . $key, $serviceType);
}
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName()
{
return 'profile_user_service';
}
}
的ServiceType:
class ServiceType extends AbstractType
{
private $service;
private $userServiceDetails;
public function __construct($service, $userServiceDetails)
{
$this->service = $service;
$this->userServiceDetails = $userServiceDetails;
}
/**
* @param \Symfony\Component\Form\FormBuilder $builder
* @param array $options
* @return void
*/
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('id', 'checkbox', array(
'label' => $this->service->getName(),
'required' => false))
->add('service', 'hidden')
->add('details', new ServiceDetailsType($this->userServiceDetails));
$values = array('service' => $this->service->getId());
if (null !== $this->userServiceDetails) {
$values = array_merge($values, array('id' => true));
}
$builder->setData($values);
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName()
{
return 'profile_service';
}
public function setUserServiceDetails($details)
{
$this->userServiceDetails = $details;
}
}
ServiceDetailsType:
class ServiceDetailsType extends AbstractType
{
private $details;
public function __construct($details)
{
$this->details = $details;
}
/**
* @param \Symfony\Component\Form\FormBuilder $builder
* @param array $options
* @return void
*/
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('id', 'hidden')
->add('minPrice', 'money', array('required' => false))
->add('maxPrice', 'money', array('required' => false))
->add('unit', 'choice', array(
'choices' => array(
'hour' => 'Hours',
'photo' => 'Photos'
),
'required' => false
))
->add('unitsAmount', null, array('required' => false));
if (!empty($this->details)) {
$builder->setData($this->details);
}
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Thestudioschedule\ProfileBundles\ServiceBundle\Entity\UserService',
'csrf_protection' => false
);
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
function getName()
{
return 'profile_service_details';
}
}
所有这一切最令人惊奇的事情!非常感谢Florian花时间在我身上并让我思考解决方案,并为不明确的问题道歉(如果是的话)。我认为,Symfony文档应该使用更多不同的表单嵌入/集合示例进行更新。
干杯, 迪马。