Search code examples
phpsymfonydoctrine-ormmappingentitymanager

Symfony - Undefined index of foreign property of a manyToOne relation


The case is a little bit intricate. I have a Controller action editCreateFirstFormPart which handles some fields of a Workflow object and renders an appropriate first part of a two parted form.

If I call the route of this action method with an id of a stored object the form will load all fields like it should. I store the object of the database, which fills the form, in the current session in case the user decides to cancel the editing in the second form:

// Persist all changes of made in the first form part
$manager->persist($workflow);
$manager->flush();

// In case the wolkflow already exists store it in the session
if(!$newWorkflow) $this->get('session')->set($workflowSessionName, $workflowBeforeSubmit);
return $this->redirectToRoute('pec_test_pra_edit_workflow_second_part', array(
    'project'               => $project->getId(),
    'workflow'              => $workflow->getId(),
    'newWorkflow'           => $newWorkflow,

    // Pass the name in the session of the stored workflow to the action method which handles the second form
    'workflowSessionName'   => $workflowSessionName,
));

This works like a charm. Now in case (which I retrieve) the user submits the second form via a cancel button I want to reset the object stored in database to the status BEFORE the first form part got submitted. Therefore I fetch the object stored in the session and want to persist it:

if($sessionObject instanceof Workflow) {
     $manager = $this->getObjectManager();
     $sessionObject = $session->get($workflowSessionName);
     $manager->persist($sessionObject);
     $manager->flush();
}

And here I get the following error:

Notice: Undefined index: 0000000061675b3d0000000022ddb0a6 in vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php (line 2917)
Line 2917: return $this->entityIdentifiers[spl_object_hash($entity)];

UnitOfWork->getEntityIdentifier(object(Fuel))// gets called after prepareUpdateData

BasicEntityPersister->prepareUpdateData(object(MProject))

My entity Workflow has an unidirectional manyToOne relation to a Project class. The MProject class extends Project and has one fuel property of class Fuel.

So one Fuel has many MProjects (oneToMany) and Many MProjects have one Fuel (manyToOne). Here are the according parts of the .orm.yml files:

Fuel.orm.yml:

  'ABundle\Entity\Fuel':
      ...
      oneToMany:
        projects:
          targetEntity: 'ABundle\Entity\MProject'
          mappedBy: fuel

Inside Fuel class:

class Fuel {

    /**
     * The collection of projects using the fuel.
     *
     * @var \Doctrine\Common\Collections\Collection
     */
     private $projects;

     ...

}

MProject.orm.yml:

'ABundle\Entity\MProject':
    repositoryClass: 'ABundle\Repository\MProjectRepository'
    type:  entity

    manyToOne:
      fuel:
        targetEntity: 'ABundle\Entity\Fuel'
        inversedBy: projects

Inside MProject class:

use BBundle\Entity\Project as BaseProject; // Origin of Project in my Entity

class MProject extends BaseProject implements SearchableTypeAlias {

    /**
     * The fuel used by the project.
     *
     * @var Fuel
     */
    protected $fuel;
    
    ...

}

Workflow.orm.yml:

MyBundle\Entity\Workflow:
  ...
  manyToOne:
    project:
      targetEntity: BBundle\Entity\Project
      cascade: [persist]
  ...

Inside Workflow class:

use BBundle\Entity\Project;

class Workflow  {

    /**
     * @var Project
     */
    private $project;

    ...

}

I don´t really know whats wrong in my usecase especially because there is no problem storing the $workflow object with calling persist in the first Controller action method.

How can I fix this Undefined index error?


Solution

  • Your problem is that you are trying to save entities detached from EntityManager. Workflow, Project entities get marked as NEW and get scheduled for insert instead of update. During exploration of the project->fuel association of session's Project the other Fuel entity with non-empty id value get found. But it is detached and id could not be found in EntityManager therefore the exception is raised.

    The entities that supposed to have a corresponding row in DB but loaded not by EntityManager (unserialized from session in your example) should be merged into EntityManager. You should merge all Workflow, Project, Fuel instances. The easiest way will be to configure the workflow->project and project->fuel associations for the cascade merge cascade: [merge] and to merge only the session Workflow.

    $manager = $this->getObjectManager();
    $sessionObject = $session->get($workflowSessionName);
    $manager->merge($sessionObject);
    $manager->flush();
    

    Note that this will automatically replace entities field values with the ones fetched from the session.