Обработка сложной формы Symfony2 с несколькими отношениями сущностей

У меня есть форма (все еще не законченная и в ней отсутствуют многие поля), которая обрабатывается как мастер с шагами, в которых обрабатываются поля из нескольких объектов. Это сама форма:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
            ->add('tipo_tramite', 'entity', array(
                'class' => 'ComunBundle:TipoTramite',
                'property' => 'nombre',
                'required' => TRUE,
                'label' => "Tipo de Trámite",
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('q')
                            ->where('q.activo = :valorActivo')
                            ->setParameter('valorActivo', TRUE);
                }
            ))
            ->add('oficina_regional', 'entity', array(
                'class' => 'ComunBundle:OficinaRegional',
                'property' => 'nombre',
                'required' => TRUE,
                'label' => "Oficina Regional",
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('q')
                            ->where('q.activo = :valorActivo')
                            ->setParameter('valorActivo', TRUE);
                }
            ))
            ->add('procedencia_producto', 'entity', array(
                'class' => 'ComunBundle:ProcedenciaProducto',
                'property' => 'nombre',
                'required' => TRUE,
                'label' => "Procedencia del Producto"
            ))
            ->add('finalidad_producto', 'entity', array(
                'class' => 'ComunBundle:FinalidadProducto',
                'property' => 'nombre',
                'required' => TRUE,
                'label' => "Finalidad del Producto"
            ))
            ->add('condicion_producto', 'entity', array(
                'class' => 'ComunBundle:CondicionProducto',
                'property' => 'nombre',
                'required' => TRUE,
                'label' => "Condición del Producto"
            ))
            ->add('lote', 'integer', array(
                'required' => TRUE,
                'label' => "Tamaño del Lote"
            ))
            ->add('observaciones', 'text', array(
                'required' => FALSE,
                'label' => "Observaciones"
    ));

}

У меня есть вопрос о том, как обрабатывать параметр data_class в этом случае, поэтому мне не нужно колдовать в контроллере. Когда я говорю магия, я имею в виду следующее:

public function empresaAction()
{
    $entity = new Empresa();
    $form = $this->createForm(new EmpresaFormType(), $entity);
    return array( 'entity' => $entity, 'form' => $form->createView() );

}

public function guardarEmpresaAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();

    /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
    $userManager = $this->container->get('fos_user.user_manager');
    /** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
    $dispatcher = $this->container->get('event_dispatcher');
    /** @var $mailer FOS\UserBundle\Mailer\MailerInterface */
    $mailer = $this->container->get('fos_user.mailer');

    $request_empresa = $request->get('empresa');
    $request_sucursal = $request->get('sucursal');
    $request_chkRif = $request->get('chkRif');

    $request_estado = $request_empresa[ 'estado' ];
    $request_municipio = $request->get('municipio');
    $request_ciudad = $request->get('ciudad');
    $request_parroquia = $request->get('parroquia');

    $user = $userManager->createUser();

    $event = new GetResponseUserEvent($user, $request);
    $dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, $event);

    if (null !== $event->getResponse())
    {
        return $event->getResponse();
    }

    $entity = new Empresa();
    $form = $this->createForm(new EmpresaFormType(), $entity);
    $form->handleRequest($request);

    $success = $url = $errors = "";

    if ($form->isValid())
    {
        if ($request_sucursal != NULL || $request_sucursal != "")
        {
            $padreEntity = $em->getRepository('UsuarioBundle:Empresa')->findOneBy(array( "padre" => $request_sucursal ));

            if (!$padreEntity)
            {
                $padreEntity = $em->getRepository('UsuarioBundle:Empresa')->findOneBy(array( "id" => $request_sucursal ));
            }

            if ($request_chkRif != NULL || $request_chkRif != "")
            {
                $rifUsuario = $request_empresa[ 'tipo_identificacion' ] . $request_empresa[ 'rif' ];
            }
            else
            {
                $originalRif = $padreEntity->getRif();
                $sliceRif = substr($originalRif, 10, 1);
                $rifUsuario = $originalRif . ($sliceRif === false ? 1 : $sliceRif + 1);
            }

            $entity->setPadre($padreEntity);
        }
        else
        {
            $rifUsuario = $request_empresa[ 'tipo_identificacion' ] . $request_empresa[ 'rif' ];
        }

        $user->setUsername($rifUsuario);
        $user->setRepresentativeName($request_empresa[ 'razon_social' ]);
        $user->setEmail($request_empresa[ 'usuario' ][ 'email' ]);
        $user->setPlainPassword($request_empresa[ 'usuario' ][ 'plainPassword' ][ 'first' ]);

        $pais = $em->getRepository('ComunBundle:Pais')->findOneBy(array( "id" => 23 ));
        $user->setPais($pais);

        $estado_id = $request_estado ? $request_estado : 0;
        $estado = $em->getRepository('ComunBundle:Estado')->findOneBy(array( "id" => $estado_id ));
        $user->setEstado($estado);

        $municipio_id = $request_municipio ? $request_municipio : 0;
        $municipio = $em->getRepository('ComunBundle:Municipio')->findOneBy(array( "id" => $municipio_id ));
        $user->setMunicipio($municipio);

        $ciudad_id = $request_ciudad ? $request_ciudad : 0;
        $ciudad = $em->getRepository('ComunBundle:Ciudad')->findOneBy(array( "id" => $ciudad_id ));
        $user->setCiudad($ciudad);

        $parroquia_id = $request_parroquia ? $request_parroquia : 0;
        $parroquia = $em->getRepository('ComunBundle:Parroquia')->findOneBy(array( "id" => $parroquia_id ));
        $user->setParroquia($parroquia);

        ...
    }
    else
    {
        $errors = $this->getFormErrors($form);
        $success = FALSE;
    }

    return new JsonResponse(array( 'success' => $success, 'errors' => $errors, 'redirect_to' => $url ));

}

Поскольку 'data_classonEmpresaFormTypeis set toUsuarioBundle\Entity\Empresa`, мне нужно обработать любой дополнительный параметр, как показано в примере выше, с помощью getter/setter, и это много работы для сложных/больших форм.

В образце формы поля tipo_tramite будут сохраняться в классе ComunBundle\Entity\Producto, но поле oficina_regional будет сохраняться в классе ComunBundle\Entity\SolicitudUsuario, и поэтому с другими, которые даже не размещены здесь, но они есть в форме, всего должно сохраняться как 3 или 4 объекта. включая отношения во многих случаях, как вы справляетесь с этим?

Я знаю, что есть CraueFormFlowBundle, который может охватывать этот процесс/поток, но не уверен, что это решение.

Любой совет?


person ReynierPM    schedule 13.10.2014    source источник


Ответы (1)


Несколько дней назад работал с многоступенчатой ​​​​формой. Я думаю, вам нужны встроенные формы. В любом случае могу порекомендовать вам еще один хороший пакет для создания мастера: SyliusFlowBundle. ИМО, он более гибкий и простой для понимания, чем CraueFormFlowBundle.

Кстати, почему вы хотите хранить все в одной форме? Мы использовали одну форму для каждого шага, и мне понравился такой подход.

person Roman Kliuchko    schedule 13.10.2014
comment
@roma-kliuchko Я принимаю идеи, это не окончательное решение, я пытаюсь поделиться с другими опытом в этом, возможно ли, чтобы вы поделились хотя бы пакетом, в котором вы используете предложенный вами пакет? Было бы неплохо иметь это в качестве учебного случая - person ReynierPM; 14.10.2014
comment
извините, не могу поделиться этим кодом, он личный. Но у них есть хороший документ здесь. Надеюсь, это поможет вам принять решение. - person Roman Kliuchko; 14.10.2014
comment
@ roma-kliuchko Следуя вашему предложению, я перехожу на SyliusFlowBundle, но у меня много сомнений, а документы не так хороши для разработчиков, всего несколько строк и ничего больше. Итак, вы упоминаете здесь, что уже сделали то же самое, используя этот пакет, верно? Итак, мой первый вопрос: где и как я создаю/вызываю сценарий, который я создаю? - person ReynierPM; 14.10.2014
comment
@ReynierPM, вам не следует создавать экземпляр напрямую. Просто настройте sylius.flow как сервис следующим образом: some_name.scenario.flow: class: path\to\your\scenario calls: - [ setContainer, [@service_container] ] tags: - { name: sylius.process.scenario, alias: some_alias } и настройте маршрутизацию: some_flow: resource: @SyliusFlowBundle/Resources/config/routing.yml prefix: /some_url - person Roman Kliuchko; 14.10.2014
comment
извините за форматирование - не могу найти, как сделать лучше в комментарии. За исключением этой конфигурации, все, что вам нужно, это определить ваш сценарий и шаги, которые вам нужны. - person Roman Kliuchko; 14.10.2014
comment
@ roma-kliuchko до сих пор не понимает, как мне вызвать форму на моем контроллере, возможно, мой ответ неверен и должен быть чем-то вроде, как мне вызвать и отобразить форму в контроллере для последующего использования? Также я спрашиваю, возможно ли сохранить (сохранить) каждый шаг и оставить процесс незавершенным, а затем вернуться к той же форме, отредактировать поток и иметь те же сохраненные данные. - person ReynierPM; 14.10.2014
comment
@ReynierPM, с этим пакетом нет необходимости определять контроллер, как обычно. Вместо этого вы определяете шаги, которые сами являются контроллерами (Sylius ContainerAwareStep расширяет контроллер). На шаге вы реализуете displayAction и forwardAction. Конечно, вы можете сохранить отправленные данные в forwardAction, используя $context->getStorage()->set() или даже записать данные в БД с помощью диспетчера сущностей. - person Roman Kliuchko; 15.10.2014
comment
@ roma-kliuchko хорошо, так как вы не можете поделиться всем пакетом, можете ли вы поделиться только forwardAction, просто чтобы посмотреть, как вы управляете вещами внутри этой функции? - person ReynierPM; 15.10.2014
comment
да, public function forwardAction(ProcessContextInterface $context) { $form = $this->getStepForm($context->getStorage()->get('some_name')); $form->handleRequest($context->getRequest()); if ($context->getRequest()->isMethod('POST') && $form->isValid()) { return $this->onFormValid($form, $context); } return $this->createView($form, $context); } - здесь getStepForm() и onFormValid абстрактные методы. Первый из них только создает форму, второй - может делать дополнительные проверки и если данные в порядке - сохраняет их. - person Roman Kliuchko; 15.10.2014
comment
Самый простой onFormValid может быть таким: protected function onFormValid(Form $form, ProcessContextInterface $context) { $context->getStorage()->set('some_name', $form->getData()); return $this->complete(); } - вместо установки данных в хранилище вы можете сохранить данные формы с помощью диспетчера сущностей, если это необходимо - person Roman Kliuchko; 15.10.2014
comment
@ roma-kliuchko Теперь я получаю все это, спасибо вам, в качестве связанного ответа вы можете взглянуть на это? - person ReynierPM; 15.10.2014