Personalizar un formulario con Symfony 2.8

Empiezo explicando como tengo configurado mi aplicación:

Yo tengo 2 entidades, una de ellas es Persona (Person) y otra es Usuario (User). No todas las personas tienen un usuario asociada pero todos los usuarios tienen una persona asociada. Las personas solo pueden tener un usuario. El módulo de usuario lo resolví con FOSUserBundle.

Las entidades están configuradas de la siguiente forma:

Entity Person

/**
 * Person
 *
 * @ORM\Table(name="MSG_PersonPerson")
 * @ORM\Entity(repositoryClass="MSG\PersonBundle\Entity\PersonRepository")
 * @ORM\HasLifecycleCallbacks()
 * @Gedmo\SoftDeleteable(fieldName="deleted_at", timeAware=false)
 * @UniqueEntity(fields={"dni", "nationality"})
 * 
 */
class Person extends EntityPattern {
 
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
 
   ...
 
    /**
     *
     * RELACIÓN IMPORTANTE - RELACIONADO CON LA ENTIDAD USER!
     *
     * @ORM\OneToOne(targetEntity="User", mappedBy="person", cascade={"persist"})
     * ORM\JoinColumn(name="user_id", referencedColumnName="id")
     * ORM\OneToOne(targetEntity="User", mappedBy="person", cascade={"persist", "remove"})
     */
    private $user;
 
    ...

Entity User

/**
 * User
 *
 * @ORM\Table(name="MSG_PersonUser")
 * @ORM\Entity(repositoryClass="MSG\PersonBundle\Entity\UserRepository")
 * @ORM\HasLifecycleCallbacks()
 * @Gedmo\SoftDeleteable(fieldName="deleted_at", timeAware=false)
 * @UniqueEntity("person")
 * 
 * Los valida el FOSUserBundle
 * UniqueEntity("email")
 * UniqueEntity("username")
 */
class User extends BaseUser {    
 
    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
 
    ...
 
    /**
     *
     * RELACIÓN IMPORTANTE - RELACIONADO CON LA ENTIDAD PERSON!
     *
     * @ORM\OneToOne(targetEntity="Person", inversedBy="user")
     * @ORM\JoinColumn(name="person_id", referencedColumnName="id")
     * @Assert\Type("MSG\PersonBundle\Entity\Person")
     */
    private $person;
 
    ...

EL FormType:

/**
     * [email protected]}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('person', 'entity', array(
                    'read_only' => true,
                    'class' => 'PersonBundle:Person',
                    'query_builder' => function($er) {
                        $qb = $er->createQueryBuilder('p')
                            ->addOrderBy('p.surname', 'ASC')
                            ->addOrderBy('p.name', 'ASC');
                        return $qb;
                    }
                )
            )
            ->add('email', LegacyFormHelper::getType('Symfony\Component\Form\Extension\Core\Type\EmailType'), array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'))
            ->add('username', null, array('label' => 'form.username', 'translation_domain' => 'FOSUserBundle'))
            ...

Esto me muestra un formulario para ingresar un usuario, listando todas las personas (Person) ordenadas primero por el apellido y luego por el nombre. Lo que quiero es que solo muestre las personas que no poseen usuario, ya que solo puede haber un usuario por persona.

Traté de armar con where p.user = null pero no funciona porque el atributo no es un atributo que esta fisicamente en la BD. Probé un con un join pero no sé como hacerlo, si me ayudan se los agradezco.

Desde ya muchas gracias. Slds.

Respuestas

#1

En el constructor de la clase persona puedes declarar que el atributo usuario sea null.

public function __construct(){ $this->usuario = null; }

Para recuperar las personas sin usuario creo que algo como esto te valdría:

$personas_sin_usuario = $this->getDoctrine()->getRepository('NombreDeTuBundle:Person')->findBy( array('usuario'=>null));

Un saludo

#2

Gracias @chipirondelnort, lo voy probar pero creo q simple vista que no va a funcionar (no lo sé lo probaré).

El atributo $user de la entidad Person no es un campo en la tabla de la BD, simplemente este atributo no existe en la tabla que administra las entidades Person dentro de la BD. El atributo $user está mapeado dentro de la entidad Person ( @ORM\OneToOne(targetEntity="User", mappedBy="person", cascade={"persist"})).

Estoy aplicando lo que se explica en esta sección:

[http://librosweb.es/libro/symfony_2_x/capitulo_8/relaciones_y_asociaciones_de_entidades.html]

Con la diferencia de que quiero hacer esto a la inversa:

// src/Acme/StoreBundle/Entity/ProductRepository.php
public function findOneByIdJoinedToCategory($id)
{
    $query = $this->getEntityManager()
        ->createQuery(
            'SELECT p, c FROM AcmeStoreBundle:Product p
            JOIN p.category c
            WHERE p.id = :id'
        )->setParameter('id', $id);
 
    try {
        return $query->getSingleResult();
    } catch (\Doctrine\ORM\NoResultException $e) {
        return null;
    }
}

En vez de recuperar los Product, quiero recuperar las categorías que poseen algún producto cargado. En mi caso, en vez de recuperar los usuarios y la persona a quien le corresponde, quiero recuperar únicamente las personas que no poseen usuario.