Robert W. Hunter
Robert W. Hunter

Reputation: 3003

Doctrine2 entities relation extra fields

I have the following DB structure.

Pge\IncidenciasBundle\Entity\Cliente:
    type: entity
    table: cliente
    repositoryClass: Pge\IncidenciasBundle\Entity\ClienteRepository
    id:
      id:
        type: integer
        generator:
          strategy: IDENTITY
    fields:
        nombre:
            type: string
            length: 250
            fixed: false
            nullable: true   
    manyToMany:
        servicios:
            targetEntity: Servicio
            cascade: [persist]
    lifecycleCallbacks: {  }
Pge\IncidenciasBundle\Entity\Servicio:
    type: entity
    table: servicio
    id:
      id:
        type: integer
        generator:
          strategy: IDENTITY
    fields:
        nombre:
            type: string
            length: 250
            fixed: false
            nullable: true
    lifecycleCallbacks: {  }

Right now, there's a DB table called cliente_servicio that keeps the relations between this two entities, some data for example:

cliente_id  servicio_id
1           1
1           4
1           8
2           1
3           3
3           7

The forms are totally working right now to manage this relation. But now, I need another function.

I need to create a new form/structure/whatever you tell me to set two extra fields per row: status and comment and date so the final DB output will be this:

cliente_id  servicio_id date        status  comment
1           1           2013-09-19  ok      null
1           4           2013-09-19  ko      Needs to clear
1           8           2013-09-19  ok      null
2           1           2013-09-19  ko      Packets lost (fix firewall)
3           3           2013-09-19  ko      Out of service (see ticket T9388)
3           7           2013-09-19  ok      null

The point is to call route localhost/whatever/{id}/{date} where {id} is cliente_id (can be the client name if necessary field nombre of cliente entity) and {date} is date, on this page index, it will display the recorded data (the data I want to create but I don't know how) for a given date for selected cliente_id.

On the new action, the form will display a field for estado, comment and date for each servicio_id assigned to {id} (cliente_id)

I think it is easy to make if you know Symfony2, but I'm totally lost... With simple PHP (no frameworks) I managed to handle this situation and it's working, but I don't know how with Symfony2.

Additional info:

Table cliente_servicio which handles the manyToMany relationship is not mapped on Symfony2, because it was auto-generated with doctrine:schema:update --force it can't be mapped because its lack of id primary key (it only has cliente_id and servicio_id)

UPDATE

Okay, doing Doctrine2: Best way to handle many-to-many with extra columns in reference table so now I have m:1 and 1:m relations with an intermediate entity for cliente and servicio called clienteservicio

Also, the point was to have in one single form, X rows with estado , comentario and date fields where X = number of servicio assigned to given cliente

<?php

namespace Pge\IncidenciasBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Cliente
 *
 * @ORM\Table(name="cliente")
 * @ORM\Entity(repositoryClass="Pge\IncidenciasBundle\Entity\ClienteRepository")
 */
class Cliente
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="nombre", type="string", length=250, nullable=true)
     */
    private $nombre;

    /**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\OneToMany(targetEntity="ClienteServicio", mappedBy="cliente")
     */
    private $servicio;

    public function __toString()
    {
        return $this->nombre;
    }
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->servicio = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set nombre
     *
     * @param string $nombre
     * @return Cliente
     */
    public function setNombre($nombre)
    {
        $this->nombre = $nombre;

        return $this;
    }

    /**
     * Get nombre
     *
     * @return string 
     */
    public function getNombre()
    {
        return $this->nombre;
    }

    /**
     * Add servicio
     *
     * @param \Pge\IncidenciasBundle\Entity\ClienteServicio $servicio
     * @return Cliente
     */
    public function addServicio(\Pge\IncidenciasBundle\Entity\ClienteServicio $servicio)
    {
        $this->servicio[] = $servicio;

        return $this;
    }

    /**
     * Remove servicio
     *
     * @param \Pge\IncidenciasBundle\Entity\ClienteServicio $servicio
     */
    public function removeServicio(\Pge\IncidenciasBundle\Entity\ClienteServicio $servicio)
    {
        $this->servicio->removeElement($servicio);
    }

    /**
     * Get servicio
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getServicio()
    {
        return $this->servicio;
    }
}

<?php

namespace Pge\IncidenciasBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Servicio
 *
 * @ORM\Table(name="servicio")
 * @ORM\Entity
 */
class Servicio
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="nombre", type="string", length=250, nullable=true)
     */
    private $nombre;

    /*
     * 
     * @ORM\OneToMany(targetEntity="ClienteServicio", mappedBy="servicio")
     */
    private $cliente;

    public function __toString()
    {
        return $this->nombre;
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set nombre
     *
     * @param string $nombre
     * @return Servicio
     */
    public function setNombre($nombre)
    {
        $this->nombre = $nombre;

        return $this;
    }

    /**
     * Get nombre
     *
     * @return string 
     */
    public function getNombre()
    {
        return $this->nombre;
    }
}

<?php

namespace Pge\IncidenciasBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * ClienteServicio
 *
 * @ORM\Table(name="cliente_servicio")
 * @ORM\Entity
 */
class ClienteServicio
{

    /**
     * @var integer
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     *
     * @ORM\Column(name="estado", type="string", length=255, nullable=false)
     */
    private $estado;

    /**
     * @var string
     *
     * @ORM\Column(name="comentario", type="string", length=255, nullable=false)
     */
    private $comentario;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="fecha", type="date", nullable=false)
     */
    private $fecha;

    /**
     * @var \Pge\IncidenciasBundle\Entity\Servicio
     *
     * @ORM\ManyToOne(targetEntity="Servicio", inversedBy="cliente")
     */
    private $servicio;

    /**
     * @var \Pge\IncidenciasBundle\Entity\Id
     *
     * @ORM\ManyToOne(targetEntity="Cliente", inversedBy="servicio")
     */
     private $cliente;

    /**
     * Set id
     *
     * @param integer $id
     * @return ClienteServicio
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set estado
     *
     * @param string $estado
     * @return ClienteServicio
     */
    public function setEstado($estado)
    {
        $this->estado = $estado;

        return $this;
    }

    /**
     * Get estado
     *
     * @return string 
     */
    public function getEstado()
    {
        return $this->estado;
    }

    /**
     * Set comentario
     *
     * @param string $comentario
     * @return ClienteServicio
     */
    public function setComentario($comentario)
    {
        $this->comentario = $comentario;

        return $this;
    }

    /**
     * Get comentario
     *
     * @return string 
     */
    public function getComentario()
    {
        return $this->comentario;
    }

    /**
     * Set fecha
     *
     * @param \DateTime $fecha
     * @return ClienteServicio
     */
    public function setFecha($fecha)
    {
        $this->fecha = $fecha;

        return $this;
    }

    /**
     * Get fecha
     *
     * @return \DateTime 
     */
    public function getFecha()
    {
        return $this->fecha;
    }

    /**
     * Set servicio
     *
     * @param \Pge\IncidenciasBundle\Entity\Servicio $servicio
     * @return ClienteServicio
     */
    public function setServicio(\Pge\IncidenciasBundle\Entity\Servicio $servicio = null)
    {
        $this->servicio = $servicio;

        return $this;
    }

    /**
     * Get servicio
     *
     * @return \Pge\IncidenciasBundle\Entity\Servicio 
     */
    public function getServicio()
    {
        return $this->servicio;
    }

    /**
     * Set cliente
     *
     * @param \Pge\IncidenciasBundle\Entity\Cliente $cliente
     * @return ClienteServicio
     */
    public function setCliente(\Pge\IncidenciasBundle\Entity\Cliente $cliente = null)
    {
        $this->cliente = $cliente;

        return $this;
    }

    /**
     * Get cliente
     *
     * @return \Pge\IncidenciasBundle\Entity\Cliente 
     */
    public function getCliente()
    {
        return $this->cliente;
    }
}

As I said, the point is assign servicio to a cliente from cliente form.

Then, from another form, set the extra fields to the servicio assigned to cliente (It would be great if I can handle every servicio for one cliente in one form containing a row for each servicio)

The way I'm doing right now, is not the way I want it...

Upvotes: 0

Views: 305

Answers (1)

m0c
m0c

Reputation: 2191

The Answer from the comments is still applicable.

You just need to turn your m:n relation to a m:1 plus 1:n relation that you will end up with 3 Entities instead of 2. And as soon as you have 3 Entities you can also just create a new form for the "intermediate" entity, because it is like every other entity.

UPDATE:

You can still simulate the same thing if you add some logic to your client:

public function addService(Service $service){
     $clientService = new ClientService();
     $clientService->setClient($this);
     $clientService->setService($service);
     $this->clientService->add($clientService);
}

You can do some similar simulations with getService();

Alternative is that you only need to adopt your Form and have multiple clientservicio on your client form but then on each clientservicio form only one service. This should still work.

Upvotes: 2

Related Questions