6

I have an entity which relates to itself. The entity has fields: parent and children.

class A
{
    // ...

    /**
     * @var A
     * @ORM\ManyToOne(targetEntity="A", inversedBy="children")
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
     */
    protected $parent;

    /**
     * @var A[]
     * @ORM\OneToMany(targetEntity="A", mappedBy="parent", cascade={"all"}, orphanRemoval=true)
     */
    protected $children;
}

I want to add children to this entity by setting up children in form. This entity type looks like this:

class AType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            // ...
            ->add('children', 'collection', [
                'type' => new AType(),
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false,
                'prototype' => true,
            ])
        ;
    }
}

When I send data like this:

'a' => [
    [
        'name' => 'main a',
        'children' => [
            [
                'name' => 'child a 1',
            ],
            [
                'name' => 'child a 2',
            ],
        ],
    ],
],

(in test, I don't have view, because this application is based on full REST Api communication) I got this error:

PHP Fatal error: Maximum function nesting level of '100' reached, aborting!

So, is it even possible to add children to self-related entities?

It would work if I have 2 entities: entity A with field children related to entity B. But, can it work with this relation?

Should I change type in AType class from new AType() to something different.

EDIT: Actually I just want to get data and validate it. I don't need HTML form to display it. I can do it like this:

// controller
$jms = $this->get('jms_serializer');
$entity = $jms->deserialize($request->getContent(), 'AcmeBundle\Entity\A', 'json');

$this->em->persist($entity);
$this->em->flush();

without using Form in controller. But in this case my data won't be validated.

Shawn Mehan
  • 4,513
  • 9
  • 31
  • 51
Kamil P
  • 782
  • 1
  • 12
  • 29
  • Are you trying to serialize your entity at some point? Self reference can cause that and you need to implement your own serialization rules. – stevenll Nov 16 '15 at 17:03
  • No. I just try to add this and that's it. My action in controller looks totally normal and returns empty response. – Kamil P Nov 16 '15 at 17:14
  • Try to [increase the xdebug value](http://stackoverflow.com/questions/4293775/increasing-nesting-functions-calls-limit/4293870#4293870): `xdebug.max_nesting_level = 200`. It should give you the real error. – A.L Nov 20 '15 at 13:20
  • That's not a solution. I will see this error even if I set nesting level to 2000. Probably I have to build my own field type. – Kamil P Nov 20 '15 at 14:12
  • @KamilP have you restarted apache after setting xdebug.max_nesting_level ? – Sergio Ivanuzzo Nov 26 '15 at 03:38
  • @Sergio Ivanuzzo, yes. But problem occur, because I load AType from AType - it's infinite loop. So I can set event 20000 xdebug.max_nesting_level and it still will appear. I'm looking for different solution. – Kamil P Nov 26 '15 at 11:07

2 Answers2

3

PHP Fatal error: Maximum function nesting level of '100' reached, aborting!

Because you have recursion. When you call createForm, it tries resolve type.

You can find this part of code in the FormFactory function resolveType.

I think you can create second form type which includes title and parent.

class AType extends AbstractType{
   //...
   public function buildForm(FormBuilderInterface $builder, array $options)
   {
    $builder
        ->add('title')
        ->add('parent')
        ->add('children', 'collection', array(
            'type' => new BType(),
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false,
            'prototype' => true
        ));
   }
}

class BType extends AbstractType {
    //..
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       $builder
         ->add('title')
         ->add('parent');
    }
 }

I think form builder can fetch and map Content-Type:application/x-www-form-urlencoded. I have implemented with html form. Also I have tried to send application/json but result is unsuccessful. That's why you can use json schema validators here.

Isabek Tashiev
  • 1,036
  • 1
  • 8
  • 14
  • I was thinking about that. But in this case I can't set up multilevel data. I can set only 2 levels. – Kamil P Nov 26 '15 at 10:53
0

I'd suggest you to have a look here: https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/tree.md#tree-entity-example

The structure id DB relies on other fields stored in DB as well apart from parentID.

It's model is based on this: https://en.wikipedia.org/wiki/Nested_set_model

  • I may do it, it's not a problem. But in this example they'r base on setting parent. I need to set children, and children of children. And also need to use it with form type. – Kamil P Nov 26 '15 at 11:04