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 MProject
s (oneToMany) and Many MProject
s 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.
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.