形成选择父母水合作用

I have a zf2 application that works with doctrine. I have the following entity:

class Role
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(type="string", length=255, unique=true, nullable=true)
     */
    protected $name;

    /**
     * @var ArrayCollection
     * @ORM\OneToMany(targetEntity="YrmUser\Entity\Role", mappedBy="parent")
     */
    protected $children;

    /**
     * @var Role
     * @ORM\ManyToOne(targetEntity="YrmUser\Entity\Role", inversedBy="children", cascade={"persist"})
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
     */
    protected $parent;
}

for this entity i have a form:

class RoleForm extends Form
{

    /**
     * [init description]
     * 
     * @return void
     */
    public function init()
    {

        $this->setHydrator(
            new DoctrineHydrator($this->objectManager, 'YrmUser\Entity\Role')
        )->setObject(new Role());

        $this->setAttribute('method', 'post');


        $this->add(
            array(
                'name' => 'name',
                'attributes' => array(
                    'type'  => 'text',
                    'placeholder' =>'Name',
                ),
                'options' => array(
                    'label' => 'Name',
                ),
            )
        );
        $this->add(
            array(
                'type' => 'DoctrineModule\Form\Element\ObjectSelect',
                'name' => 'parent',
                'attributes' => array(
                    'id' => 'parent_id',
                ),
                'options' => array(
                    'label' => 'Parent',
                    'object_manager' => $this->objectManager,
                    'property'       => 'name',
                    'is_method'      => true,
                    'empty_option' => '-- none --',
                    'target_class'   => 'YrmUser\Entity\Role',
                    'is_method'      => true,
                    'find_method'    => array(
                        'name'   => 'findBy',
                        'params' => array(
                            'criteria' => array('parent' => null),
                        ),
                    ),
                ),
            )
        );
    }
}

The hydration for the select in the form works as it only shows other roles that don't have a parent. But when editing a existing entity it shows itself in the select so i can select itself as its parent. I figured if i would have the id of current entity inside the form i can create a custom repo with a method that retrieves all roles without a parent and does not have the current entity id. But i cant figure out how to get the id of the currently edited entity from inside the form.

Any help is appreciated.

Cheers,

Yrm

You can fetch the bound entity within the form using $this->getObject().

You have actually already set this with setObject(new Role());. Unfortunately this means that it was not loaded via Doctine and you will have the same issue, no $id to work with.

Therefore you will need to add the 'parent role' options (value_options) after you have bound the role loaded via doctrine.

From within the controller, I normally request the 'edit' form from a service class and pass in the entity instance or id that is being edited. Once set you can then modify existing form elements before passing it back to the controller.

// Controller
class RoleController
{
   public function editAction()
   {
     $id      = $this->params('id'); // assumed id passed as param
     $service = $this->getRoleService();
     $form    = $service->getRoleEditForm($id); // Pass the id into the getter 

     // rest of the controller...
   }  
}  

By passing in the $id when you fetch the form you can then, within a service, modify the form elements for that specific role.

class RoleService implements ObjectManagerAwareInterface, ServiceLocatorAwareInterface
{
  protected function loadParentRolesWithoutThisRole(Role $role);

  public function getRoleEditForm($id)
  {
    $form = $this->getServiceLocator()->get('Role\Form\RoleEditForm');

    if ($id) {
      $role = $this->getObjectManager()->find('Role', $id);
      $form->bind($role); // calls $form->setObject() internally

      // Now the correct entity is attached to the form
      // Load the roles excluding the current
      $roles = $this->loadParentRolesWithoutThisRole($role);

      // Find the parent select element and set the options
      $form->get('parent')->setValueOptions($roles); 
    }

    // Pass form back to the controller
    return $form;
  }
}

By loading the options after the form has initialized you do not need the current DoctrineModule\Form\Element\ObjectSelect. A normal Select element that has no default value_options defined should be fine.