Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony - Add text in generated form

I'd like to do something quite simple, but I can't figure out how to manage it. I have a form:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}

There are several text field in it. I'd like to "insert" some text (like <p>my Text</p>) between two text fields (let's say between name text field and description text field). Form are generated with form builder tool. I've tried something like:

$builder
    ->add('stuffName') // works well (text field 1)
    ->add('addedText', 'text', array('label' => 'my Text')) // Trouble here!
    ->add('stuffDescription'); // works well (text field 2)

But it generates a text field (and not a simple text). I don't care if the text is set in the form builder or directly in twig template... As long as it is between my two text fields. Any idea?

Thanks a lot!

like image 796
DavidL Avatar asked Feb 08 '23 00:02

DavidL


2 Answers

Symfony forms contain only form fields. Any additional content you want has to be added by the template.

This means you'll have to output the form field-by-field. Your form, for example might look like this:

{{ form_start(form) }}
    {{ form_row(form.stuffName) }}

    <p>Your Text</p>

    {{ form_row(form.stuffDescription) }}
{{ form_end(form) }}

For more more information on how you can customize form rendering, please see the forms chapter in the Symfony documentation.

like image 181
jbafford Avatar answered Feb 12 '23 04:02

jbafford


The keyword in this question is generated.

Let's assume, that you build a form generator in Symfony. You have entities like Form, Fields and Fields Items (it's options for select box or buttons for radio button field).

So you have this entities and you create a service to create a form from the data. In the service you build the form ($this->buildedForm - generated form, $page->getFormData() - put the data to the constructed form):

$this->buildedForm = $this->formFactory->create(
    'form',
    $page->getFormData(),
    ['action' => '/page/formview/' . $task->getId()]
);

foreach($fields as $field) {
    $fieldBuilderMethod = 'construct' . ucfirst($field->getType()) . 'Field';
    if (method_exists($this, $fieldBuilderMethod)) {
        $this->$fieldBuilderMethod($field);
    }
}
return $this->buildedForm;

And you have methods for each type like (examples for Symfony 2):

private function constructInputField(FormField $field)
{
    $this->buildedForm->add(
        $field->getFieldName(),
        'text',
        [
            'label' => $field->getName(),
        ]
    );
}

private function constructTextareaField(FormField $field)
{
    $this->buildedForm->add(
        $field->getFieldName(),
        'textarea',
        [
            'label' => $field->getName(),
        ]
    );
}

You can now create your custom form type to paste a text in the generated form (it could be placed in the form folder of your bundle and retrieved with namespace "use"):

private function constructSimpletextField(FormField $field)
{
    $this->buildedForm->add(
        $field->getFieldName(),
        new SimpletextType(),
        [
            'label' => $field->getName(),
            'data' => $field->getPlaceholder(),
        ]
    );
}

What in this custom field?

namespace Myproject\MyBundle\Form\TaskTypes;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;

class SimpletextType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'disabled' => true,
            'required' => false,
            'mapped' => false,
        ]);
    }

    public function getParent()
    {
        return 'text';
    }

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

And the whole magic comes out in the template. For your custom form type you need to make a custom theme (see https://symfony.com/doc/2.7/form/form_customization.html#form-customization-form-themes). And there:

{% block simpletext_label %}{% endblock %}
{% block simpletext_widget %}
    <p>{{ form.vars.data }}</p>
{% endblock %}
{% block simpletext_errors %}{% endblock %}

See, no label, no errors (it just a text) and only text in the field widget. Very handy for generated forms with dynamic template.

EDIT - Symfony 5

In Symfony 5, this solution became simplier. The form customization doesn't changes, and the php code became like this:

namespace Myproject\MyBundle\Form\TaskTypes;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;

class SimpletextType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'disabled' => true,
            'required' => false,
            'mapped' => false,
        ]);
    }

    public function getBlockPrefix(): string
    {
        return 'simpletext';
    }
}

It's used like this :

public function buildForm(FormBuilderInterface $builder, array $options): void {
    /* … */
    $builder->add('anykey', SimpleTextType::class, [
        'data' => "Type your text here",
    ]);
    /* … */
}
like image 44
Vasiliy Toporov Avatar answered Feb 12 '23 04:02

Vasiliy Toporov