How to make aliases for Symfony form fields

Imagine you want to rename form parameter but you also want it to accept old parameter name in requests to preserve backwards compatibility. Here's how you do it.

Step 1. Make tests for both cases

Symfony has a nice helper for testing forms. You should read about it in documentation.

Let's assume you want to accept parameter foo as parameter baz. You want both cases to be covered. Also you want predictable behavior in case both parameters are provided. Tests for these cases will look like this:

use Symfony\Component\Form\Test\TypeTestCase;

/**
 * @see MyType
 */
class MyTypeTest extends TypeTestCase
{
    public function testOldParameterName()
    {
        $model = new FooModel();
        $form = $this->factory->create(MyType::class, $model);

        $form->submit(['foo' => 'baz']);

        $this->assertEquals(
            'baz',
            $model->getBar(),
            '"foo" parameter must be accepted as "bar"'
        );
    }

    public function testNewParameterName()
    {
        $model = new FooModel();
        $form = $this->factory->create(MyType::class, $model);

        $form->submit(['bar' => 'baz']);

        $this->assertEquals(
            'baz',
            $model->getBar(),
            '"bar" parameter must be accepted'
        );
    }

    public function testBothParameterNames()
    {
        $model = new FooModel();
        $form = $this->factory->create(MyType::class, $model);

        $form->submit([
            'foo' => 'baz',
            'bar' => 'qux',
        ]);

        $this->assertEquals(
            'qux',
            $model->getBar(),
            '"bar" parameter must have priority over "foo"'
        );
    }
}

Run these tests. See them fail. Congratulations, you've done TDD. Now it's time to do work.

Step 2. Make aliases

There's no out-of-the box alias support in Symfony. If you check it's code, you'll see request parameters are tightly coupled with form field names. That's ok.

We can make an event listener that modifies request before passing to form. There we can convert old-style requests to new-style requests. To do this, add a block like this to your form code:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    // Convert old parameter names to new
    $builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
        $data = $event->getData();

        if (isset($data['foo']) && !isset($data['bar'])) {
            $data['bar'] = $data['foo'];
            unset($data['foo']);

            $event->setData($data);
        }
    });

    // ...
}

Step 3. Run tests again

See them green. Tadaa!

Nice job reading this, here's Nicholas Cage for you: Nicholas Cage beautiful as always. Now write something as comment.

Categories: Howtos

Tags: , ,