Home > Software design >  How to use DB default when persist entity in Doctrine?
How to use DB default when persist entity in Doctrine?

Time:08-27

I have entity class with many fields like so:

/** @ORM\Entity() */
class Address
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    private int $id;

    /** @ORM\Column(type="datetime", name="add_time") */
    private DateTime $createdAt;

    /** @ORM\Column(type="text", name="full_address") */
    private string $fullAddress;

    /** @ORM\Column(type="string") */
    private string $street;

    // other fields
}

This entity has about 20 fields. Almost all of them are defined as varchar(100) default '' not null in the database.

Now I'm going to do a partial update. So I send just a single field (or sometimes a subset of fields) instead of entire form. Some fields may have an empty value (empty string).

As I understand, I can not use $form->handleRequest to populate my entity, so I use

$form->submit($request->request->all(), false);

But in this case all fields with empty string value are not set into the entity. And Doctrine generates INSERT statement with full list of fields and pass null values into placeholders, and that causes Integrity constraint violation: 1048 Column 'street' cannot be null

I tried some solutions, but no one worked for me:

  1. Set field default value:
/** @ORM\Column(type="string") */
private string $street = '';

It produces Uncaught TypeError: Argument 1 passed to Entity\Address::setStreet() must be of the type string, null given on $form->submit.

  1. Set default in the constructor:
public function __construct()
{
    $this->street = '';
}

Exactly the same as the 1st one.

  1. Add Doctrine default option:
/** @ORM\Column(type="string", options={"defalt": ""}) */
private string $street = '';

No changes at all because BasicEntityPersister::getInsertColumnList doen't use this information.

  1. After 3rd I tried to implement my own EntityPersister, but it looks like there is no way to do that. Doctrine doesn't allow to change it.

I probbly missed something very symple and stupid.

Is there a way to exclude fields with default values from INSERT statement?

CodePudding user response:

When you submit data from the form to the entity, TextType field with empty string value '' is transformed to the null and set by setStreet() method. For more information see the documentation https://symfony.com/doc/current/reference/forms/types/text.html#empty-data, especially the text in the red box. Empty string value to the null transformation is executed by method TextType::reverseTransform.

There are 2 variants to resolve it:

1 - modify setter

public function setStreet(?string $street): self
{
    $this->street = (string) $street;

     return $this;
}

2 - add a custom view transformer for the TextType fied in the form builder or create a new form type with custom view transformer

public function buildForm(FormBuilderInterface $builder, array $options)
{
    .....

    $builder->get('street')->addViewTransformer(new NullToEmptyStringTransformer());
}


class NullToEmptyStringTransformer implements DataTransformerInterface
{
    public function transform(mixed $value): mixed
    {
        return $value;
    }

    public function reverseTransform(mixed $value): string
    {
        return (string) $value;
    }
}
  • Related