Muy buenas,
Estoy teniendo muchos problemas cuando intento publicar en este caso un comentario que lleva fotos a través del método $.ajax
de jQuery.
Todo me lo hace bien menos renderizarme las fotos en tiempo real a través del formulario, porque el comentario con su contenido y la fecha y todo me lo muestra perfecto. Es a la hora de las fotos, sólo me las muestra cuando actualizo la página, pero con Ajax no lo hace y eso que me las guarda perfectamente.
Estoy utilizando symfony 2.6.4 y este es mi código:
Javascript:
$.ajax({ url: Routing.generate('comment_new_form'), data: $data, cache: false, dataType: 'html', contentType: false, processData: false, type: "POST", success: function(data) { if (data) { $form.remove(); $reply.html(data); $('#comment_thread').find('.comment_replying').removeClass('comment_replying'); } else { return false; } }, error: function() { alert("Ha ocurrido un error, vuelve a intentarlo"); }, });
Código PHP de la ruta Ajax:
public function newFormAction(Request $request) { $user = $this->get('security.context')->getToken()->getUser(); if (!$this->getRequest()->isXmlHttpRequest() OR !$user) { // check if request is AJAX request, if not redirect return new Response(json_encode(array('error' => 'Sólo respondo consultas vía AJAX.'))); } // más datos...... $em = $this->getDoctrine()->getManager(); $comment = new Comment(); $comment->setMessages($message); $comment->setUser($user); $comment->setParent($CommentRoot); $comment->setRoot($message_id); $comment->setBody($body); $em->persist($comment); $em->flush(); $iFoto = 1; if ($fotos[0]) { foreach ($fotos as $foto) { $fotoEntity = new Fotos(); list($width, $height, $type, $attr) = getimagesize($foto->getPathname()); $nombreFotoSlug = str_replace( pathinfo($foto->getClientOriginalName(), PATHINFO_EXTENSION), "", $foto->getClientOriginalName() ); $nombreFoto = Util::getSlug($nombreFotoSlug); $nombreArchivoFoto = $nombreFoto . "." . $foto->guessExtension(); $directorio = "fotos/messages/$message_id/comments"; // Guardamos todos los datos en la tabla fotos y guardamos la // fotos en la carpeta correspondiente. $foto->move($directorio, $nombreArchivoFoto); $fotoEntity->setRutaFoto($nombreArchivoFoto); $fotoEntity->setAlto($height); $fotoEntity->setAncho($width); $fotoEntity->setUser($user); $fotoEntity->setMessages($message); $fotoEntity->setComments($comment); $fotoEntity->setNumero($iFoto); $iFoto++; $em->persist($fotoEntity); $em->flush(); } } $CommentNew = $em ->getRepository('AcmeCommentBundle:Comment') ->find($comment->getId()); $template = $this->render( 'AcmeCommentBundle:Comment:comment_ajax.html.twig', array( 'entity' => $message, 'comment' => $CommentNew, ) ); return new Response($template->getContent(), 200); }
Plantilla Twig:
<div id="comment_{{ comment.id }}" class="comment_show comment_depth_"> <div id="comment_body_{{ comment.id }}" class="comment_body"> <div itemscope="" itemtype="http://schema.org/Person"> {% set urluser=url('perfil', {'user': comment.user.getUsernameCanonical()}) %} <a title="{{ comment.userName | capitalize}} " itemprop="url" href="{{utils.getUrl(urluser)}}"> {{ comment.userName | capitalize }} <img sitemprop="image" src="{{ comment.user.rutaFoto | imagine_filter('my_thumb') }}" alt=" {{ comment.userName| capitalize }} " title="{{ comment.userName | capitalize}} " class="avatar"> </a> </div> <p>{{ comment.body | nl2br }}</p> <div class="ago"> <p> Publicado {{ time_diff(comment.createdAt)}}</p> </div> {% if comment.getFotos() %} <div class="galeria row clearfix" itemscope="" itemtype="http://schema.org/photos"> <div class="col-md-12 efecto" data-liffect="zoomIn"> {% set fotoShare = '' %} {% set foto = '' %} {% for image in comment.getFotos() %} {% if loop.index ==1 %} {% set fotoShare = url('home') ~ image.rutaFotoComment %} {% set foto = url('foto', {'slug':entity.url}) %} {% else %} {% set foto = url('foto_pagination', {'slug':entity.url,'page':image.numero}) %} {% endif %} <div class="marco-foto" itemprop="photo" itemscope="" itemtype="http://schema.org/ImageObject"> {% set nombreFoto = 'Foto comentario ' ~ loop.index ~ ' del viaje ' ~ entity.titulo|capitalize ~ ' - ' ~ comment.user.getUsername() | capitalize %} {% if image.nombre %} {% set nombreFoto = image.nombre ~ ', Foto comentario ' ~ loop.index ~ ' ' ~ entity.titulo|capitalize ~ ' ' ~ comment.user.getUsername() | capitalize %} {% endif %} <a title="{{nombreFoto}}" itemprop="url" class="fancybox" href="{{asset(image.rutaFotoComment)}}"> <img itemprop="contentURL" src="{{ image.rutaFotoComment | imagine_filter('my_thumb') }}" alt="{{nombreFoto}}" title="{{nombreFoto}}"> </a> </div> {% endfor %} </div> </div> </div> {% endif %} </div> <div class="comment_reply"> <button data-user-id="{{ comment.user.id }}" data-message-id="{{entity.id}}" data-parent-id="{{ comment.id }}" class="comment_reply_show_form btn btn-primary">Responder</button> </div> <div class="comment_replies"></div>
Espero que con esto sea suficiente para que me ayudar con el problema.
Gracias por todo.
Respuestas
Una pregunta rápida: si pruebas a quitar el filtro imagine_filter
en la plantilla que muestra el comentario, ¿se sigue produciendo el mismo error?
@javiereguiluz
Gracias Javier,
Pero lo he quitado y lo mismo. Por alguna razón desconocida el array de fotos relacionada con los comentarios viene vació. Te pongo el código donde hago dump en mi plantilla_ajax.html.twig
y luego la captura del objeto fotos.
{% if comment.getFotos() %} {{dump( comment)}} <div class="galeria row clearfix" itemscope="" itemtype="http://schema.org/photos"> <div class="col-md-12 efecto" data-liffect="zoomIn"> {% set fotoShare = '' %} {% set foto = '' %} {% for image in comment.getFotos() %}
El {{ dump( comment) }}
me muestra lo siguiente: el ArrayCollection
vacío. La verdad esto es muy raro, por cierto dentro del for no entra {% for image in comment.getFotos() %}
@jcarlosweb
Buenas, no estoy muy seguro de que con $.ajax
puedas subir imágenes al servidor.
En el controlador veo que tienes if ($fotos[0]) {...
pero no se ve de donde viene la variable $fotos
, si puedes muéstranos como obtienes dicha variable.
Además puedes hacer estos dumps y nos muestras:
dump($fotos, $request->files->all(), $_FILES);
Saludos!
@manuel_j555
Hola Manuel,
Sí se puede con HTML5 Form Data
El objeto lo recojo de la siguiente forma:
$fotos = $request->files->get('acme_commentbundle_comment')['fotos'];
Lo sube correctamente porque cuando actualizo la página muestra las fotos perfectamente sin Ajax. Esto quiere decir que las fotos se han subido correctamente tanto a la base de datos y a su carpeta correspondiente.
El problema viene por $ajax
que es super rarísimo. Te muestro los dumps que me has pedido
Si necesitas que enseñe más código me avisas.
@jcarlosweb
Ok, gracias por la info.
En tu controlador veo que recorres las fotos y llamas al setComments($comment)
en cada instancia de $fotoEntity, pero no haces la asociación inversa $comment->addFotos($fotoEntity)
.
Entonces aunque hagas lo siguiente luego de todos los persist:
$CommentNew = $em ->getRepository('AcmeCommentBundle:Comment') ->find($comment->getId());
Me parece que el método find()
realmente no está ejecutando ninguna consulta, porque ya la entidad comment
está manejada en el EntityManager, por lo que la colección de fotos en el objeto $CommentNew
tiene los mismos valores que cuando hiciste el persist de $comment
.
Prueba con el $comment->addFotos($fotoEntity)
y nos avisas.
Saludos!
@manuel_j555
Manuel, si ahí estaba el problema, que tonto fui.
Solo una cosa para entender el problema que he tenido.
Entonces lo que hace $comment->addFotos($fotoEntity)
¿es solo añadir las fotos al objeto actual de comment
?
Muchas gracias Manuel, me has salvado ♥
@jcarlosweb
Basicamente si, pero además te da un poco más de control de que fotos se asociarán realmente al $comment
.
Hay ejemplos de código donde en el addXXX()
verificas que no exista ya un elemento con cierta característica en la colección; si existe no se añade. También en mi caso, he tenido campos que dependen de cálculos que se realizan en colecciones, como sumatorios de costos (esto lo hago en el @PrePersist
de la entidad), entre otros.
Saludos!
@manuel_j555
Gracias Manuel por la explicación. Como siempre un gusto.
@jcarlosweb