Back to Blog
Sep 15th, 2015

Symfony's Under-Used property_path option

Written by weaverryan

Edit
Symfony's Under-Used property_path option

Though not required, we typically, bind Symfony form objects to a class (often an entity). This means that the field names must correspond with the property names on the class (well actually, the getter/setter methods, via the PropertyAccess component):

// ...

class ProductFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', 'text')
            ->add('price', 'number');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('data_class', 'AppBundle\Model\Product');
    }

    // ...
}

Since this has name and price fields, the Product class must also have the methods getName(), setName(), getPrice() and setPrice():

// ...

class Product
{
    private $name;
    private $price;

    public function getName()
    {
        return $this->name;
    }
    public function setName($name)
    {
        $this->name = $name;
    }
    public function getPrice()
    {
        return $this->price;
    }
    public function setPrice($price)
    {
        $this->price = $price;
    }
}

The Magic: property_path Option

But the mapping doesn't actually use the field's name (e.g. price) to find the getters/setters. In the background, each field has a property_path option, which defaults to the field name. This means that the field names could be something entirely different than the property name, as long as the property_path is set:

// ProductFormType.php
// ...

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('productName', 'text', [
            'property_path' => 'name'
        ])
        ->add('mainPrice', 'number', [
            'property_path' => 'price'
        ]);
}

When would this be useful? Suppose the Product object has a related Category object:

class Product
{
    // ...

    /**
     * @var Category
     */
    private $category;

    public function getCategory()
    {
        return $this->category;
    }
    public function setCategory(Category $category)
    {
        $this->category = $category;
    }
}

What if you want the user to be able to edit the category's title property, right inside the Product form? That can be done by using embedded forms. Or, you can leverage property_path:

// ProductFormType.php
// ...

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('name', 'text')
        ->add('price', 'number')
        ->add('categoryTitle', 'text', [
            'property_path' => 'category.title'
        ]);
}

The key is category.title, which leverages the PropertyAccess component and means that $product->getCategory()->getTitle() and $product->getCategory()->setTitle() are called in the background when the form is loaded and saved.

Now, note that this won't change the Category from one to another: you're actually modifying the title of the same object. You also need to make sure that the Product has a Category, or else the PropertyAccess component can't call down the path. But, depending on your situation, this might be the perfect (and simplest) solution.

Cheers!

8 Comments

Sort By
Login or Register to join the conversation
Default user avatar Bruno Lima 5 years ago

Great! Thank you.

I found it great when I needed to change a relationship field name (relationship id), like so:

```
->add(
____'customer',
____EntityType::class, // Don't forget
____[
________'class' => CustomerEnterprise::class, // This is an M-N relationship I need to refer while booking an appointment
________'property_path' => 'customerEnterprise', // I think this is not cool for an API. The enterprise only sees its customers, while a customer can be in several enterprises
____]
)
```

Great tip. Thank you

| Reply |
Default user avatar SimpleWeek 5 years ago

Very simple and nice solution, thanks :) Didn't know that related entities could be used with `property_path`

| Reply |
Default user avatar Neandher Carlos 5 years ago

Coooool! I will try now, thanks! ^^

| Reply |

Very informative! Many thanks!! ;)

| Reply |
Default user avatar Giorgio Premi 5 years ago

Always a good reminder, thanks!
I always try hard not to couple model class to forms, and so I create intermediate class named 'UpdateEntity' and 'CreateEntity'. By using `property_path` one can easily map simple `entity.property` getter/setter, without loosing the ability to add form-only field.

| Reply |

Nice tip with using this with intermediate classes!

| Reply |
Default user avatar Michaƫl Perrin 5 years ago

I never thought to use the property_path option this way and would have used an embedded form instead!
Thanks for the tip!

| Reply |
Default user avatar Shady 5 years ago

Good to know, thanks :)

| Reply |

Delete comment?

Share this comment

astronaut with balloons in space

"Houston: no signs of life"
Start the conversation!