Buy

Using More Fields: email and repeated

We have just one password box, so lets turn this into 2 boxes by using the repeated field type. Let’s also change the email field to be an email type:

// src/Yoda/UserBundle/Controller/RegisterController.php

public function registerAction()
{
    $form = $this->createFormBuilder()
        ->add('username', 'text')
        ->add('email', 'email')
        ->add('password', 'repeated', array(
            'type' => 'password',
        ))
        ->getForm()
    ;

    // ..
}

The repeated field type is special because it actually renders two fields, in this case, password fields. If the two values don’t match, a validation error will show up. If you refresh, you’ll see the 2 fields. Oh no, attack of the clones!

The email field looks the same, but if you inspect it, you’ll see that it’s an input email field, an HTML5 field type that should be used:

<input type="email" ... />

Head over to Symfony’s documentation and go into the Reference Section. There, you’ll find a page called Form Field Type Reference. This is awesome: it shows you all of the built-in field types and the options you can pass to each. For example, if you click repeated, it shows you how to customize the error message that shows up if the fields don’t match and some other stuff. Use this section to your advantage!

The Repeated Fields and “Compound” fields

Now look back at our 2 password fields. This highlights a very special aspect about the way forms work. Specifically, a single field may in fact be one or many fields:

<div>
    <!-- -->
    <input type="password" id="form_password_first" name="form[password][first]" required="required" />
</div>

<div>
    <!-- -->
    <input type="password" id="form_password_second" name="form[password][second]" required="required" />
</div>

When you use the repeated field type, it creates two sub-fields called “first” and “second”. To see what I’m talking about, replace the form_row that renders the password field with two lines: one that renders the first box and one that renders the second:

{# src/Yoda/UserBundle/Resources/views/Register/register.html.twig #}
{# ... #}

{{ form_row(form.username) }}
{{ form_row(form.email) }}
{{ form_row(form.password.first) }}
{{ form_row(form.password.second) }}

{# ... #}

Note

When a field is actually several fields, it’s called a compound field.

When we refresh, we see exactly the same thing. I just wanted to highlight how password is really now two fields, and we can render them individually or both at once.

If this feels confusing, don’t worry! This concept is a little bit more advanced.

Customizing Field Labels

Since “first” and “second” are, well, terrible labels, let’s change them! One way to do this is by adding a second argument to form_row and passing a label key:

{# src/Yoda/UserBundle/Resources/views/Register/register.html.twig #}
{# ... #}

{{ form_row(form.password.first, {
    label: 'Password'
}) }}

{{ form_row(form.password.second, {
    label: 'Repeat Password'
}) }}

Refresh! Much better!

Leave a comment!

  • 2016-03-08 weaverryan

    We're working on that - the "Updated" feature is not useful yet! In this case, it was a very minor tweak of some non-important screencast metadata. That's something we're planning on making *much* more useful soon - I also want to see exactly *what* has been updated!

  • 2016-03-08 Shairyar Baig

    Hi Ryan,

    I am seeing "Updated 4 days ago" next to the tutorial heading, just out of curiosity how can i know what was updated?

    Regards,
    Baig

  • 2016-02-23 Shairyar Baig

    Thanks Ryan

  • 2016-02-22 weaverryan

    Hey :)

    Hmm, so this is not a problem I've had to solve personally - but it *is* a problem that others have, so it's good that you searched first for a bundle / existing solution. But, here's one potential direction:

    1) Somehow, your users create "new" fields in the admin panel. I'm assuming that this "field creation" is a *different* screen than where people actually fill out the forms (it's like a schema-creation tool, in a sense). Somehow, you save these to the database - with information about the field types, etc

    2) Create a new form class - e.g. DynamicFieldsType. Allow this type (in configureOptions) to have an option passed in - something like "fields", which would be an array of information about the fields that should be added. You'll be able to reference this "fields" option in buildForm(). You'll send this information in via the controller:


    $form = $this->createForm(DynamicFieldsType::class, null, ['fields' => $fieldsInfo]);

    3) In buildForm, use this "fields" option to completely, dynamically build your form. If you need validation, you'll need to add it via the "constraints" option for each field (since there is no entity behind this).

    4) Finally, you can use this form directly if you want (like I've shown above). OR, if these fields are part of a bigger form, you'll need to embed this form in your main form (e.g. MainAdminType). In that case, you'll also need to pass a fields option to the main type so that you can pass this option into the child type (DynamicFieldsType). Or, you could also inject the EntityManager into DyanmicFieldsType and register it as a service.

    I hope that somewhat gives you some ideas - at least from someone who has not actually had to solve this before :). There are probably even "cooler" solutions involving form events... but I don't see the point: just query the DB for the fields you need and dynamically build the form.

    Cheers!

  • 2016-02-22 Shairyar Baig

    Hi Ryan,

    I am hoping that you can push me in right direction.

    I am working on a product where on an form fields are hard coded in a formtype class just like any form on a website but now i need to allow user to create more fields using an admin panel. The admin panel is all taken care of but i am stuck at how to allow them to create more fields and make sure they appear on front end with the form.

    Cant seem to find any bundle either that does this.

    Baig