Generate same form type on same page multiple times Symfony2

核能气质少年 提交于 2019-11-27 16:48:24

问题


I'm trying to generate a form type in particular the "ProductLanguageType".

I want to generate the ProductLanguageType as many times as the current numbers of existing languages in the Language table.

For example if I have (English, French, Russian, Chinese) in the Language table, it would generate 4 ProductLanguageType form on the same page.

I would like to know how do I query language table and generate multiple form of the same type on the same page, is the form builder capable of doing it or is there another workaround? Been having some trouble with this for some time now and would be happy to find a good solution for this.

ProductLanguageType:

class ProductLanguageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){

    $builder->add('id_language', 'entity', array(
                   'class' => 'AdminBundle:Language',
                   'data_class' => 'Main\AdminBundle\Entity\Language',
                   'property' => 'language'
                  )
                 )
            ->add('name', 'text')
            ->add('description', 'ckeditor', array(
                    'config_name' => 'admin',
                    'config' => array(
                        'filebrowser_image_browse_url' => array(
                            'route'            => 'elfinder',
                            'route_parameters' => array('instance' => 'default'),
                        ),
                    )
                ))
            ->add('short_description', 'text');

}

public function getName(){
    return 'productLanguage';
}
}

ProductType(ProductLanguageType is embeded in here):

class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){

    $builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
    $builder->add('productLanguage', new ProductLanguageType())
            ->add('id_seller','text')
            ->add('price','text')
            ->add('cost_price','text')
            ->add('retail_price','text')
            ->add('hot', 'checkbox')
            ->add('featured', 'checkbox')
            ->add('new', 'checkbox')
            ->add('free_shipping', 'checkbox')
            ->add('status','text') //active or inactive, to be decided if hidden or visible
            ->add('Add', 'submit');

}
}

回答1:


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.




回答2:


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


来源:https://stackoverflow.com/questions/27690680/generate-same-form-type-on-same-page-multiple-times-symfony2

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