Symfony: Obtener fotos en un evento listener de un bundle de tercero

Buenas noches!!

Estoy intentando implementar en el bundle FOSCommentBundle añadir fotos, para ello estoy utilizando los eventos que el mismo proporciona que son los siguientes:

  • fos_comment.comment.pre_persist
  • fos_comment.comment.post_persist
  • fos_comment.comment.create
  • fos_comment.thread.pre_persist
  • fos_comment.thread.post_persist
  • fos_comment.thread.create
  • fos_comment.vote.pre_persist
  • fos_comment.vote.post_persist
  • fos_comment.vote.create

El que utilizo es fos_comment.comment.pre_persist. Y lo creo como servicio de esta manera:

acme_comment.listener:
        class: Acme\CommentBundle\Event\CreateCommentListener
        arguments: 
            - @doctrine.orm.entity_manager
            - @fos_comment.manager.comment
            - @security.context
            - @request_stack
        tags:
            - {name: kernel.event_listener, event: fos_comment.comment.pre_persist, method: onCommentPersist }

Después tengo la clase Acme\CommentBundle\Event\CreateCommentListener:

namespace Acme\CommentBundle\Event;
 
use FOS\CommentBundle\Events;
use FOS\CommentBundle\Event\CommentEvent;
use FOS\CommentBundle\Model\CommentInterface;
use FOS\CommentBundle\Model\CommentManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\RequestStack;
use Doctrine\Orm\EntityManager;
use Acme\FotosBundle\Entity\Fotos as Foto;
 
class CreateCommentListener
{
    private $em;
    private $commentManager;
    private $user;
    private $requestStack;
    private $securityContext;
 
    public function __construct(EntityManager $em,CommentManagerInterface $commentManager, SecurityContext $securityContext,RequestStack $requestStack)  {
 
       $this->em = $em;
       $this->requestStack = $requestStack->getCurrentRequest();
       $this->commentManager = $commentManager;
       $this->securityContext = $securityContext;
 
       if ($this->securityContext->getToken() !== null) {
           $this->user = $this->securityContext->getToken()->getUser();
       } else {
           $this->user = false;
       }
    }
 
    /**
     * Disallows comments in a closed thread.
     *
     * @param \FOS\CommentBundle\Event\CommentEvent $event
     */
    public function onCommentPersist(CommentEvent $event)
    {
        if($this->user !== false){
 
        /* @var $comment \FOS\CommentBundle\Model\CommentInterface */
 
        $comment = $event->getComment();
        $fotos = $this->requestStack->files;
 
        var_dump($fotos->all()); //aqui compruebo que estoy recibiendo las fotos
        die();
        $iFoto=1;
        foreach ($fotos as $foto){
           echo $foto->getClientOriginalName();
 
           $foto= new Foto();
           $foto->subirFoto($comment->getThread()->getId());
           $foto->setMessages($post);
           $foto->setComment($comment);
           $foto->setUser($this->user);
           $foto->setNumero($iFoto);
 
           $this->em->persist($foto);
           $this->em->flush();
 
           $iFoto++; 
        }
 
        die("nada");
        echo $post->getId();
        }
    }

Sigo en el siguiente POST.

Respuestas

#1

Aqui hago un var_dump($fotos->all());, pero nada me devuelve array(0) { }

Te muestro también la entidad Comment que es la que reemplaza a la original:

<?php
namespace Acme\CommentBundle\Entity;
 
use Doctrine\ORM\Mapping as ORM;
use FOS\CommentBundle\Entity\Comment as BaseComment;
use FOS\CommentBundle\Model\SignedCommentInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Jc\Util;
 
/**
 * @ORM\Entity
 * @ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
 */
class Comment extends BaseComment implements SignedCommentInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
 
    /**
     * Thread of this comment
     *
     * @var Thread
     * @ORM\ManyToOne(targetEntity="Acme\CommentBundle\Entity\Thread")
     */
    protected $thread;
    /**
     * Author of the comment
     *
     * @ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User" , inversedBy="comments")
     * @var User
     */
    protected $author;
 
     /**
     * @var File
     *
     * @ORM\OneToMany(
     * targetEntity="Acme\FotosBundle\Entity\Fotos",
     * mappedBy="comment",
     * cascade={"all"},
     * orphanRemoval=true)
     * @Assert\Valid()
     *
     */ 
    private $fotos;
 
    public function __construct() {
 
        //$this->fotos   = new ArrayCollection();
        $this->createdAt=new \DateTime(date('Y-m-d H:i:s'));
 
    }
 
    public function __toString()
    {
        return (string) "Comentario del hilo:".$this->getAuthorName() ?: 'Nuevo comentario';
    }
 
    public function setAuthor(UserInterface $author)
    {
        $this->author = $author;
    }
 
    public function getAuthor()
    {
        return $this->author;
    }
 
    public function getAuthorName()
    {
        if (null === $this->getAuthor()) {
            return 'Anónimo';
        }
 
        return $this->getAuthor()->getUsername();
    }
 
    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
 
    /**
     * Add fotos
     *
     * @param \Acme\FotosBundle\Entity\Fotos $fotos
     * @return Comment
     */
    public function addFoto(\Acme\FotosBundle\Entity\Fotos $fotos)
    {
        $this->fotos[] = $fotos;
 
        return $this;
    }
 
    /**
     * Remove fotos
     *
     * @param \Acme\FotosBundle\Entity\Fotos $fotos
     */
    public function removeFoto(\Acme\FotosBundle\Entity\Fotos $fotos)
    {
        $this->fotos->removeElement($fotos);
    }
 
    /**
     * Get fotos
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getFotos()
    {
        return $this->fotos;
    }
}

También muestro el Formulario CommentType.php

<?php
 
namespace Acme\CommentBundle\Form\Type;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use FOS\CommentBundle\Form\CommentType as BaseType;
use FOS\CommentBundle\Model\CommentInterface;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
 
class CommentType extends AbstractType
{
    protected $em;
 
    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }
 
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        //parent::buildForm($builder, $options);
         $builder
         ->add('body', 'textarea')
         ->add('fotos', 'file', array(
             'multiple' => true,
             'required'=>false,
             'data_class' => null,
 
            ))
         ;
 
    }
 
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\CommentBundle\Entity\Comment'
        ));
    }
 
    public function getName()
    {
        return 'comment_form';
    }
    public function getParent()
    {
        return 'fos_comment_comment';
    }
}

También en la vista he puesto el {{ form_enctype(form) }}

La verdad ya no se que hacer más he probado de todo y sigue sin salirme nada.

¿Cómo lo tengo que hacer?

#2

Hola,

Puedes probar a modificar la linea:

$this->requestStack = $requestStack->getCurrentRequest();
//Por
$this->requestStack = $requestStack->getMasterRequest();

Solo para verificar si estas en un subRequest al momento de ser invocado el listener. De ser así, ese es el problema.

Por otro lado, si usas o tienes la posibilidad de Usar la versión 2.6 de symfony, allí tienes la función dump($var), que te permite visualizar la informacion de un objeto php mucho mejor que con var_dump.

#3

Muchas gracias Manuel como siempre eres muy amable.

Pero sigue saliéndome lo mismo. He probado también hacer un var_dump($fotos) sin el objeto files para ver que me muestra y me muestra lo siguiente:

object(Symfony\Component\HttpFoundation\FileBag)#12 (1) {
    ["parameters":protected]=> array(0) { }
}

Por cierto en el Composer para la actualización de la version 2.6, ¿qué forma es la mejor? ¿De esta manera: "symfony/symfony": "2.6.*"?

Bueno Manuel espero puedas ayudarme ha resolver el problema, a veces me desespero mucho con Symfony.

Un abrazo.

#4

Sigo sin saber porque no me muestra las foto en el request. ¿Tiene que ver algo con foscommentbunle, que solamente registre lo que viene predefinido en su formulario?.

Por ejemplo para coger el texto del textarea si puedo cogerlo lo hago así:

$this->requestStack->request->get('fos_comment_comment')['body']

Pero las fotos imposible; me da el resultado del anterior post. Pongo de paso el html que me genera el formulario:

<form class="fos_comment_comment_new_form" 
action="http://test.local/app_dev.php/api/threads/129/comments" data-parent=""
method="POST" enctype="multipart/form-data" >
 
<div class="fos_comment_form_errors">
</div>
 
<textarea id="fos_comment_comment_body" name="fos_comment_comment[body]"
          required="required"></textarea>
 
<div>
  <label for="fos_comment_comment_fotos">Fotos</label>
  <input type="file" id="fos_comment_comment_fotos" name="fos_comment_comment[fotos][]" 
         multiple="multiple" />
</div>
 
<input type="hidden" id="fos_comment_comment__token" name="fos_comment_comment[_token]" 
       value="SNEMKNEjvjj5XJl5r0Eu8aZEPRulUiA8dDVcn06ZmOw" />
 
<div class="fos_comment_submit">
  <input type="submit"  class="btn btn-primary" value="Enviar comentario" />
</div>
 
</form>
#5

Verifica si en la variable global $_FILES hay elementos. Si es así, deberás indagar sobre el proceso ejecutado al enviar el formulario, a ver en que momento es llamado tu listener.

Con respecto a actualizar Symfony, como lo has colocado está bien.

Por otro lado en el profiler tienes la información del formulario, puedes inspeccionar allí también a ver si se enviaron los archivos.

#6

Me retorna array(0) { }. Increíble.......

#7

Manuel tengo que añadir que el formulario se envía por jQuery. No si será ese el problema.

Este es el archivo javascript que provee el bundle: comments.js

#8

Bueno, parece ser que es por culpa del archivo JavaScript que proporciona. Vamos a ver cómo puedo modificar el archivo para conseguir que coja las imágenes. Esto va a ser complicado.

#9

Bueno al final lo que voy hacer es hacerlo propio, porque ha sido una equivocación coger un bundle el cual ya no tiene ni soporte y seguro que tardaré mucho menos.

Un cordial saludo.