php - Symfony 5 - Using DataTransformer on Entity with another column than primary key
Get the solution ↓↓↓Following this doc https://symfony.com/doc/current/form/data_transformers.html#harder-example-transforming-an-issue-number-into-an-issue-entity, we learn how to fill a field (which is an Entity) without using a choice field type or similar.
It seems to work, using the primary key of the Entity concerned (el famoso "id").
However, i want to use another field and store it in a table, but i have an error (see screeshot at bottom)
Entities :
<?php
namespace App\Entity;
use App\Repository\LandRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=LandRepository::class)
* @ORM\Table(name="land",indexes={@ORM\Index(columns={"uid"})})
* @ORM\HasLifecycleCallbacks()
*/
class Land
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $libelle;
/**
* @ORM\Column(type="integer")
*/
private $uid;
public function getId(): ?int
{
return $this->id;
}
public function getLibelle(): ?string
{
return $this->libelle;
}
public function setLibelle(string $libelle): self
{
$this->libelle = $libelle;
return $this;
}
public function getUid(): ?int
{
return $this->uid;
}
public function setUid(int $uid): self
{
$this->uid = $uid;
return $this;
}
}
namespace App\Entity;
use App\Repository\RideRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=RideRepository::class)
* @ORM\HasLifecycleCallbacks()
*/
class Ride
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $libelle;
/**
* @ORM\ManyToOne(targetEntity=Land::class)
* @ORM\JoinColumn(name="areaparent", referencedColumnName="uid")
*/
private $areaparent;
public function getId(): ?int
{
return $this->id;
}
public function getLibelle(): ?string
{
return $this->libelle;
}
public function setLibelle(string $libelle): self
{
$this->libelle = $libelle;
return $this;
}
public function getAreaparent(): ?Land
{
return $this->areaparent;
}
public function setAreaparent(?Land $areaparent): self
{
$this->areaparent = $areaparent;
return $this;
}
}
Expected final result :
"Land" table
"Ride" table
So you can see that in the "ride" table that the "areaparent" column is relative to the "land.uid" column.
"Land" form is classic
"Ride" form have a minor change : The "areaparent" is not a choice field, it's a text type which will call my DataTransformer
Extract of my form "RideType"
<?php
namespace App\Form;
use App\Entity\Ride;
use App\Entity\Land;
use Symfony\Component\Form\AbstractType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use App\Repository\LandRepository;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use App\Form\DataTransformer\UIDTransformer;
class RideType extends AbstractType
{
private $transformer;
public function __construct(UIDTransformer $transformer)
{
$this->transformer = $transformer;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('libelle')
->add('areaparent', TextType::class, [
'invalid_message' => 'That is not a valid areaparent number',
])
;
$builder->get('areaparent')->addModelTransformer($this->transformer);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Ride::class,
]);
}
}
Extract of my DataTransformer :
<?php
namespace App\Form\DataTransformer;
use App\Entity\Land;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class UIDTransformer implements DataTransformerInterface
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* Transforms an object (Land) to a string (areaparent).
*
* @param Land|null $Land
* @return string
*/
public function transform($land)
{
if (null === $land) {
return '';
}
return $land->getUid();
}
/**
* Transforms a string (police) to an object (Land).
*
* @param string $areaparent
* @return Land|null
* @throws TransformationFailedException if object (Land) is not found.
*/
public function reverseTransform($areaparent)
{
// no areaparent? It's optional, so that's ok
if (!$areaparent) {
return;
}
$land = $this->entityManager->getRepository(Land::class)->findByUid($areaparent);
if (count($land) == 0) {
// causes a validation error
// this message is not shown to the user
// see the invalid_message option
throw new TransformationFailedException(sprintf('Land with areaparent "%s" does not exist!',$areaparent));
}
return $land[0];
}
}
I try to debug the symfony/doctrine code, and if i correctly understand, the error appears because the field "uid" is not considered as an "identifier".
See some dump.
Have you got some ideas ?
Thanks !
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: an exception occurred in the driver: could not find driver
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.