2015-02-10 10 views
6

Qui è il mio tipo di modulo:Symfony2 campo di modulo non aggiornato quando si verifica un errore di convalida

class TestFormType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 

     $builder->add('thumbnail', 'hidden', array(
      'label' => 'Thumbnail', 
      'label_attr' => array(
       'class' => 'col-xs-2 control-label' 
      ), 
      'required' => false, 
      'error_bubbling' => true, 
      'required' => false 
     )); 

     $builder->add('thumbnail_data', 'file', array(
      'error_bubbling' => true, 
      'required' => false 
     )); 
    } 

    public function setDefaultOptions(\Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'X\LibraryBundle\Entity\Test', 
      'cascade_validation' => true, 
      'error_bubbling' => true, 
     )); 

    } 

    public function getName() 
    { 
     return 'test'; 
    } 
} 

Ecco l'entità, parte importante è il metodo setThumbnailData ($ file), che memorizza il file delle miniature e imposta la miniatura percorso tramite il metodo setThumbnail (stringa).

<?php 

namespace X\LibraryBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* Test 
* 
* @ORM\Table(name="test") 
* @ORM\Entity(repositoryClass="X\LibraryBundle\Repository\TestRepository") 
*/ 
class Test 
{ 
    /** 
    * @ORM\Column(name="id", type="integer", nullable=false) 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * @ORM\Column(type="text", nullable=true) 
    */ 
    protected $thumbnail; 

    /** 
    * Set thumbnail 
    * 
    * @param string $thumbnail 
    * @return Test 
    */ 
    public function setThumbnail($thumbnail) 
    { 
     $this->thumbnail = $thumbnail; 

     return $this; 
    } 

    /** 
    * Get thumbnail 
    * 
    * @return string 
    */ 
    public function getThumbnail() 
    { 
     return $this->thumbnail; 
    } 

    /** 
    * This will save file to disk 
    * @param $file 
    */ 
    public function setThumbnailData($file) { 
     if($file !== null && $file !== false) 
     { 
      $fileName = $file->getClientOriginalName(); 
      $baseDir = __DIR__ . '/../../../../../../../web/uploads/promotional_material/'; 
      $dir = sha1(microtime()); 
      while (is_dir($baseDir . $dir)) { 
       $dir = sha1(microtime()); 
      } 
      mkdir($baseDir . $dir); 
      $this->setThumbnail('/uploads/promotional_material/' . $dir . '/' . $fileName); 
      $file->move($baseDir . $dir, $fileName); 
     } 
    } 

    public function getThumbnailData() { 
     return ''; 
    } 
} 

Ora il problema è, se il modulo si imbatte in un errore di convalida, le seguenti linee ramoscello produrre output diverso, il valore corretto in uscita dalla seconda linea, l'altro produce miniatura del tracciato originale. Quindi, se produco l'input della miniatura usando {{form_widget (form.thumbnail)}}, ottengo il percorso della miniatura originale, non quello che dovrebbe essere cambiato tramite il metodo setThumbnailData().

{{ dump(form.thumbnail.vars.data) }} 
{{ dump(form.vars.data.thumbnail) }} 

Il problema è causato dall'impostazione della miniatura utilizzando il metodo setThumbnailData()? Non sei sicuro di come risolvere questo problema diverso da quello duro codifica l'ingresso in ramoscello in questo modo:

<input type="hidden" name="test[thumbnail]" value="{{ form.vars.value.thumbnail }}"/> 

risposta

5

non posso esattamente risolvere il problema, perché a mio parere si sta facendo nel modo sbagliato. Una classe di dati è in realtà solo in modo responsabile per la conservazione dei dati, in modo che il metodo di set/getThumbnailData dovrebbe assomigliare a questa

<?php 
// ... 
private $thumbnailData; 

public function setThumbnailData(UploadedFile $thumbnailData) { 
    $this->thumbnailData = $thumbnailData; 
} 

public function getThumbnailData() { 
    return $this->thumbnailData; 
} 

Nel vostro controller si dispone di qualcosa come questo:

<?php 
// ... 
public function formAction() { 

    $form = // ... 
    $form->handleRequest($request); 
    if($form->isValid()) { 
     $test = $form->getData(); 
     /* @var $test Test */ 
     $thumbnailUploader = $this->get('thumbnail_uploader'); 
     /* @var $thumbnailUploader ThumbnailUploadService */ 

     $file = $test->getThumbnailData(); 
     $filename = $file->getClientOriginalName(); 
     $thumbnailUploader->upload($filename, $file); 

     // ... 
    } 
} 

vi consiglio di spostare ogni logica che non ha nulla a che fare con forme o richieste in servizi. Il tuo servizio in questo caso può essere più generico per gestire i file symfony con un determinato nome file.

<?php 
class ThumbnailUploadService { 
    /** 
    * @param $file Symfony\Component\HttpFoundation\File\File 
    * 
    */ 
    public function upload($filename, File $file) { 
     // ... 
    } 
} 
+0

Bene, voglio salvare il file sul disco anche se fallisce la convalida, quindi l'utente non deve ri-caricare l'immagine se dovesse verificarsi un errore di convalida. – Trololololol

+0

Quindi creare un nuovo 'Type' e' Validator' renderlo perfettamente compatibile con il framework del modulo di symfony, magari con un campo 'file' e' hidden' come tipi figlio. Se si salva il file su disco, cosa succede se l'utente non inserisce mai dati validi? – Aitch

0

Inoltre c'è un altro modo utilizzando callback. Qui ti do una classe generica per caricare l'immagine e generare le miniature. Spero che questo lavoro per te. Questa classe gestisce i file generati automaticamente quando si crea un aggiornamento o si cancella l'entità.

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert; 
use Symfony\Component\HttpFoundation\File\UploadedFile; 
use Symfony\Component\Validator\Constraints as Assert; 
use App\MyBundleBundle\Util\Util; 

/** 
* Image 
* 
* @ORM\Table(name="image") 
* @ORM\Entity() 
* @ORM\HasLifecycleCallbacks 
*/ 
class Image 
{ 

    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    * 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="name", type="string") 
    * @Assert\NotBlank() 
    */ 
    private $name; 


    private $temp; 

    /** 
    * @ORM\Column(type="string", length=255) 
    */ 
    protected $path; 

    /** 
    * @Assert\Image(maxSize="5M") 
    */ 
    private $file; 

    /** 
    * Sets file. 
    * 
    * @param UploadedFile $file 
    */ 
    public function setFile(UploadedFile $file = null) 
    { 
     $this->file= $file; 

     if (isset($this->path)) { 
      $this->temp = $this->path; 
      $this->path= null; 
     } else { 
      $this->path= 'initial'; 
     } 
    } 

    /** 
    * Get file. 
    * 
    * @return UploadedFile 
    */ 
    public function getFile() 
    { 
     return $this->file; 
    } 

    /** 
    * @ORM\PrePersist() 
    * @ORM\PreUpdate() 
    */ 
    public function preUpload() 
    { 
     if (null !== $this->getFile()) { 
      // do whatever you want to generate a unique name 
      $filename = Util::getSlug($this->name) . uniqid() . '.' . $this->file->guessExtension(); 
      $this->path = $filename; 
     } 
    } 

    /** 
    * @ORM\PostPersist() 
    * @ORM\PostUpdate() 
    */ 
    public function upload() 
    { 
     if (null === $this->getFile()) { 
      return; 
     } 

     $this->getFile()->move($this->getUploadRootDir(), $this->path); 
     if (isset($this->temp)) { 
      if (file_exists($this->getUploadRootDir() .'/'. $this->temp)) { 
       unlink($this->getUploadRootDir() . '/' . $this->temp); 
      } 
      $this->temp = null; 
     } 
     $this->file= null; 
     //create a dir to save de thumbnails 
     if (!file_exists($this->getUploadRootDir() . '/thumbnails')) { 
      mkdir($this->getUploadRootDir() . '/thumbnails'); 
     } 

     //call a method in util class to generate the thumbnails 
     Util::redim($this->getUploadRootDir() . '/' . $this->path, $this->getUploadRootDir() . '/thumbnails/' . $this->path, 128, 128); 
    } 

    /** 
    * @ORM\PostRemove() 
    */ 
    public function removeUpload() 
    { 
     //This is to remove the files when the entity is delete 
     if ($file = $this->getAbsolutePath()) { 
      if (file_exists($file)) { 
       unlink($file); 
       $thumb = $this->getUploadRootDir() . '/thumbnails/' . $this->getPath(); 
       if (file_exists($thumb)) { 
        unlink($thumb); 
       } 
      } 
     } 
    } 

    public function getAbsolutePath() 
    { 
     return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path; 
    } 

    public function getWebPath() 
    { 
     return null === $this->path? null : 
      $this->getUploadDir() . '/' . $this->path; 
    } 

    protected function getUploadRootDir() 
    { 
     return $this->getUploadDir(); 
    } 

    protected function getUploadDir() 
    { 
     return 'uploads/image/'; 
    } 

    /** 
    * Get id 
    * 
    * @return integer 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

    /** 
    * Set nombre 
    * 
    * @param string $name 
    * @return Image 
    */ 
    public function setName($name) 
    { 
     $this->name= $name; 

     return $this; 
    } 

    /** 
    * Get nombre 
    * 
    * @return string 
    */ 
    public function getName() 
    { 
     return $this->name; 
    } 


    /** 
    * Set path 
    * 
    * @param string $path 
    * @return Imagen 
    */ 
    public function setPath($path) 
    { 
     $this->path= $path; 

     return $this; 
    } 

    /** 
    * Get path 
    * 
    * @return string 
    */ 
    public function getPath() 
    { 
     return $this->path; 
    } 

    public function __toString() 
    { 
     return $this->getName(); 
    } 
} 
Problemi correlati