28
Abr

En este artículo mostraré una implementación del plugin sfThumbnailPlugin para redimensionar imágenes. Idealmente usado para la creación de las previsualizaciones de fotografías en nuestros sitios web.

Lo necesario:

  1. Instalar el plugin sfThumbnailPlugin
    symfony plugin:install sfThumbnailPlugin
  2. Tener configurada la BD, y el modelo implementado previamente con al menos un campo para guardar imágenes varchar(50).
  3. Tener un módulo creado con el “Admin generator” de Symfony

Procedimiento

Primero, configuraremos el formulario en la clase correspondiente. Tomaré por ejemplo un módulo para subir noticias a un sitio web.

Widget

Usaremos el widget para subir archivo editable sfWidgetFormInputFileEditable, ya que este nos permite mostrar la imagen que se ha subido además de dar la opción de eliminarla cuando existe.

NoticiaForm.class.php

$this->widgetSchema['imagen'] = new sfWidgetFormInputFileEditable(array(
   'label'     => 'Imagen Principal',
   'file_src'  => '/uploads/noticias/thumbs/'.$this->getObject()->getImagen(),
   'is_image'  => true,
   'edit_mode' => !$this->isNew(),
   'template'  => '<div>%file%<br /><label></label>%input%<br /><label></label>%delete% Eliminar imagen actual</div>',
));

Explicación de lo anterior:

  • Label nos permite modificar la etiqueta del campo en el formulario.
  • File_src provee la ruta a la imagen ya subida, para mostrarla.
  • Is_image, si no me equivoco le permite a Symfony conocer que estamos trabajando con una imagen (si alguien sabe su utilidad, comente).
  • Edit_mode hace que la imagen sólo se muestre una vez que hayamos creado el registro, por ende cuando se ha subido ya algo.
  • Template, es el formato con el que queremos mostrar la previsualización de la imagen.

Validator

El validador es el que finalmente sube y guarda la imagen, por lo tanto es donde debemos usar el plugin sfThumbnailPlugin.

NoticiaForm.class.php

$this->validatorSchema['imagen'] = new sfValidatorFile(array(
   'required'   => false,
   'mime_types' => 'web_images',
   'path' => sfConfig::get('sf_upload_dir').'/noticias/original',
   'validated_file_class' => 'sfResizedFile',
));

Explicación.

  • Required, ya sabemos.
  • Mime_types permite decir qué archivos se pueden subir, los que son permitidos, en este caso sólo imágenes.
  • Path es usado para indicar la ruta donde queremos que se guarden las imágenes (de tamaño original, o ampliado).
  • Validated_file_class es el parámetro importante aquí, nos permite decir que usaremos una clase propia para manejar la imagen subida.

sfResizedFile es una clase nueva, la cual obtuve desde el Foro de Symfony. Créditos para malas.

/lib/sfResizedFile.class.php

/**
 * sfResizedFile represents a resized uploaded file.
 *
 * @package    symfony
 * @subpackage validator
 * @author     Malas
 * @version    0.1
 */
class sfResizedFile extends sfValidatedFile
{

	/**
	 * Saves the uploaded file.
	 *
	 * This method can throw exceptions if there is a problem when saving the file.
	 *
	 * If you don't pass a file name, it will be generated by the generateFilename method.
	 * This will only work if you have passed a path when initializing this instance.
	 *
	 * @param  string $file      The file path to save the file
	 * @param  int    $fileMode  The octal mode to use for the new file
	 * @param  bool   $create    Indicates that we should make the directory before moving the file
	 * @param  int    $dirMode   The octal mode to use when creating the directory
	 *
	 * @return string The filename without the $this->path prefix
	 *
	 * @throws Exception
	 */
	public function save($file = null, $fileMode = 0666, $create = true, $dirMode = 0777)
	{
		if (is_null($file))
		{
			$file = $this->generateFilename();
		}

		if ($file[0] != '/' && $file[0] != '\\' && !(strlen($file) > 3 && ctype_alpha($file[0]) && $file[1] == ':' && ($file[2] == '\\' || $file[2] == '/')))
		{
			if (is_null($this->path))
			{
				throw new RuntimeException('You must give a "path" when you give a relative file name.');
			}

			$smallFile = $this->path.DIRECTORY_SEPARATOR.'s_'.$file;
			$file = $this->path.DIRECTORY_SEPARATOR.$file;
		}

		// get our directory path from the destination filename
		$directory = dirname($file);
		if (!is_readable($directory))
		{
			if ($create && !mkdir($directory, $dirMode, true))
			{
				// failed to create the directory
				throw new Exception(sprintf('Failed to create file upload directory "%s".', $directory));
			}

			// chmod the directory since it doesn't seem to work on recursive paths
			chmod($directory, $dirMode);
		}
		if (!is_dir($directory))
		{
			// the directory path exists but it's not a directory
			throw new Exception(sprintf('File upload path "%s" exists, but is not a directory.', $directory));
		}
		if (!is_writable($directory))
		{
			// the directory isn't writable
			throw new Exception(sprintf('File upload path "%s" is not writable.', $directory));
		}

		// copy the temp file to the destination file
		$thumbnail = new sfThumbnail(100, 100, true, true, 85, 'sfGDAdapterCuttingOff');
		$thumbnail->loadFile($this->getTempName());
		$thumbnail->save($smallFile, 'image/jpeg');

		$thumbnail = new sfThumbnail(400, 400, true, true, 85, 'sfGDAdapter');
		$thumbnail->loadFile($this->getTempName());
		$thumbnail->save($file, 'image/jpeg');

		// chmod our file
		chmod($smallFile, $fileMode);
		chmod($file, $fileMode);

		$this->savedName = $file;
		return is_null($this->path) ? $file : str_replace($this->path.DIRECTORY_SEPARATOR, '', $file);
	}

}

Para crear nuestros thumbnails, solo sebemos agregar cada uno como se muestra en negrita:

$thumbnail = new sfThumbnail ($maxWidth = null, $maxHeight = null, $scale = true, $inflate = true, $quality = 75, $adapterClass = null, $adapterOptions = array())

Si necesitamos 5 tamaños diferente, debemos agregar 5 veces la creación y guardado de un objeto sfThumbnail.

Finalmente, limpiar la cache del proyecto y probar cómo funciona el redimensionado de imágenes.

NOTA: Si aparece el error de que no existe sfGDAdapterCuttingOff, simplemente eliminar esa declaración. Se debe a que no está completamente instalado GD. En mi caso funcionó sin necesidad de usar ese parámetro.

Visto en Foro de Symfony

, , , ,

110 Responses to “sfThumbnailPlugin y Admin Generator: redimensionar imágenes”

  • Omar

    Hice todo lo indicado y me apareció el error que mencionas al final de que no existe sfGDAdapterCuttingOff y no se que parámetro es el que debo eliminar. Despúes de eso eliminando algunos parámetros del método del constructor logré que me guardara la imagen original y el thumbnail, pero me lo guardan en una misma carpeta. Y por último no se como mostrar el thumbnail en una página.

    • Omar,

      Para lo del error. La declaracion deberia quedar asi:

      $thumbnail = new sfThumbnail(100, 100, true, true, 85);

      Respecto a lo de guardarlo en otra carpeta. En la clase sfResizedFile, busca lo siguiente:

      $smallFile = $this->path.DIRECTORY_SEPARATOR.’s_’.$file;
      $file = $this->path.DIRECTORY_SEPARATOR.$file;

      Ahi estas definiendo el path. En este caso, sale en la misma carpeta, pero le agrega un “s_” al nombre. Puedes hacer algo como:

      $smallFile = $this->path.DIRECTORY_SEPARATOR.’miniaturas’.DIRECTORY_SEPARATOR.$file;

      Y para mostrar la imagen en la pagina:

      image_tag(‘/uploads/PATH/miniaturas/’.$objeto->getImagen()

      Espero haberte orientado y no confundido mas jejeje.

      • omar

        disculpa pero el problema es que no se donde poner esa linea

        $thumbnail = new sfThumbnail(100, 100, true, true, 85);

        yo hice todo lo que tu indicas hasta la parte que hay que crear el thumbnail. y no puse la linea

        $thumbnail = new sfThumbnail(100, 100, true, true, 85);

        en ningun lugar y cuando lo probe que subi la imagen me dio ese error que tu mencionastes, no existe sfGDAdapterCuttingOff, yo fui a la clase donde estaba el error o sea sfThumbnail.class.php linea 61 o sea el constructor

        $this->adapter = new $adapterClass($maxWidth, $maxHeight, $scale, $inflate, $quality, $adapterOptions);

        y cuando elimine esa linea me salieron 2 errores mas y entonces no se por fin que es lo que tengo que cambiar
        disculpa la molestia y gracias de antemano

        • Tranquilo. Mira.

          En el archivo /lib/sfResizedFile.class.php que creamos,
          busca esta linea (es lo que esta en este post mas arriba):

          // copy the temp file to the destination file
          $thumbnail = new sfThumbnail(100, 100, true, true, 85, ‘sfGDAdapterCuttingOff’);

          En esa linea, solo quita ‘sfGDAdapterCuttingOff’, si no te funciona, dejalo como sigue:

          $thumbnail = new sfThumbnail(100, 100, true, true, 85, ‘sfGDAdapter’);

          Si te fijas, solo estamos omitiendo o cambiando el parametro $adapterOptions de la linea en la que PHP encuentra el error, pero que en realidad no es donde se produce.

          Saludos.

  • omar

    muchisimas gracias funciono perfectamente. Si no es mucha
    molestia tambien necesito ayuda con una funcion para imprimir un prestamo (un modulo de mi aplicacion) y no se como mandarlo a imprimir, me recomendaron el sfTCPDFplugin
    pero a lo mejor tu sabes alguna manera de hacerlo o conoces de algun foro donde postear mis dudas.
    de nuevo muchisimas gracias hermano

  • Aun no he tenido que mandar a imprimir. Quiza si debas documentarte respecto al plugin sfTCPDFPlugin.
    Todas tus dudas puedes resolverlas en la comunidad en español de symfony, responden muy rapido:

    http://groups.google.com/group/symfony-es

    Saludos

  • ChikiCadiz

    Hola!! Ante todo gracias por tu aporte que me ha sido muy útil en cierta medida, y digo esto porque realmente lo que necesito es guardar dicha imagen en la base de datos donde residen los datos d emi aplicación. ¿Podrías ayudarme en cómo hacer esto?

    Saludos.

  • David

    Yo utilizo la librería:
    http://phpthumb.gxdlabs.com/

    que os la recomiendo. Con el plugin que trata me encontré con el problema que sólo podía cargar las imágenes loadFile mediante un argumento de tipo url web (http://www…)

  • Mimi

    Hola me da el siguiente error
    Fatal error: Class ‘sfResizedFile’ not found in /usr/share/pear/symfony/validator/sfValidatorFile.class.php on line 167

  • Mimi

    Bueno el error anterior se resolvio con esto $this->validatorSchema[‘imagen1_delete’] = new sfValidatorBoolean();

    imagen1 es el campo

  • jesus

    buenas david!!! mira tengo el siguente error:

    Fatal error: Class ‘sfResizedFile’ not found in C:\symfony-1.4.3\lib\validator\sfValidatorFile.class.php on line 167

    puede ser porke no generé el modulo con el “admin generator”??

    que puedo hacer para solucionarlo??

    gracias de antemano

    • jesus

      ui!! veo ke es el mismo error ke tubo mimi,,, pero no entiendo tu respuesta… ke codigo es el ke hay que introducir manualmente?? disculpa por las molestias!! jejeje

      • En el post se explica cómo crear los thumbnails con una clase denominada sfResizedFile, la cual no es una clase de Symfony, sino una que hay que crear.

        Es decir, el archivo /lib/sfResizedFile.class.php hay que crearlo y pegar el código que está en este mismo post.

        Lee completo primero para que entiendas la idea de lo que se está haciendo.

        Espero haberte ayudado.

        Saludos

        • jesus

          gracias eres un crak!!! el problema era ke en el directorio
          /lib/sfResizedFile.class.php no me encotraba la clase, he tenido que ponerla en /lib/from/doctrine/sfResizedFile.class.php y ahí si me la encuentra.(no se por ke sera…) pero bueno, problema solucionado… jejeje
          gracias por tu ayuda y por tus post!! ya te tengo en mis favoritos!!!

  • Gracias por tu aporte!!! Me ha sido de mucha ayuda.

  • Hay algo que me parece interesante agregar. Espero que este bien y que le sirva a alguien…
    Luego de agregar una imagen con otros tamaños ademas del original, intentaba eliminar las imagenes creadas, pero solamente se eliminaba la original. Entonces agregue el siguiente método en noticiaForm.class, luego del método config:

    public function doSave($con = null)
    {
    //si elimino la imagen con check
    if($this->getValue(‘nombrefoto_delete’))
    {
    $filename = $this->getObject()->getNombrefoto();

    //directorio de la imagen original
    $filepath = sfConfig::get(‘sf_upload_dir’).’/fotos/’.$filename;
    @unlink($filepath);

    //directorio de la imagen con tamaño distinto
    $thumbnailpath = sfConfig::get(‘sf_upload_dir’).’/fotos/miniatura/’.$filename;
    @unlink($thumbnailpath);

    $this->getObject()->setNombrefoto(null);
    }
    return parent::doSave($con);
    }

    ‘nombreFoto’ es el campo de la tabla que hace referencia a la imagen

    De esta manera no solo se elimina la imagen original,sino que también la/s de tamaño distinto.

  • Hola David, excelente tu Post! te hago una consulta. Soy un principiante de Symfony, pero quería saber si los thumbs no se podrían generar también en el doSave del form…
    Que opinas?
    Desde ya muchísimas gracias!
    Viva Symfony! la calidad y la simplicidad (que son parecidas jeje)

  • Juanan

    Hola,

    Esta solución es válida para la versión 1.4?

    No termino de encontrar documentación sobre este tema de subir imágenes con el admin generator.

    Gracias y saludos!

    • Juanan

      Dos cosas…..

      1.- Gracias por el aporte, que he ido al grano y te no he dado las gracias. Un post de gran utilidad.

      2.- Confirmo que funciona en la versión 1.4.4. No me estaba funcionando porque no me había dado cuenta que al copiar la definición de la clase sfResizedFile en el fichero….había machacado la etiqueta <?php

      Saludos y gracias de nuevo

  • Agustin Gutierrez

    Hola Queria saber como puedo hacer para que me muestre la imagen pequeña creada por el thumbnail. Primero probe poniendo en distintas carpetas, como explicaste en un comentario mas arriba pero me tira estos warning

    Warning: imagejpeg() [function.imagejpeg]: Unable to open ‘/home/agustin/web/i4d/web/uploads/images/original/thumbs/s_6e39981024a564bc7d222c1c4d2baff0d9bf7ddf.jpg’ for writing: No such file or directory in /home/agustin/web/i4d/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php on line 162

    Warning: chmod() [function.chmod]: No such file or directory in /home/agustin/web/i4d/lib/sfResizedFile.class.php on line 82

    Warning: Cannot modify header information – headers already sent by (output started at /home/agustin/web/i4d/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php:162) in /home/agustin/web/i4d/lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 357

    Warning: Cannot modify header information – headers already sent by (output started at /home/agustin/web/i4d/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php:162) in /home/agustin/web/i4d/lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 357

    Despues de ellos la ejecucion sigue normalmente, pero no me muestra las imagenes, ni las guarda
    Y ademas tampoco me anda el link eliminar imagen
    Gracias

  • Agustin Gutierrez

    Ejecute
    symfony project:permissions y me tira el siguiente error:
    SF_ROOT_DIR/web/uploads/images

  • Agustin Gutierrez

    Lo solucione guardando las dos imagenes en la misma carpeta, pero yo
    querria que se mostrara la imagen reducida, la que tiene el nombre
    s_….
    y no la de tamaño mas grande. Ademas queria ver como hacer para que el
    ‘template’ => ‘%file%%input%%delete% Eliminar imagen actual’, funcione ya
    que solo me aparece el texto pero no hace nada

  • ALIT07

    Gracias David, Sos un ´pro!

  • morper

    HOla¡
    quería saber como poder redimensionar las imagenes, pero que no cada una dependiendo del tamaño de la imagen original, se redimensione de un tamaño u otro, me gustaría que todas las imagenes, sean como sean, se me redimensionen con el tamaño 30×35, es posible???

  • Muchas gracias me sirvio de mucho!!! solo falto añadirle el validador del delete, en mi caso es el siguiente 😉

    $this->validatorSchema[‘avatarurl_delete’] = new sfValidatorPass();

  • Para poder eliminar todas las imagenes. Como ya mencionaron edite el metodo doSave en mi caso en la clase del formulario “class PatientExperienceForm extends BasePatientExperienceForm”

    public function doSave($con = null)
    {

    /*Delete*/
    if($this->getValue(‘avatar_url_delete’)){
    @unlink(sfConfig::get(‘sf_upload_dir’).’/images/patientexperience_preview/mini_’.$this->getObject()->getAvatarUrl());
    @unlink(sfConfig::get(‘sf_upload_dir’).’/images/patientexperience_preview/medium_’.$this->getObject()->getAvatarUrl());
    }
    /* Update */
    if($this->getValue(‘avatar_url’)){
    @unlink(sfConfig::get(‘sf_upload_dir’).’/images/patientexperience_preview/mini_’.$this->getObject()->getAvatarUrl());
    @unlink(sfConfig::get(‘sf_upload_dir’).’/images/patientexperience_preview/medium_’.$this->getObject()->getAvatarUrl());
    }
    return parent::doSave($con);
    }

  • I am really impressed with your writing skills as well as
    with the layout on your weblog. Is this a paid theme or
    did you modify it yourself? Anyway keep up the nice quality
    writing, it is rare to see a great blog like this one nowadays.

  • Hi outstanding website! Does running a blog such as this require a great deal of work?
    I have absolutely no understanding of computer programming however I had been hoping to start my own blog soon.
    Anyway, should you have any suggestions or techniques
    for new blog owners please share. I know this is off topic however I simply wanted to ask.
    Many thanks!

  • Amazing blog! Is your theme custom made or did you download
    it from somewhere? A theme like yours with a few simple adjustements would really make my blog shine.
    Please let me know where you got your theme. Many thanks

  • Hi there would you mind stating which blog platform you’re using?
    I’m going to start my own blog in the near future but I’m
    having a tough time deciding between BlogEngine/Wordpress/B2evolution and Drupal.
    The reason I ask is because your layout seems different then most blogs
    and I’m looking for something completely unique. P.S Apologies for getting off-topic
    but I had to ask!

  • Dіgamos que no estoy completamente deacuеrdo coon la forma en que se dice, ρerο no est
    mаl lo ԛue see diсe.Saludos 😉

  • Hi! I could have sworn I’ve been to this website before but
    after going through a few of the articles I realized it’s new to me.
    Anyhow, I’m certainly pleased I came across it and I’ll be bookmarking
    it and checking back often!

  • Bueno, nоo es que est del todo deacuerdo con еl texto, ssin
    embargo me parexe ƅien el trasfondo.Enhorabuena

  • The opening of these strategies for the best way to make money online for free with no scams and rather fast at that is to
    use a mini-work web site like Fiverr. You may be asking yourself how this is possible with just a blog.
    Most people fail to make money online because once they see all they have
    to learn and do, they are simply not willing to put in the effort to work that hard to educate themselves.

  • I was pretty pleased to discover this site. I need to to thank you
    for your time just for this wonderful read!! I definitely appreciated every little bit of it and
    i also have you book-marked to look at new information on your website.

  • Hello i am kavin, its my first time to commenting anyplace, when i read this
    piece of writing i thought i could also make comment due to this sensible article.

  • Very rapidly this site will be famous amid all blog viewers, due to it’s fastidious content

  • Thank you a bunch for sharing this with all folks you really know what you’re speaking approximately!

    Bookmarked. Kindly also visit my web site =). We may have a hyperlink change arrangement between
    us

  • whoah this blog is excellent i love reading your articles.
    Stay up the good work! You understand, lots of people are hunting round for this
    info, you could help them greatly.

  • What’s Taking place i’m new to this, I stumbled upon this I’ve found It positively useful
    and it has aided me out loads. I’m hoping to contribute & aid different customers like its helped me.
    Good job.

  • I am really loving the theme/design of your web
    site. Do you ever run into any web browser compatibility issues?
    A couple of my blog readers have complained about my site not working correctly in Explorer but looks
    great in Firefox. Do you have any ideas to help fix this issue?

  • This info is worth everyone’s attention. When can I find out more?

  • Excellent way of describing, and nice post to obtain information regarding my
    presentation subject matter, which i am going to deliver in institution of higher education.

  • I feel that is among the most significant info for me.
    And i’m satisfied reading your article. But wanna commentary on some general issues, The website taste
    is great, the articles is in reality great : D. Just right activity, cheers

  • Thank you for sharing your info. I really appreciate your efforts and I
    am waiting for your further write ups thanks once again.

  • We are a group of volunteers and starting a brand new scheme in our community.

    Your web site provided us with helpful helpful and paintings
    on . You have a formidable process and our all the neighborhood be thankful to you
    .
    Definitely believe that you stated . Your favorite justification appeared to
    be on the web easy thing to bear in mind remember of .
    I tell you , i certainly get annoyed think worries clear
    that just do not recognize about . You controlled perfectly as out on all managed to hit the nail
    on the top without having side effect , others cAN could take a signal.
    Will probably be again to get more. Thanks

  • Thanks for sharing your thoughts on virtual dating.
    Regards

    • Sunt de acord cu soaDrloiul.pragos, nu trebuie sa fie la fel de rapid ca opera, ci doar mai rapid si mult mai sigurSirGod poate chiar IE 9 reprezinta un fel de vista, adica cel mai mare esec:) Bine, IE6 e greu de depasit la capitolul acesta

  • Hey there! I just wanted to ask if you ever have any problems
    with hackers? My last blog (wordpress) was
    hacked and I ended up losing many months of hard work due to no backup.
    Do you have any solutions to stop hackers?

  • As already mentioned, the risk of these human growth hormone side effects
    grows with the amount of HGH given, but over time, the damage can be serious and irreversible.
    In this way, the number of loyal customers of Genf20 is increasing by each passing day.
    There would be a decrease in muscle mass and more fat deposited around the waistline.

  • It is also offered in the type of a supplement- capsules
    and powders. Carnitine- Here is another amino acid that has the
    ability to aid sperm in it’s motility. This is normal and most men do not notice any great
    difference or suffer any physical consequences due to lowered testosterone levels.

  • Wow, marvelous weblog format! How lengthy have you been running a blog for?
    you made blogging look easy. The whole glance of your site is magnificent, let alone the content material!

  • Asking questions are truly fastidious thing if you are not understanding anything entirely, however this article gives fastidious understanding yet.

  • Cufrently it appears like Expression Engine is the preferred blogging platform out there right now.

    (from what I’ve read) Is that what you’re using on your
    blog?

  • I really like your blog.. very nice colors & theme. Did you create this website yourself
    oor did you hire someone to do iit for you? Plz respond
    as I’m looking to create my ownn blog and would like to know where u got
    this from. cheers

    • Eu sempre compro na magazine Luiza com o meu cartão de credito mas estou um cartão de credito da propia loja porque fui senpre bem atendido por todos os verodednes nota.10

  • We are a group of volunteers and starting a
    new scheme in our community. Your site offered us
    wiith valuable information to work on. You’ve doe an impressive job and our entire community will be thankful to
    you.

  • An outstanding share! I have just forwarded this onto a colleague who was
    doing a little homework on this. And he in fact bought me breakfast smply because I stumbled upon it for him…

    lol. So let me reword this…. Thanks for the meal!! But yeah,
    thanks for spending time to discuss this topic here on your blog.

  • Juanan

    Otra pregunta…..

    Como se puede hacer para que se guarde el fichero que se sube con su nombre original?

    Gracias

Add reply