When I reload an object from the session, I get an error "Maybe you forget to persist it in the entity manager?".
What can be done?
There are situations, when you want to store data in sessions. In general this works fine in Symfony. But once your data contains Doctrine-entities, your code will explode sooner or later.
Doctrine is proposing the MERGE-function (see: https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/cookbook/entities-in-session.html), but this function is marked as depreciated.
Here you will find a function to revitalize doctrine-data once loaded back from session to make your code work pretty and nice.
public function anyName() {
// ...
$data = $this->session->get('myData', $default_data);
$data = $this->sessionHelper->revitalizeEntityObjects($data);
// ...
}
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use ReflectionClass;
class SessionHelper
{
const DB_NAMESPACE_NAME = "App\Entity";
private $emi;
public function __construct(EntityManagerInterface $emi) {
$this->emi = $emi;
}
public function revitalizeEntityObjects(object $object)
{
$reflect = new ReflectionClass($object);
$props = $reflect->getProperties();
foreach ($props as $prop) {
$propName = $prop->getName();
$propName = ucfirst($propName); // capitalize first letter
$getter = "get{$propName}"; // name of the getter-function
$setter = "set{$propName}"; // name of the setter-function
// check if the property has a GETTER and SETTER (else go to next property)
if ( ! $reflect->hasMethod($getter) ) { continue; }
if ( ! $reflect->hasMethod($setter) ) { continue; }
// get the value of the property
$value = $object->$getter();
// check if the value is an object (else go to next property)
if ( ! is_object($value)) { continue; }
// check if the object has the expected namespace-prefix (else go to next property)
$subReflect = new ReflectionClass($value);
if ($subReflect->getNamespaceName() !== self::DB_NAMESPACE_NAME) { continue; }
// check if the ID-Field can be fetched by the standard 'getId'-function
if ( ! $subReflect->hasMethod('getId') ) { continue; }
// get the classname of the entity and the repository of that entity
$classname = $subReflect->getName();
$repository = $this->emi->getRepository($classname);
// re-fetch the object from the database
$reloadedObject = $repository->find($value->getId());
// check if something has been fetched (else do nothing and go to next property)
if ( ! $reloadedObject) { continue; }
// store the re-fetched object back into the main-object
$object->$setter($reloadedObject);
}
return $object;
}
}
Tim