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
PHP "Pretty Print" JSON_Encode
How to Convert Between 12 Hour Time and 24 Hour Time in PHP
Is There a Function to Make a Copy of a PHP Array to Another
How to Go to the Same Page After Login in PHP
Combining and Compressing Multiple JavaScript Files in PHP
Merge 2 Arrays and Sum the Values (Numeric Keys)
How to Set an Absolute Include Path in PHP
Check to See If an Email Is Already in the Database Using Prepared Statements
Avoid Add to Cart for Specific Product Categories If User Is Unlogged in Woocommerce
Differencebetween Is_A and Instanceof
File Not Found When Running PHP with Nginx
Zf2 + Doctrine 2 - Child-Level Discriminators with Class Table Inheritance
PHP - Get the Size of a Directory