Hola,
Tengo una entidad Block y otra entidad Question con una relación ManyToMany básica. Este seria el mapeado de las entidades:
// AppBundle/Entity/Question /** * @var ArrayCollection * * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Block", inversedBy="questions", cascade={"persist"}) * @ORM\JoinTable(name="question_block") */ private $blocks; // AppBundle/Entity/Block /** * @var ArrayCollection * * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Question", mappedBy="blocks", cascade={"persist"}) */ private $questions;
Se trata de un juego y tanto desde Question, como desde Block, necesito añadir preguntas al bloque o asignar las preguntas a un bloque. Es decir, si estoy creando una pregunta, esta la asigno a uno o varios bloques y si estoy creando un bloque necesito también poder añadir preguntas directamente.
El primer caso no tengo problemas, pero buscando información he visto que desde el inversed side (Block) no lo hace Doctrine, ¿como lo hago entonces?. Si es nuevo no hay problemas, pero si estoy editando un bloque y quiero quitar preguntas y añadir otras, no me elimina las que haya desmarcado (un select multiple ahora mismo). Actualmente hago algo así:
// AppBundle/Controller/Admin/BlocksController ... /** * @Route("/{id}/edit", options={"expose"=true}, name="admin_game_blocks_edit") * @Method({"GET", "POST"}) * @param Block $block * @param Request $request * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response */ public function editAction(Block $block, Request $request) { $form = $this->createForm(BlockType::class, $block, ['em' => $this->getUser()->getCode()]); $oldQuestions = new ArrayCollection(); foreach ($block->getQuestions() as $question) { $oldQuestions->add($question); } $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $em = $this->getDoctrine()->getManager($this->getUser()->getCode()); $block->setUpdatedAt(new \DateTime()); $block->setQuestions($oldQuestions); $em->flush(); return $this->redirectToRoute('admin_game_blocks_index'); } return $this->render('admin/game/blocks/edit.html.twig', [ 'block' => $block, 'form' => $form->createView() ]); } ...
// AppBundle/Entity/Block ... /** * Set questions * * @param ArrayCollection $questions * @return Block */ public function setQuestions($questions = null) { if ($questions) { foreach ($questions as $question) { if (!$this->questions->contains($question)) { $this->removeQuestion($question); } } } foreach ($this->getQuestions() as $question) { $this->addQuestion($question); } return $this; } ...
Ni que decir tiene que no funciona puesto que no elimina la que haya desmarcado, aunque en general no funciona muy bien, es como lo he dejado antes de escribir aquí jeje. A ver si alguien me puede echar una mano, seguro que os lo habéis encontrado antes jeje :P
Gracias.
Un saludo.
Respuestas
Solucionado, últimamente parece que escribir aquí hace que se me aclaren las ideas jeje. Al final solo tuve que añadir 'by_reference' => false
al formulario lo cual hace que los métodos addX y removeX sean llamados y me ahorro todo lo que estaba haciendo.
Ahora me surge otra duda. ¿Como podría hacer para que en vez de un select multiple sea un listado o una tabla a la que añadir registros?. Tengo un Block y quiero que se muestre un listado/tabla con las Question y poder añadir registros ya existentes a esta y que se guarde la relación. Tanto al crear como al editar, claro.
Gracias.
Un saludo.
@LoGaNsF