Несколько форм построены из одного выбора - PullRequest
0 голосов
/ 26 февраля 2012

все.

Я хотел бы спросить, возможно ли иметь несколько форм (теперь для каждой опции выбора) на одной странице вместо поля множественного выбора.

Ситуация такова: IПользователь с двусторонним отношением @ManyToMany к Службам и таблицей хранения отношений «user_services», но расширен с помощью дополнительных полей, таких как min_price, max_price и т. д., с классом UserService Doctrine Entity.

Я думаю, чтолучший пользовательский опыт в моем конкретном случае состоит в том, чтобы иметь макет таблицы с флажками, названиями услуг и полями цены с одной кнопкой сохранения, но я не могу понять, как создать несколько форм, в которых каждая форма соответствует одному варианту из списка выбора, напримера затем дополнительные поля для этой опции.

Спасибо.

Ответы [ 2 ]

1 голос
/ 27 февраля 2012

В этом случае, я думаю, вам следует использовать тип collection, который можно использовать для обработки многих отношений.

Вы хотите обработать список user_services для данного user, если я хорошо понимаю.

Затем вы должны сделать что-то вроде этого:

  • 1, создайте UserServiceType, который будет представлять отношения между пользователем и службой (плюс его min_price, max_price и т. д.):
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');
    }
}
  • 2, зарегистрируйте его как form_type:
// app/config/config.yml (for example)
services:
    user_service_type:
        class: UserServiceType
        tags:
            - { name: form.type, alias: user_service }
  • 3, настройтеВаш UserType для обработки этой коллекции:
class UserType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('services', 'collection', array(
                'type'      => 'user_service', // this is the id of the form type registered above
                'allow_add' => true,
                'allow_delete' => true,
                'prototype' => true,
            ))
        ;
    }

    public function getDefaultOptions()
    {
        return array('data_class' => 'Entity\User');
    }
}
0 голосов
/ 04 марта 2012

Представьте, что у вас есть несколько служб, и вы хотите их отобразить

enter image description here

Что бы вы сделали?

Мое решение:

Контроллер:

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;
    }
}

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';
    }
}

Самое удивительное, что все это работает!Большое спасибо Флориану за то, что он уделил мне время и заставил меня задуматься над решением, и я прошу прощения за неясный вопрос (если он есть).Я думаю, что документы Symfony должны быть обновлены с помощью более разнообразных примеров встраивания / сбора форм, подобных этому.

Cheers, Dima.

...