Generate same form type on same page multiple times Symfony2

我的梦境 提交于 2019-11-29 02:33:07

Hope this will help somebody.

The proper way will be to use Symfony's form.factory service to create a named builder and in turn create a form from that. I recommend creating a function for the form creation process as (as I understand, correct me if I', wrong) each FormBuilder instance must be different to create a different form.

Just as an explanation of the purpose of the code: I needed to show a list of open tickets in the help system with ability to assign a person (authorized without logging in) based on their login token to the ticket. That required to display N forms on single page that would be unique but generated from single "template" or Type if you will.

This code achieved that without any hacks. There is just no shorthand method to createForm with specific ID (name) from the controller AFAIK.

ex.

public function generateFormForTicketAssignment(Ticket $ticket) {   

    $ticketAssignType = new TicketAssignInvokeType();
    $ticketAssignType->setNameSuffix($ticket->getId());

    /**
     * @var Symfony\Component\Form\FormBuilderInterface
     */
    $builder = $this->get('form.factory')->createNamedBuilder($ticketAssignType->getName(), $ticketAssignType );
    $builder->setAutoinitialize(true);
    $formTicket = $builder->getForm();

    $formTicket->get('ticket')->setData($ticket);


    return $formTicket;
}

AND (this is important part) the ticketAssignInvokeType looks like this:

class TicketAssignInvokeType extends AbstractType {

private $nameSuffix = null;
private $name = 'ticket_assign_invoke';

public function __constructor(string $suffix = null)   {
    //parent::__construct();

    $this->nameSuffix = $this->generateNameSuffix();
}

private function generateNameSuffix() {
    if ($this->nameSuffix == null ||  $this->nameSuffix == '') {
        $generator = new SecureRandom();
        //change data to alphanumeric string
        return bin2hex($generator->nextBytes(10));
    }

    return $this->nameSuffix;
}

/**
 * 
 * @param string $suffix When set suffix added to form will use selected 
 * string (note it should be unique for all forms on a page).
 */
public function setNameSuffix($suffix){
   $this->nameSuffix = $suffix;
}

public function buildForm(FormBuilderInterface $builder, array $options)   {
    $builder
        ->add('loginToken',new AuthenticateTokenType())
        ->add('ticket',new TicketIDType())
        ->add('save', 'submit', array('label' => 'form.button.assign'))
    ;

}

public function getName()    {
    if ($this->nameSuffix == null || $this->nameSuffix == "" ) {
        $this->nameSuffix = $this->generateNameSuffix();
    }
    return $this->name .'_'. $this->nameSuffix;
}

public function configureOptions(OptionsResolver $resolver)    {
   // ...
}
}

This is somewhat overly complex logic and testing for name suffix but at some point I could not figure out why all I go was form name without suffix hence the complexity.

PS. I have created forms as services and will later test if a service can be used as well as this was my first intention.

PS2. I am not sure about the setAutoinitialize method yet, but will test it furtner as well.

Now in Symfony 3.0 they changed the createNamedBuilder, so it's possible to solve this by only calling:

use AppBundle\Form\ShippingTrackCodeReturnType;

$uniqueForm = $this->get('form.factory')->createNamedBuilder('ship_form_'.$orderRecord->getId(), ShippingTrackCodeReturnType::class, $orderRecord)->getForm();

So, you just need to loop to display and save them:

foreach ($invoice->getOrderRecords() as $key => $orderRecord) 
{
    // creates the forms with different names
    $returnShipTrackCodeForm = $this->get('form.factory')->createNamedBuilder('ship_form_'.$orderRecord->getId(), ShippingTrackCodeReturnType::class, $orderRecord)->getForm();

    $returnShipTrackCodeForm->handleRequest($request);
    if ($returnShipTrackCodeForm->isSubmitted() && $returnShipTrackCodeForm->isValid()) 
    {
        // flush object
    }

    $returnForms[$orderRecord->getId()] = $returnShipTrackCodeForm;
}  
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!