Muy buenas,
La verdad es que ya no puedo más con esto, me tiene un poco desesperado.
Mi problema es que en el administrador con SonataAdminBundle
no puede eliminar ningún campo de la base de datos imágenes y lo más que me mosquea es que tengo otro hecho igual con vídeos y funciona correctamente. Bueno en el de vídeo son solamente enlaces a YouTube, pero es lo mismo. Porque aunque no me eliminara la foto de la carpeta, me podría eliminar el registro.
Expongo mi código haber si me podéis sacar de este aprieto que llevo tres días, para esto leyendo, probando y probando.
Tengo dos entidades una foto y otra messages.
Entidad Fotos:
/** * Fotos * * @ORM\Table(name="fotos") * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Fotos { /** * @ORM\ManyToOne(targetEntity="Acme\MessagesBundle\Entity\Messages", inversedBy="fotos") * @ORM\JoinColumn(name="message_id", referencedColumnName="id") */ private $messages; // ... }
Código para FotosAdmin.php
class FotosAdmin extends Admin { /** * @param FormMapper $formMapper */ protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('foto', 'file',array( 'required' => false, 'help' => $rutaFoto, 'label' => 'Foto '.$numero.' ', 'attr' => array( 'class' => 'nice_file_field', // 'onchange'=>"readImage(this.form,this)", // 'oninvalid'=>"setCustomValidity('Por favor escoge un nombre de usuario valido')" ) )) ->add('nombre','text',array( 'label' => 'Nombre la foto:', 'required' => false, )) ; } // ... }
Continua en la siguiente respuesta...
Respuestas
Continúo con el código, porque me ha dado un error que la pregunta no puede ser tan larga.
Entidad messages:
/** * Messages * * @ORM\Table(name="messages") * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Messages { /** * @var ArrayCollection $fotos * * @ORM\OneToMany( * targetEntity="Acme\FotosBundle\Entity\Fotos", * mappedBy="messages", * cascade={"all"}) * orphanRemoval=true) *@Assert\Valid() * */ private $fotos; /** * @var ArrayCollection $videos * * @ORM\OneToMany( * targetEntity="Acme\VideosBundle\Entity\Videos", * mappedBy="messages", * cascade={"all"}, * orphanRemoval=true) *@Assert\Valid() * */ private $videos; // ... public function __construct() { $this->fotos = new ArrayCollection(); $this->videos = new ArrayCollection(); } // ... /** * Set fotos * * @param string $fotos * @return messages */ public function setFotos($fotos = null) { foreach ($fotos as $image) { $image->setMessages($this); } public function addFotos(\Acme\FotosBundle\Entity\Fotos $fotos) { if(!$this->fotos->contains($fotos)){ $this->fotos[] = $fotos; $fotos->setMessages($this); } return $this; } public function removeFotos(\Acme\FotosBundle\Entity\Fotos $fotos) { $this->fotos->removeElement($fotos); $this->fotos->remove($fotos); $fotos->setMessages(null); if ($file = $this->fotos->getUploadRootDir($id)) { unlink($file); } } public function removeVideos(\Acme\VideosBundle\Entity\Videos $videos) { $this->videos->removeElement($videos); } // ... }
Formulario MessagesAdmin.php para SonataAdmin:
class MessagesAdmin extends Admin { /** * @param FormMapper $formMapper */ protected function configureFormFields(FormMapper $formMapper) { // ... ->Tab('Fotos', array('value'=>'Fotos')) ->with('Fotos', array( 'class' => 'col-md-12', 'description' => '', 'name' => 'Fotos' )) ->add('fotos', 'sonata_type_collection', array( 'by_reference' => false, //'btn_add' => false, 'required' => false, 'cascade_validation' => true, 'label' => 'Fotos experiencias', 'type_options' => array('delete' => true,) ), array( 'edit' => 'inline', // 'inline' => 'table', 'sortable' => 'position', )) ->end() ->end() // ...
Bueno pues cuando marco el checkbox de Delete y lo doy actualizar no hace nada, lo peor de todo es que ni siquiera me da un error. Otra cosa la subida de imagen me va bien.
Pongo una captura de la imagen del administrador.
@jcarlosweb
Muy buenas otra vez,
La verdad me gustaría saber si las preguntas que hago son muy obvias o son inutiles.
Ya que al no tener respuesta, no se donde publicarlo y no se quien me podría ayudar.
La unica ayuda que tengo es internet ya que soy autodidacta y Symfony lo estoy aprendiendo así. No si sabeís si para este tipo de preguntas, ¿donde puedo hacerlo?.
Y que me da igual pagar mi unica intencion es aprender.
Un saludo.
@jcarlosweb
Buenas otra vez,
Ahora sí que me sale error por lo menos. Por lo que se ve no puedo conseguir el id
del mensaje relacionado con la foto cuando le doy a eliminar. Me sale el siguiente error:
Error: Call to a member function getId() on a non-object in /var/www/proyecto/src/acme/FotosBundle/Entity/Fotos.php line 650
Y la linea 650 es esto donde obtengo la ruta de la foto:
/** * Get rutaFoto * * @return string */ public function getRutaFoto() { $ruta="fotos/messages/".$this->getMessages()->getId()."/".$this->rutaFoto; return $ruta; }
Sabéis porque no puedo conseguir el id
en la entidad fotos. La verdad que esto me funciona en todo menos en esto, a la hora de eliminar.
Un saludo.
@jcarlosweb
Perfecto ya he conseguido sacar el id del mensaje, solamente tenia que crear los setter y getter del campo de relación con el mensaje.
Ahora el problema esta que no se como eliminarlo ya que el problema que tengo no lo puedo solucionar con HasLifecycleCallbacks y PostRemove, ya que esto se ejecuta cuando elimino el mensaje y rollo esta que al administrar el mensaje expongo las fotos y las pre visualizo bien y puedo subir más foto, pero no puedo eliminar, al igual que hago con los videos. Claro los vídeos son campos de textos pero las fotos es solamente un registro que tengo que eliminar de la tabla fotos para eliminar la relación con el mensaje. Es solo eso.
Por ahora he conseguido sacar en el PreUpdate MessagesAdmin.php la foto que viene con la variable delete de esta manera:
public function preUpdate($objectif) { $params = $this->getRequest()->request->get($this->getUniqid()); $images = $params['fotos']; foreach ($images as $key=>$value) { if(isset($images[$key]["_delete"])) echo "yes"; die(); }
Pero el único data que obtengo es esto
Content-Disposition: form-data; name="s5474db1dc479a[fotos][2][_delete]"
que me lo pasa por Post porque lo he mirado por el Chrome, pero ahora no se como eliminarlo, no tengo ninguna solución ni con HasLifecycleCallbacks ni nada, ni con la funcion removeFotos de la entidad ni nada.
La verdad estoy haciendo otras cosas de programación, pero llevo ya casi con esto un mes.
Haber si alguien me saca de este embrollo porque la verdad, no se como una cosa tan normal no esta resuelta por ningún sitio.
Gracias!!!
@jcarlosweb
Buenas,
Prueba a configurar en la asociación OneToMany lo siguiente:
Saludos!
@manuel_j555
Gracias @manuel_j555,
Pero ya lo tengo hecho en la entidad Messages.php
de este modo
/** * @var ArrayCollection $fotos * * @ORM\OneToMany( * targetEntity="Acme\FotosBundle\Entity\Fotos", * mappedBy="messages", * cascade={"persist", "remove"}, * orphanRemoval=true) *@Assert\Valid() * */ private $fotos; // continua ... public function removeFotos(\Acme\FotosBundle\Entity\Fotos $fotos) { die("hola"); $this->fotos->removeElement($fotos); $this->fotos->remove($fotos); $fotos->setMessages(null); if ($file = $this->fotos->getUploadRootDir($id)) { unlink($file); } }
Pero la función removeFotos
ni siquiera si ejecuta ya que no me lanza ni el die()
;
Gracias por la ayuda.
@jcarlosweb
A lo siento, no lo habia visto, bueno prueba a jugar con la opción by_reference del tipo collection.
Generalmente con la opción by_reference en false, lo que se hace es forzar el llamado de los add y remove de la clase padre, en este caso de Messages.
Acá lo explican mejor http://symfony.com/doc/current/cookbook/form/form_collections.html
Saludos!
@manuel_j555
@manuel_j555 eres grande!!! Gracias!!!!! Me funciona con 'by_reference' => true
, la verdad no entiendo porque me funciona, sinceramente, porque en la llamada en la funcion removeFotos()
le tengo puesto die();
y no se ejecuta, entonces la verdad no se donde proviene la función que elimina el registro, porque si me gustaría perfilarlo y eliminar la imagen del directorio.
Muchas gracias!!!
@jcarlosweb
Con by_reference en true?, por defecto está en true, por lo que si lo has puesto como true, realmente no estás haciendo ningún cambio.
Pero en fin, yo creería que el by_reference es más para usarlo en la funcionalidad de agregar que en la de remover, ya que al remover, la clase PersistentCollection fuerza que el elemento removido sea eliminado de la base de datos. uses o no by_reference.
La gracia del by_reference en estos casos es que en true hace algo como:
//para agregar $message->getFotos()->add($foto); //para remover $message->getFotos()->remove($foto);
mientras que en false hace:
//para agregar $message->addFoto($foto); //para remover $message->removeFoto($foto);
Lo que tambien hay que tener en cuenta es si ese método removeFotos lo has creado tú o lo ha creado Symfony con el comando generate entities, ya que cuando el nombre de la propiedad termina con s hay casos (mas bien creo que siempre) donde esa s del final es removida. por tanto puede que el método sea removeFoto en vez de removeFotos
@manuel_j555
Hola Manuel,
Gracias de nuevo. Manuel lo tenía en false
. Según vi en algunos tutoriales o algunos foros.
Ahora estoy en el trabajo, pero en cuanto llegue a casa ya que Symfony es una cosa propia, lo miro y te comento sobre el caso de la "s".
Muchas gracias de nuevo Manuel.
@jcarlosweb
Hola de nuevo @manuel_j555,
No encuentro donde se ejecuta la eliminación de la foto, he probado con y sin "s" y ademas en todas las entidades que tienen relación con las fotos y añadirle las dos funciones con y sin s.
¿Pude ser al ser tipo sonata_type_collection
me lo ejecute una función interna de sonata? ¿Cuál puede ser? Esto lo que añado al formulario:
->add('fotos', 'sonata_type_collection', array( 'by_reference' => true, 'mapped' => true, 'required' => false, 'cascade_validation' => true, 'label' => 'Fotos experiencias', 'type_options' => array( 'delete' => true, ) ), array( 'edit' => 'inline', 'sortable' => 'position', )) ->end()
Gracias y un abrazo!!
@jcarlosweb
Hola,
Con el 'by_reference' => true
, no va a llamar nunca a el removeFoto
de la entidad. Debe estar en false
para que lo haga, por lo que te recomiendo que pruebes lo de la s
con el 'by_reference' => false
.
Una mejor opción sería eliminar esos métodos add
y remove
de la entidad, y ejecutar el comando de consola doctrine:generate:entities Bundle:Message
para que el framework te los genere correctamente.
Por otro lado, puedes crear un callback en la entidad \Acme\FotosBundle\Entity\Fotos
para el evento PostRemove
de Doctrine:
/** * @ORM\PostRemove() */ public function removeImage() { // aquí la lógica para eliminar la imagen. }
@manuel_j555
Manuel tenias totalmente la razón. He aprendido mucho de esta lección que me has dado. Al final he generado de nuevo los getter y setter. Y si eran si la "s" y yo lo había puesto a mano. Luego elimino el registro del foto perfectamente y con PostRemove
lo elimino del directorio.
Ahora no me gustaría abusar de tu ayuda, pero tengo un problema todavía con las colecciones: cuando le doy botón de "Añadir nueva foto" y examino la foto y luego sin actualizar el mensaje le doy añadir de nuevo "Añadir nueva foto" y se pierde el valor de de la primera collection
que he añadido, tengo que volver a examinar la foto para que suba la foto correctamente.
¿Sabes a que puede ser debido?
Solamente decirte que muchas gracias, creo que sin ti nunca lo hubiera conseguido.
Un abrazo muy fuerte @manuel_j555
@jcarlosweb
De nada hermano :)
Bueno, creo que eso que comentas es JavaScript, por lo que sería bueno que expongas el código para poder ayudarte mejor, aunque creería que mejor te crees un nuevo post para no ligar las cosas.
@manuel_j555
Gracias Hermano. Eso haré.
@jcarlosweb
Hola, gracias por sus respuestas me ayudaron a darle solución a un problema similar. Gracias por compartir!
@jmarioromero