Avoiding Recursion with Doctrine Entities and Jmsserializer

Avoiding recursion with Doctrine entities and JMSserializer

Check the Serializer/Handler/DoctrineProxyHandler.php file on JMSSerializerBundle. Now, if you comment this line:

public function serialize(VisitorInterface $visitor, $data, $type, &$handled)
{
if (($data instanceof Proxy || $data instanceof ORMProxy) && (!$data->__isInitialized__ || get_class($data) === $type)) {
$handled = true;

if (!$data->__isInitialized__) {
//$data->__load();
}

It will stop lazy loading your entities. If this is what you're looking for, then just go ahead and create your own handler where you don't lazy load.

If this isn't correct, I recommend that you customize your entities before sending them to JMSSerializerBundle at your taste. For example, in any related entities I want the ID, while in others i need a custom column name like code, or name, or anything.

I just create a copy of my entity object and then start getting the fields I need for relationships. Then, I serialize that copy. JMSSerializerBundle won't lazy load because I already provided the proper fields.

How to handle recursive objects with JMS Serializer

Unfortunately, when deserializing, there is no way for the serializer to know whether the objects are identical or actually the same object. Even if you could nest them recursively.

But, you can get the desired result when combining the @Accessor annotation with some business logic. So going off of your example:

class Company {
/**
* @Accessor(setter="addEmployees")
*/
private $employees;

public function addEmployee(Employee $employee)
{
if (!$this->employees->contains($employee)) {
$this->employees[] = $employee;
$employee->setCompany($this);
}
}

public function addEmployees($employees)
{
foreach ($employees as $employee) {
$this->addEmployee($employee);
}
}
}

class Employee {
/**
* @Accessor(setter="setCompany")
*/
private $company;

public setCompany(Company $company = null)
{
$this->company = $company;

if ($company) {
$company->addEmployee($this);
}
}
}

I think this is a more natural approach than using @PostDeserialize as you probably already have some of these methods in your code. Also, it ensures the contract in both ways, so if you were to start from Employee you'd get the same result.

Disable Doctrine 2 lazy loading when using JMS Serializer?

After having looked for the answer in Doctrine, my team figured out that the JMS Serializer was the "problem".
It triggered the use of Doctrine Proxies automatically. We wrote a Patch for JMS Serializer to avoid the Lazy Loading.

We implemented our own DoctrineProxyHandler which just doesn't trigger Doctrines lazyloading mechanism and registered it within our SerializationHandlers Array.

class DoctrineProxyHandler implements SerializationHandlerInterface {

public function serialize(VisitorInterface $visitor, $data, $type, &$handled)
{
if (($data instanceof Proxy || $data instanceof ORMProxy) && (!$data->__isInitialized__ || get_class($data) === $type)) {
$handled = true;

if (!$data->__isInitialized__) {

//don't trigger doctrine lazy loading
//$data->__load();

return null;
}

$navigator = $visitor->getNavigator();
$navigator->detachObject($data);

// pass the parent class not to load the metadata for the proxy class
return $navigator->accept($data, get_parent_class($data), $visitor);
}

return null;
}

Now i can simply select my table, join the associations i need - and my JSON will contain just the data i selected instead of infinite depth associations and recursions :)

$qb= $this->_em->createQueryBuilder()
->from("\Project\Entity\Personappointment", 'pa')
->select('pa', 't', 'c', 'a')
->leftjoin('pa.table', 't')
->leftjoin('pa.company', 'c')
->leftjoin('pa.appointment', 'a')

JSON will just contain

{  
Personappointment: { table {fields}, company {fields}, appointment {fields}}
Personappointment: { table {fields}, company {fields}, appointment {fields}}
Personappointment: { table {fields}, company {fields}, appointment {fields}}
.
.
}

FOSRestBundle's serializer throws recursion error using inherited entities

Finally the API is working... I had to override the metadata of the classes I was inheriting adding the following lines to the config.yml

jms_serializer:
metadata:
directories:
HeztenCoreBundle:
namespace_prefix: "Hezten\\CoreBundle"
path: "%kernel.root_dir%/serializer/HeztenCoreBundle"

In the path that is selected above I added one yml file for each Model setting exclusion policy to ALL:

Hezten\CoreBundle\Model\Enroled:
exclusion_policy: ALL

And I used annotations on the entities that were inheriting those models to expose required info.

I don't know if this is the best approach but works well for me

Symfony2 Form why my form return warning: json_encode(): recursion detected?

Entities are prone to recursive issues, if you var_dump or print_r an entitiy, it will hang.

One of the best serialization tools that is capable of turning an entity into a hierarchal non-recursive tree is: https://github.com/schmittjoh/JMSSerializerBundle

It is used with FOSRestBundle as part of its transparent acceptable response handing.

You are having a similar issue to this: Avoiding recursion with Doctrine entities and JMSserializer

Check out the solution, and try using JMSSerializer.

Edit: Other likely cause:

When you return the array you are returning the form contained within that array.
Your event listener is trying to serialize this as json, this is both a cause of issues as well as being relatively pointless unless the form is being used to provide an augmented data template.

Either way, a form cannot be serialized so simply, did you even mean to do that?



Related Topics



Leave a reply



Submit