Skip to content

Instantly share code, notes, and snippets.

@boekkooi
Last active December 23, 2020 02:49
Show Gist options
  • Save boekkooi/5600b3d43f694f26855d to your computer and use it in GitHub Desktop.
Save boekkooi/5600b3d43f694f26855d to your computer and use it in GitHub Desktop.
Using a custom property path for symfony forms set / get path

Sometimes you have a small little class like Rate.php and want to use it with a symfony form like:

$builder
    ->add('cost', MoneyType::class, [
        'currency' => 'EUR',
        'label' => 'Cost',
        'divisor' => 100,
    ]);

But S*** symfony forms expects a set<name> method. Let's change this behaviour by using a custom property accessor and overriding the path.

$builder
    ->setDataMapper(new PropertyPathMapper(
        new CustomPropertyAccessor([ 'cost' => 'changeCost' ])
    ));

All done.

<?php
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyAccess\PropertyPath;
/**
* A property accessor that allows you to rewrite a property path for setters and getters.
*/
class CustomPropertyAccessor extends PropertyAccessor
{
/**
* @var array
*/
private $customSets;
/**
* @var array
*/
private $customGets;
/**
* @inheritDoc
*/
public function __construct(array $propertySets = [], array $propertyGets = [], $magicCall = false, $throwExceptionOnInvalidIndex = false)
{
parent::__construct($magicCall, $throwExceptionOnInvalidIndex);
$this->customSets = $propertySets;
$this->customGets = $propertyGets;
}
/**
* @inheritDoc
*/
public function getValue($objectOrArray, $propertyPath)
{
if (isset($this->customGets[(string)$propertyPath])) {
$propertyPath = new PropertyPath($this->customGets[(string)$propertyPath]);
}
return parent::getValue($objectOrArray, $propertyPath);
}
/**
* @inheritDoc
*/
public function setValue(&$objectOrArray, $propertyPath, $value)
{
if (isset($this->customSets[(string)$propertyPath])) {
$propertyPath = new PropertyPath($this->customSets[(string)$propertyPath]);
}
parent::setValue($objectOrArray, $propertyPath, $value);
}
}
<?php
class FaxRate
{
/**
* @var int
*/
protected $cost;
/**
* @return int
*/
public function getCost()
{
return $this->cost;
}
/**
* @param int $cost
*/
public function changeCost($cost)
{
$this->cost = $cost;
}
}
@ostrolucky
Copy link

ostrolucky commented Dec 10, 2017

This gist comes up often for me in google search. So for all of you who come here searching how to change property path, you don't need to use this way. You can do this via... property_path option.

$builder
    ->add('cost', MoneyType::class, [
        'currency' => 'EUR',
        'label' => 'Cost',
        'divisor' => 100,
        'property_path' => 'changeCost',
    ]);

@BonBonSlick
Copy link

@ostrolucky 'property_path' is not for this

@andrepintado
Copy link

Dude, this was life saver. Thanks a lot.

@freedmo
Copy link

freedmo commented Aug 29, 2019

@ostrolucky 'property_path' is not for this

Why not?

@reneroboter
Copy link

I guess the following part from the official documentation is also helpful for this topic.
https://symfony.com/doc/4.4/form/data_mappers.html

@lebrunthibault
Copy link

DataMappers are certainly more powerful but property path totally works for a simple use case ! thansk @ostrolucky

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment