Meta data missing when using DiscriminatorMap #6420

Open
opened 2026-01-22 15:32:54 +01:00 by admin · 0 comments
Owner

Originally created by @pmishev on GitHub (Mar 3, 2020).

Bug Report

Q A
BC Break yes (with php7.3 vs 7.1)
Version v2.7.1

Summary

When using a DiscriminatorMap, is seems metadata in entity manager is not being loaded for entities.

Current behavior

How to reproduce

I have different types of notes using a single table using DiscriminatorMap:

/**
 * @ORM\Entity
 * @ORM\Table(name="journalist_internal_notes")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="note_type", type="string")
 * @ORM\DiscriminatorMap({
 *     "journalist-internal-note" = "JournalistInternalNote",
 *     "journalist-policy" = "JournalistPolicy",
 * })
 */
class JournalistInternalNote
/**
 * JournalistPolicy
 *
 * @ORM\Entity(repositoryClass="App\Repository\JournalistPolicyRepository")
 * @ORM\HasLifecycleCallbacks
 */
class JournalistPolicy extends JournalistInternalNote

Then there's a link entity:

/**
 * NoteJournalistLink
 *
 * @ORM\Table(
 *     name="journalist_internal_note_journalist_links",
 *     uniqueConstraints={@ORM\UniqueConstraint(name="uq_journalist_internal_note_id__journalist_id", columns={"journalist_internal_note_id","journalist_id"})}
 * )
 * @ORM\Entity
 *
 * @UniqueEntity(
 *  fields={"journalistInternalNote", "journalist"},
 *  message="The journalist is already assigned to this note."
 * )
 */
class NoteJournalistLink
{
    /**
     * @var JournalistInternalNote
     *
     * @ORM\ManyToOne(targetEntity="JournalistInternalNote", inversedBy="noteJournalistLinks")
     * @ORM\JoinColumn(name="journalist_internal_note_id", referencedColumnName="id", nullable=false)
     *
     */
    private $journalistInternalNote;

    /**
     * @var Journalist
     *
     * @ORM\ManyToOne(targetEntity="Journalist", inversedBy="noteJournalistLinks")
     * @ORM\JoinColumn(name="journalist_id", referencedColumnName="id", nullable=false)
     *
     * @Assert\NotBlank(message="The value for the journalist field should not be blank")
     */
    private $journalist;
    
   ...
}

And I have a basic CRUD for creating a new "JournalistPolicy":

class JournalistInternalNoteController {
    ...
    public function addPolicyAction(Request $request, Journalist $journalist, EntityManagerInterface $em)
    {
        $note = new JournalistPolicy();

        $form = $this->createForm(JournalistPolicyType::class, $note);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em->persist($note);
            $em->flush();

            return $this->redirect($successUrl);
        }

        return $this->render('journalist/journalist_internal_notes/edit.html.twig', [
           'journalist' => $journalist,
           'form' => $form->createView(),
        ]);
    }
}

Inside the JournalistPolicyType::buildForm() :

        $builder->add('noteJournalistLinks', CollectionType::class, [
            'entry_type' => NoteJournalistLinkType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false,
            'prototype' => true,
            'label' => false,
        ]);

Submitting that form in PHP 7.3 gives an error:

An exception occurred while executing 'SELECT blabla FROM journalist_internal_note_journalist_links t0 WHERE t0.journalist_internal_note_id = ? AND t0.journalist_id = ?' with params [{}, 67361]:

Notice: Object of class App\Entity\JournalistPolicy could not be converted to int

This happens because when the UniqueEntityValidator in symfony-bridge tries to validate the entity, it tries to build a select query for the selected journalist and a note that does not yet have an id.
In this line: https://github.com/doctrine/orm/blob/2.7/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L1943, it basically converts the entity to a null when it has the metadata for it.
When there is no metadata for the entity at that point, the entity object is bound to the PDO query as it is.
So, when PDO::execute() is called, it tries to convert an object to an integer, which throws an expected exception.
In php7.1, this problem went unnoticed, because PDO works differently there - apparently the object was first being converted to string and then to int, so given that there was a __toString() method, the result was null, which was just fine.

I am posting this issue here, because to me the main problem lies in the fact that the metadata for the JournalistPolicy object is missing in the entity manager and it doesn't even tries to retrieve it.
I suspect it is missing because of using a DiscriminatorMap, however I can't figure out how and when metadata is being populated, in order to suggest a fix

Expected behavior

The metadata for JournalistPolicy to exist in the entity manager, so the code enters tha if: https://github.com/doctrine/orm/blob/2.7/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L1943 and the object is transformed to a null

Originally created by @pmishev on GitHub (Mar 3, 2020). ### Bug Report <!-- Fill in the relevant information below to help triage your issue. --> | Q | A |------------ | ------ | BC Break | yes (with php7.3 vs 7.1) | Version | v2.7.1 #### Summary When using a DiscriminatorMap, is seems metadata in entity manager is not being loaded for entities. #### Current behavior <!-- What is the current (buggy) behavior? --> #### How to reproduce I have different types of notes using a single table using DiscriminatorMap: ``` /** * @ORM\Entity * @ORM\Table(name="journalist_internal_notes") * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="note_type", type="string") * @ORM\DiscriminatorMap({ * "journalist-internal-note" = "JournalistInternalNote", * "journalist-policy" = "JournalistPolicy", * }) */ class JournalistInternalNote ``` ``` /** * JournalistPolicy * * @ORM\Entity(repositoryClass="App\Repository\JournalistPolicyRepository") * @ORM\HasLifecycleCallbacks */ class JournalistPolicy extends JournalistInternalNote ``` Then there's a link entity: ``` /** * NoteJournalistLink * * @ORM\Table( * name="journalist_internal_note_journalist_links", * uniqueConstraints={@ORM\UniqueConstraint(name="uq_journalist_internal_note_id__journalist_id", columns={"journalist_internal_note_id","journalist_id"})} * ) * @ORM\Entity * * @UniqueEntity( * fields={"journalistInternalNote", "journalist"}, * message="The journalist is already assigned to this note." * ) */ class NoteJournalistLink { /** * @var JournalistInternalNote * * @ORM\ManyToOne(targetEntity="JournalistInternalNote", inversedBy="noteJournalistLinks") * @ORM\JoinColumn(name="journalist_internal_note_id", referencedColumnName="id", nullable=false) * */ private $journalistInternalNote; /** * @var Journalist * * @ORM\ManyToOne(targetEntity="Journalist", inversedBy="noteJournalistLinks") * @ORM\JoinColumn(name="journalist_id", referencedColumnName="id", nullable=false) * * @Assert\NotBlank(message="The value for the journalist field should not be blank") */ private $journalist; ... } ``` And I have a basic CRUD for creating a new "JournalistPolicy": ``` class JournalistInternalNoteController { ... public function addPolicyAction(Request $request, Journalist $journalist, EntityManagerInterface $em) { $note = new JournalistPolicy(); $form = $this->createForm(JournalistPolicyType::class, $note); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $em->persist($note); $em->flush(); return $this->redirect($successUrl); } return $this->render('journalist/journalist_internal_notes/edit.html.twig', [ 'journalist' => $journalist, 'form' => $form->createView(), ]); } } ``` Inside the JournalistPolicyType::buildForm() : ``` $builder->add('noteJournalistLinks', CollectionType::class, [ 'entry_type' => NoteJournalistLinkType::class, 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, 'prototype' => true, 'label' => false, ]); ``` Submitting that form in PHP 7.3 gives an error: ``` An exception occurred while executing 'SELECT blabla FROM journalist_internal_note_journalist_links t0 WHERE t0.journalist_internal_note_id = ? AND t0.journalist_id = ?' with params [{}, 67361]: Notice: Object of class App\Entity\JournalistPolicy could not be converted to int ``` This happens because when the `UniqueEntityValidator` in `symfony-bridge` tries to validate the entity, it tries to build a select query for the selected journalist and a note that does not yet have an id. In this line: https://github.com/doctrine/orm/blob/2.7/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L1943, it basically converts the entity to a `null` when it has the metadata for it. When there is no metadata for the entity at that point, the entity object is bound to the PDO query as it is. So, when PDO::execute() is called, it tries to convert an object to an integer, which throws an expected exception. In php7.1, this problem went unnoticed, because PDO works differently there - apparently the object was first being converted to string and then to int, so given that there was a __toString() method, the result was `null`, which was just fine. I am posting this issue here, because to me the main problem lies in the fact that the metadata for the JournalistPolicy object is missing in the entity manager and it doesn't even tries to retrieve it. I suspect it is missing because of using a DiscriminatorMap, however I can't figure out how and when metadata is being populated, in order to suggest a fix #### Expected behavior The metadata for JournalistPolicy to exist in the entity manager, so the code enters tha `if`: https://github.com/doctrine/orm/blob/2.7/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L1943 and the object is transformed to a `null`
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6420