phpdoctrinemany-to-manypersistencexmlmapper

Doctrine 2.4 can't persist/insert many to many association entities


people can you help me? im having troubles persisting an entity (Solicitud) on Doctrine 2.4 ,the entity has all of its associated objects already stored on its properties, when im passing the object to the entity manager for persist and flush.

The fully descripted relations should be...

  1. Usuario-> Solicitudes (One to Many)
  2. Solicitud-> Servicios (Many to Many)
  3. Category->Servicios (One to Many)

I did generated the entities and the DB structure from my XML Mapping...

On my "solicitud" XML i have defined the relation as you can see below...and the intermediate table got effectively created when i executed the command:

vendor\bin\doctrine orm:schema-tool:update --force

with two columns and everything ok.

this is on "Solicitud" on the fields that define the many to many relation

<many-to-many field="servicios" target-entity="Servicio">
<cascade>
<cascade-persist/>
</cascade>
<join-table name="solicitud_servicio">
<join-columns>
<join-column name="id_solicitud" referenced-column-name="id"/>
</join-columns>
<inverse-join-columns>
<join-column name="id_servicio" referenced-column-name="id"/>
</inverse-join-columns>
</join-table>

and this on Servicio

<doctrine-mapping xmlns="http://doctrine-project.org..." 
  xmlns:xsi="http://www.w3.org/2001/XMLS..." 
  xsi:schemalocation="http://doctrine-project.org... http://doctrine-
  project.org...">
  <entity name="Servicio" table="servicio">
  <indexes>
  <index name="id_categoria" columns="id_categoria"/>
  </indexes>
  <id name="id" type="integer" column="id">
  <generator strategy="IDENTITY"/>
  </id>
   <field name="codigo" type="string" column="codigo" length="15" 
  nullable="false"/>
  <field name="nombre" type="string" column="nombre" length="70" 
  nullable="false"/>
  <field name="detalle" type="string" column="detalle" length="250" 
  nullable="false"/>
  <field name="precioPublico" type="integer" column="precio_publico" 
  nullable="false"/>
 <field name="precioPrivado" type="integer" column="precio_privado" 
  nullable="false"/>
  <field name="medida" type="string" column="medida" length="15" 
  nullable="false"/>
  <field name="planificacion" type="integer" column="planificacion" 
  nullable="false"/>
  <field name="fabricacion" type="integer" column="fabricacion" 
  nullable="false"/>
  <field name="fechaCreacion" type="datetime" column="fecha_creacion" 
  nullable="true"/>
  <field name="ultimaModificacion" type="datetime" column="ultima_modificacion" 
  nullable="false"/>
  <many-to-one field="idCategoria" target-entity="Categoria">
  <join-columns>
  <join-column name="id_categoria" referenced-column-name="id"/>
  </join-columns>
  </many-to-one>
  </entity>
</doctrine-mapping>

Is there something i'm missing? maybe another sentence calling to persist on another of the classes involved/related?

i'm trying to persist through the "solicitud" entity in the entity manager sentences... i have them separated on a different layer as DAO, but it makes no problem, when the data arrives to this layer, i tried var_dump , and everything is okay.

in my "SolicitudService" i wrote this function to collect all the related objects needed for persist , i use VO (virtual objects) with functions inside to build the data from object to Json or from Json to Objects and toEntity Pattern(from VO to Object of the needed class).

what i do in this function:

  1. First i find the objects that i have on my SolicitudServicioVO The following three sentences after the try, then i create the new object Solicitud.
  2. Then i set the objects founded via DAO entities, into the "Solicitud" new object (5 lines after the "//set Solicitud Properties" comment).
  3. After that i iterate,($solicitudServicioVO->listadoServicio), through the listadoServicio ,(list of services coming from the front end), and create VO for each one, that are able in the next sentences to build themselves as an entity "or class of the needed type", in this case the ones that i mentioned in the relations definition at the beginning of this question.
  4. i send to persist, on this sentence

    $this->solicitudDAO->create($solicitud);
    

that leads to the DAO that has...

function create($solicitud){
  $this->em->persist($solicitud);
  $this->em->flush();
  return $solicitud;
}

This function could be more descriptive on its name by maybe calling it createSolicitud as its purpose its to create a new one, but nevermind...it also has to add a Solicitud related to the user.. so i insist , nevermind that by now.

function addSolicitud($solicitudServicioVO){
try{
  $usuario = $this->usuarioDAO->find($solicitudServicioVO->getIdUsuario()->id);
  $direccion = $this->direccionDAO->find($solicitudServicioVO-
  >getIdDireccion()->id);
  $facturacion = $this->datoFacturacionDAO->find($solicitudServicioVO-
  >getIdFacturacion()->id);

  $solicitud = new Solicitud();

  //set Solicitud Properties
  $solicitud->setFechaCreacion(new DateTime());
  $solicitud->setEstado("solicitado");
  $solicitud->setIdFacturacion($facturacion);
  $solicitud->setIdDireccion($direccion);
  $solicitud->setIdUsuario($usuario);

  foreach($solicitudServicioVO->listadoServicio as $servicioVO)
  { 
    $categoriaServicioVO = $this->categoriaService->getCategoria($servicioVO-
    >getCategoriaId());
    $servicio = $servicioVO->toEntity();
    $servicio->setIdCategoria($categoriaServicioVO->toEntity());
    $solicitud->addServicio($servicio);
  }

  $resp = $this->solicitudDAO->create($solicitud);
  $response = Utils::getInstancia()->httpResponseSuccess('001');
  $response['data'] = $resp;
  return $response; 
  }
  catch(Exception $e){
  $response = $e->getMessage();
  }
}

So, i was the most descriptive that i could , im not bieng able to persist this data about the SOlicitud entity...do someone has already a similar problem or any extra ideas...maybe in the XML definition?, it does got trough the entities as annotations and nothing seems to be wrong.

Please help me , this many to many cancer has been taking almost a week without resolution jajaja


Solution

  • updating trouble status jaja:

    "A new entity was found through the relationship 'Solicitud#servicios' that was not configured to cascade persist operations for entity: Servicio@00000000044008fd0000000000ad7488. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={\"persist\"}). If you cannot find out which entity causes the problem implement

    effectively , the entity Solicitud is a new one, cause im trying to create it, the data to create this new Solicitud is being sended from the front-end, with services that i already extracted from DB... i think im about to resolve it.

    what do you think about this loop..., should i be asking for a find for each service, as i have the respective id?

        foreach($solicitudServicioVO->listadoServicio as $servicioVO)
        {   
            $categoria = $this->categoriaDAO->find($servicioVO->getCategoriaId());
            //maybe change this next line
            $servicio = $servicioVO->toEntity(); 
            // for this next one?? ill try and tell you...
            $servicio = $this->servicioDAO->find($servicioVO->getId());
            $servicio->setIdCategoria($categoria);
            $solicitud->getServicios();
            $solicitud->addServicio($servicio);
    
        }
    

    as i show here, i have the service data inside the $servicioVO, maybe i can go to find it in the DB, on this same loop.

    when im doing Solicitud-> addServicio($servicio), im adding one of this fron-end sended services,(servicio), that can construct themselves as object of the Servicio class, on a toEntity pattern function.

    so, i understand that doctrine might be complaining cause it thinks that the services added to the arrayCollection are not the same that it already knows from its DB, even though im setting them with its respective ID, cause the error message directs me more to verify the service entity...than the new Solicitud one.

    ...i did resolved this way, im testing it now, and it works fine, so...if someone else falls into this pit, don't trust your own constructed objects jajaja, doctrine wants it their way, and you shall obey, do find or find by to get the right objects instead of building them, even if the data inside is the same, the persist function got confused, it´s better for this situation to use the direct queried db objects.