Symfony - Circular reference error in ManyToOne relationships - symfony

I am using Symfony 5 and doctrine. I have two entities with ManyToOne relationships (Product and ProductImage). Each product can have multiple images and the product entity has getProductImages() method to fetch its product images.
But when I use this method in controller response like this:
return $this->json($product->getProductImages());
I get the following error:
A circular reference has been detected when serializing the object of class "App\Entity\Product"
Do you have any idea how can I solve it?

$this->json() uses a serializer to convert the ProductImage into json. When the serializer tries to serialize the ProductImage it finds the reference to its Product and tries to serialize that too. Then when it serializes the Product it finds the reference back to the ProductImage, which causes the error.
If you do not need the Product information in your json, the solution is to define a serialization group and skip the serialization of the Product property that is causing the error.
Add a use statement to your ProductImage class:
use Symfony\Component\Serializer\Annotation\Groups;
Add a group to the properties you want to serialize, but skip the Product property:
/**
* #Groups("main")
*/
private $id;
/**
* #Groups("main")
*/
private $filename;
And in your controller specify the group to use in $this->json():
return $this->json(
$product->getProductImages(),
200,
[],
[
'groups' => ['main']
]
);

Related

How to use Association field in Symfony EasyAdmin 4

When I use:
public function configureFields(string $pageName): iterable
{
return [
AssociationField::new('XYZ')
];
}`
I get error "Object of class App\Entity\XYZ could not be converted to string"
When I add ->autocomplete() to the AssociationField::new('XYZ'), then it works, but on save it displays error "Expected argument of type "?string", "App\Entity\XYZ" given at property path "XYZ".
Whats the CORRECT way to use this field with many to one relation? Symfony Easy Admin documentation https://symfony.com/doc/current/EasyAdminBundle/fields/AssociationField.html doesn't help at all.
Your entity App\Entity\XYZ will be converted to a string in your association field (which is a standard symfony entity type). Otherwise there is no way to set a label in your entity select.
It will try to convert it using the __toString method, so you need to add it in your entity.
For example:
/**
* #ORM\Entity(repositoryClass=XyzRepository::class)
*/
class Xyz
{
public function __toString(){
return $this->name; //or anything else
}
EasyAdmin should be able to guess the entity class, so you don't have to specify it like you would for a simple EntityType.

Symfony 2 - could not able to insert json_array type variable

json_array type variable is not able to include to the database. The populated exception is as follow
(Symfony\Component\Debug\Exception\ContextErrorException(code: 0): Warning: implode(): Invalid arguments passed at /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SimpleArrayType.php:51)"}
My entity class has this part for json_array type paramter.
/**
*
* #ORM\Column(name="street", type="json_array")
*/
private $street;
also I include to the db using entity manager.
$entityName->setStreet(
array(
'street_1' => $queueItem->street_1,
'street_2' => $queueItem->street_2));
if($this->em->getUnitOfWork()->getEntityState($entityName)) {
$this->em->flush();
}
I think you should use type="text" or a own entity for multiple streets
http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html#text
Because:
type="json_array" is deprecated use type="json" http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html#json-array
this type want a string that could be encoded, not an array

Set up non-persistent relation in Doctrine 2

I have an object $user that has a one to many relation with $establishment. I can use:
$user->getEstablishments();
The user can select a stablishment to work on. I have this method that I call in the controller:
$user->setCurrentEstablishment($establishment);
And this one that I call in the view:
$establishment = $user->getCurrentEstablishment();
I want to be able to call:
$user->setCurrentEstablishmentBy Slug($establishment_slug);
where the slug is a string, and let the user object look for the establishment.
Doctrine discourages the practice of accessing the Entity Manager inside the Entity object, but I think that using it in the controller is even worse.
I suspect that some special Doctrine annotation exists that takes care of non persistent relations like this, or some method other than serving the Entity Manager through a service should be used here. Some easy way of referencing other entities from inside the model.
¿Is there any? ¿How could I do that?
There is no Annotation in Doctrine which could convert slug into object.
What can help You is ParamConverter, with it you can automatically convert slug from query into object. But it still must be used in Controller.
Example usage:
/**
* #Route("/some-route/{slug}")
* #ParamConverter("object", class="AppBundle:Establishment", options={"id" = "slug", "repository_method" = "findEstablishmentBySlug"})
*/
public function slugAction(Establishment $object)
{
...
Docs about param converter: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

Getting multiple rows using ParamConverter

Hi Im trying to use ParamConverter to get multiple rows from DB but profiler show query with limi 1. Is it possible to get it like that
/**
* #Route("/localization/{code}", name="pkt-index")
* #ParamConverter("localizations", class="PriceBundle:Localization")
*/
after entering localization/0003 I should get more than 100 rows.
EDIT:
I have used repository_method option
and
/*
* #Route("/localization/{id}", name="pkt-index")
* #ParamConverter("localizations", class="PriceBundle:Localization", options={
* "repository_method": "getByLocalizationCode"
* })
*/
but funny thing is that when I change {id} in route it does not work it throws and exception
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
even if variable exists in entity class, if variable dont exist it throws
Unable to guess how to get a Doctrine instance from the request information.
EXPLANATION
when I change {id} in route it does not work it throws and exception
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
Here I think symfony treads id like primary key and as parameter to repository method it pass string when I changed this id to something else it pass array
Example
/**
* #Route("/localization/{id}", name="pkt-index")
*/
pass string to method
/**
* #Route("/localization/{code}/{name}", name="pkt-index")
*/
pass array to method
array(
'code' => 003
'name' => localization_name
)
and last
/**
* #Route("/localization/{id}/{name}", name="pkt-index")
*/
will pass string id omit the name
Hope this sounds reasonable.
forgottenbas's answer isn't completely right. #ParamConverter will first try to find one entity by id ...
... then try to match the route variables against db columns to find an entity ...
but essentially it will only convert one entity at a time.
If you would still like to use a paramconverter you would need to write a custom one.
or just use a one-liner inside your controller action:
/**
* #Route("/localization/{code}", name="pkt-index")
*/
public function yourAction($code)
{
$localizations = $this->getDoctrine()->getRepository("YourBundle:Localization")->findBy(array("code" => $code));
// ...
ParamConverter currently can only extract id from request and find one entity from db. Look at
DoctrineParamConverter code. But you can specify your own param converter with some extra logic.

how to implement this symfony form, with a entity which has a array of entities?

i have a big problem with a symfony form. i need to do the following:
I want to generate a form for a entity, but this entity has a array of other entities which should be also added (if possible).
here is the data structure:
I hava a Entity called Foo (keeps a array of FooItems) and the a entity FooItems.
class Foo
{
{...}
/**
* #var string
* #ORM\Column(type="string")
*/
private $fooItems;
{...}
now i need to build a form for this, the user can add one or more FooItems to the Foo. How to realise this?
From Symfony's cookbook:
How to Embed a Collection of Forms
http://symfony.com/doc/current/cookbook/form/form_collections.html
If you want to store multiple form fields into a single string in the database instead of an one-to-many relation, you can also implement an DataTransformerInterface to convert the fields to a string and back.
Taka a look a DateTimeToStringTransformer which does it for the DateType form element

Resources