Adam Lundrigan
Adam Lundrigan

Reputation: 598

Zend\Form\Element\Collection containing elements from a Doctrine Class Table inheritance?

I have a question about using Doctrine ORM's Class Table inheritance (CTI) with ZF2's Zend\Form. In our system each user can have multiple roles, and these roles are defined through a class-table inheritance scheme so that we can define role-specific profile fields (ie: "grade level" is only applicable to student accounts). To construct this, there is an Account entity with a OneToMany association to Account\Role (the CTI "base" class):

<?php
namespace CdliPortal\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="account")
 */
class Account implements AccountInterface
{
    // Other Fields Omitted

    /**
     * @ORM\OneToMany(targetEntity="CdliPortal\Entity\Account\Role", mappedBy="account", cascade={"ALL"})
     */
    protected $roles;
}

I've already set up a Zend\Form instance which binds an Account entity (I followed the example from the DoctrineModule documentation), and everything appears to be working A-OK...except for the CTI collection. In my Form object I add a Zend\Form\Element\Collection member:

$roles = $user->getRoles();
if ( count($roles) > 0 ) {
    $formAccount->add(array(
        'type' => 'Zend\Form\Element\Collection',
        'name' => 'roles',
        'options' => array(
            'count' => count($roles),
            'target_element' => $this->serviceLocator->get('cdliportal_form_account_role'),
        ),
    ));
}

However, as you can see above, when setting up the roles field the target_element (in this case a fieldset) is specified at the collection level, which means that the collection must be uniform. For my above-described case I would need to be able to specify the target_element individually for each element of the collection, depending on which member of the CTI it represents.

Any ideas / advice on how I could achieve this in a way that would still allow the elements of the collection to be automatically populated when I bind an Account object?

Upvotes: 2

Views: 909

Answers (1)

Adam Lundrigan
Adam Lundrigan

Reputation: 598

I've hacked my way into a solution which works for my use case: build a custom NonuniformCollection form element which is passed a collection of prototypes (one for each of the CTI entities) and clones the appropriate ones when the element is populated.

I've placed the code in a Gist here: https://gist.github.com/adamlundrigan/5195646

One caveat is that the template functionality no longer works as it doesn't know which prototype to use.

I'm still open to being shown a cleaner way to achieve this if anyone out there has any advice :)

Upvotes: 1

Related Questions