Forms 从一个选择构建多个表单

Forms 从一个选择构建多个表单,forms,orm,symfony,many-to-many,Forms,Orm,Symfony,Many To Many,全部 我想问一下,是否有可能在一个页面上有多个表单(现在每个选择选项),而不是多个选择字段 情况是:我有一个与服务有@ManyToMany bi关系的用户和“User\u Services”关系存储表,但扩展了附加字段,如带有UserService实体类的min\u price,max\u price,等等 我认为在我的特殊情况下,更好的用户体验是使用带有复选框、服务名称和价格字段的表布局,并带有一个保存按钮,但我不知道如何创建多个表单,其中每个表单对应于选择列表中的一个选项,然后是该选项的其他

全部

我想问一下,是否有可能在一个页面上有多个表单(现在每个选择选项),而不是多个选择字段

情况是:我有一个与服务有@ManyToMany bi关系的用户和“User\u Services”关系存储表,但扩展了附加字段,如带有UserService实体类的
min\u price
max\u price
,等等

我认为在我的特殊情况下,更好的用户体验是使用带有复选框、服务名称和价格字段的表布局,并带有一个保存按钮,但我不知道如何创建多个表单,其中每个表单对应于选择列表中的一个选项,然后是该选项的其他字段


谢谢。

在这种情况下,我认为您应该使用
集合
类型,它可以用来处理多对多关系

如果我理解得很好,您希望为给定的
用户处理
用户服务的列表

然后,您必须制作如下内容:

  • 1、创建一个
    UserServiceType
    ,它将表示用户和服务之间的关系(加上其最低价格、最高价格等):
类UserServiceType扩展了AbstractType { 公共函数buildForm(FormBuilder$builder,数组$options) { $builder ->添加(‘最低价格’、‘货币’) ->添加(‘最高价格’、‘货币’) ; } 公共函数getDefaultOptions() { 返回数组('data_class'=>'Entity\UserService'); } }
  • 2、将其注册为表格类型:
//app/config/config.yml(例如)
服务:
用户\服务\类型:
类别:UserServiceType
标签:
-{name:form.type,别名:user\u service}
  • 3、配置
    UserType
    以处理此集合:
class用户类型扩展了AbstractType
{
公共函数buildForm(FormBuilder$builder,数组$options)
{
$builder
->添加('services','collection',数组(
'type'=>'user\u service',//这是上面注册的表单类型的id
“允许添加”=>true,
“允许删除”=>true,
“原型”=>正确,
))
;
}
公共函数getDefaultOptions()
{
返回数组('data_class'=>'Entity\User');
}
}

假设您有一组服务,并且希望显示它们

你会怎么做

我的解决方案:

控制器:

用户服务类型:

服务类型:

ServiceDetailsType:

最令人惊奇的是,所有这些工作!非常感谢Florian花时间在我身上,让我不断思考解决方案,并为不清楚的问题(如果是)道歉。我认为,Symfony文档应该更新为更多不同的表单嵌入/收集示例,如下所示

干杯,
迪玛。

谢谢你的回复,我今天晚上会试试看,好像“收藏”根本不起作用,我试着简化任务$生成器->添加('服务);-渲染倍增选择。但是$builder->add('services','collection',array('type'=>'text');-除“服务”标签外,不呈现任何内容。我使用{form_widget(form)}}来呈现表单。我还尝试了$builder->add('services','collection',array('type'=>newserviceType());在ServiceType()类($builder->add('name')中只有服务的“name”)。但也没什么。奇怪,非常奇怪,它不起作用,或者我错过了一些重要的东西。我甚至试过Symfony2书中的例子(或者说烹饪书,我不记得了),但都不管用。我使用的是2.0.10 Symfony。我认为您必须将
UserServiceType
注册为服务,并将其标记为
表单.type
。这将使此类型如下所示:
->添加('services','collection',array('type'=>'user\u service')
。请参阅我的更新答案。
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()
        ));
    }
}
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';
    }
}
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;
    }
}
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';
    }
}