Lastimosamente para lo que tenia pensado era demasiado...
Lo que deseaba hacer es subir varias imágenes cuando se enviaba el formulario, para esto se necesita un campo de tipo "file", pero solo se puede subir uno a la vez como explica el Cookbook
En este caso se necesita un array de campos "file". Para esto en nuestro Entity se define un atributo de tipo array:
<?php
//////Unidad.php
/**
* @var array
*/
public $imagenes;
//////
?>
Ahora para el Type:
///////UnidadType.php
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('imagenes', 'collection', array(
'type' => 'file',
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'options'=>array(
'required' => false,
'attr' => array('class' => 'unidades'),
{
$builder
->add('imagenes', 'collection', array(
'type' => 'file',
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'options'=>array(
'required' => false,
'attr' => array('class' => 'unidades'),
)));
}
}
Como se puede ver, se define como 'collection' el tipo de datos para la variable $imagenes. La opcion prototype nos permite tener en el formulario el texto HTML del campo generado (en este caso el campo file); se genera algo como esto:
<div><label class="unidades" for="unidad_imagenes_$$name$$">$$name$$</label><input type="file" id="unidad_imagenes_$$name$$" name="unidad[imagenes][$$name$$]" class="unidades" /></div>
jQuery('#agregar_campo_file').click(function(e) {
e.preventDefault();
var files = jQuery('#unidad_imagenes');
var newWidget = files.attr('data-prototype');
newWidget = newWidget.replace(/\$\$name\$\$/g, files);
$('#unidad_imagenes').append(newWidget);
files++;
return false;
});
var files = jQuery('#unidad_imagenes');
var newWidget = files.attr('data-prototype');
newWidget = newWidget.replace(/\$\$name\$\$/g, files);
$('#unidad_imagenes').append(newWidget);
files++;
return false;
});
Dentro del HTML debemos tener un link:
<a href="#" id="agregar_campo_file">Agregar Imagen</a>
Al hacer clic sobre el enlace se iran agregando campos 'file' al formulario.
En la plantilla TWIG para el formulario de envio se debe incluir la etiqueta "form_enctype" para poder enviar los archivos.
Hasta aquí podemos enviar los archivos al servidor, pero estos archivos no están siendo almacenados. Es necesario utilizar las funciones para el tipo 'file' como "move". Con esta función se puede almacenar los archivos subidos en alguna carpeta dentro del servidor.
Esta gestión es realizada por una función dentro de la Entidad y debe ser llamada antes de persistir el objeto:
if ($editForm->isValid()) {
$entity->uploadVarios();
$em->persist($entity);
$em->flush();
return $this->redirect(/* Generar tu URL */);
}
Como se puede ver, se hace un llamado a la función uploadVarios desde la entidad antes de persistirla.
Para tener una relacion entre las imagenes subidas y la entidad, definí un campo en la base de datos de tipo 'text' y es una array serializado que contiene el nombre de las imágenes almacenadas. Opté por esto (dato serializado) para no definir una nueva tabla en la base de datos que almacene un registro por cada imagen guardada.
/**
* @ORM\Column(type="text", nullable=true)
*/
public $path;
* @ORM\Column(type="text", nullable=true)
*/
public $path;
Este campo se actualiza dentro de la funcion uploadVarios de la Entidad. Al ser un dato serializado, se puede "des-serializar" y obtener un array con los nombres de las imagenes almacenadas anteriormente. De igual manera se puede agregar mas nombres y mantener los anteriores
La funcion uploadVarios se define como sigue:
public function uploadVarios()
{
$mypath = unserialize($this->path);
foreach ($this->imagenes as $key => $value) {
if ($value){
//Definir un nombre valido para el archivo
//Gedmo es una de las extensiones de Doctrine para Sluggable, Timestampable, etc
$nombre = \Gedmo\Sluggable\Util\Urlizer::urlize($value->getClientOriginalName(), '-');
//Verificar la extension para guardar la imagen
$extension = $value->guessExtension();
$extvalidas = array('JPG','JPEG','PNG','GIF');
if ( !in_array(strtoupper($extension), $extvalidas)){
return;
}
//Quitar la extension del nombre generado
//caso contrario el nombre queda algo como: miimagen-jpg
$nombre = str_replace('-'.$extension, '', $nombre);
//Nombre final con extension
//Queda algo como: miimagen.jpg
$nombreFinal = $nombre.'.'.$extension;
//Verificar si la imagen ya esta almacenada
if (@in_array($nombreFinal, $mypath)){
//si la imagen ya esta almacenada, se continua con el siguiente item
continue;
}
//Almacenar la imagen en el servidor
$value->move($this->getUploadRootDir(), $nombreFinal);
//Agregar el nuevo nombre al final del Array
$mypath[]= $nombreFinal;
}
}
$this->path = serialize($mypath);
$this->imagenes = array();
}
Las siguientes funciones se explican en el Cookbook y se utilizan para definir los directorios donde se almacenan los arhivos (van dentro del Entity):
protected function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
return 'uploads/documents';
}
Ahora cuando se suben varios archivos, la variable $path de mi base de datos queda algo asi:
a:3:{i:0;s:25:"claymore-wallpaper-09.jpg";i:1;s:11:"2lw20ro.jpg";i:2;s:38:"kawapaper-selain-0000096-1920x1200.jpg";}
Ahora ya se almacenan las imagenes en el servidor :)
Visualizar las Imágenes
Si queremos ver las imagenes almacenadas se necesita pasar un array con el nombre de las imagenes a la plantilla TWIG:
Si queremos ver las imagenes almacenadas se necesita pasar un array con el nombre de las imagenes a la plantilla TWIG:
public function editAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository(/*Reposritorio de tu Entity*/)->find($id);
return array(
'entity' => $entity,
'arrayimagenes' => unserialize($entity->getPath()),
);
}
Y en la plantilla se los visualiza de la siguiente manera:


Buenas, tengo una pregunta
ResponderEliminar¿donde esta el codigo donde enlazas el array de imagenes del formulario con tu entidad?
Un saludo,
Buen post
Hola balasobrebroadway, al definir en tu Entity un atributo:
ResponderEliminar/**
* @var array
*/
public $imagenes;
y si en el Type lo defines como 'collection',
->add('imagenes', 'collection', .......
esto es suficiente para que cualquier cosa que sea enviada dentro de este campo (collection) sea parte del Entity y este disponible como array. Es por esto que puedes manipular los datos como si fueran parte del Entity.
No necesitas mas código para enlazar los archivos enviados con tu Entity.
Espero que sea de tu ayuda.
Gracias por tu visita.
Estimado Gregorio,
ResponderEliminarbuena página, te felicito.
Saludos
Gracias Luizao por tu comentario.
EliminarHola, estoy intentando seguir lo que haces y creo que lo tengo todo igual. Pero cuando pulso sobre el botón submit de mi formulario me sale lo siguiente:
ResponderEliminarNo se pudo encontrar el archivo
¿Qué puede ser?
Hola Juanma, esto puede suceder si la ruta al archivo no es valida:
Eliminarhttp://gitnacho.github.com/symfony-docs-es/reference/constraints/File.html#notfoundmessage
Asegurate que la ruta a la imagen no contenga caracteres raros (espacios,"ñ", ").
Ademas asegurate que tienes permiso (escritura y lectura) tanto a la imagen que intentas subir, como al directorio web/ de tu aplicación
Antes de nada muchísimas gracias por responder, era que tenía una validación en la variable path de la entidad, la quite y ya funciona, pero ahora tengo otro problemilla.En mi formulario, lo relleno, sale lo de agregar las fotos(agrego por ejemplo 2) y le doy al botón de submit, y no salta ningún error, pero en la BD, el campo path no queda como pone en el tutorial me queda así :
ResponderEliminarPatch b:0;
Imagenes a:0:{}
...
No hace referencia a la foto, el cual tampoco se crea en
/web/uploads/images ...
y como pone aquí llamo antes de persistir a la función
$incidencia->uploadVarios();
$em = $this->getDoctrine()->getEntityManager();
$em->persist($incidencia);
$em->flush();
y lo he puesto todo siguiente este magnifico tutorial.. ¿Alguna idea de que puede ser?
Hola Juanma, mira la variable "imagenes" es un array que contiene las imágenes que subes, no tiene que ser serializado (ni tiene relación con la Base de Datos) es como una variable temporal para iterar cada una de las imágenes que subes.
EliminarFijate en esto:
/**
* @var array
*/
public $imagenes;
A diferencia de la variable path:
/**
* @ORM\Column(type="text", nullable=true)
*/
public $path;
Cuando subes imagenes, cada una esta almacenada en la variable $imagenes, esto debido a que en el formulario se pasa este campo en el
FormBuider del UnidadType:
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('imagenes', 'collection', array(
'type' => 'file',
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'options'=>array(
'required' => false,
'attr' => array('class' => 'unidades'),
)));
}
Fijate que la variable que pasas en el FormBuilder sea "imagenes" o la variable que tengas asociada como array en tu entidad.
Saludos.
Hola, hice el cambio que me comentaste, ahora ya en mi BD, no aparece el campo imagenes, solo path,pero sigue pasando lo mismo, no se guarda la imagen en web/images, ni tampoco en el campo path de la BD se guarda el nombre... solo se guarda b:0; , que no se que significa, nunca he serializado nada, e igual ahí esta el problema, aunque el hecho de que no se me guarde la foto en la carpeta... no tiene nada que ver con serializar...no? Una pregunta en mi entidad, tendría que poner que implementa a \Serializable ?? o alguna otra cosa, por si el fallo es de eso. Como siempre gracias por intentar ayudarme
ResponderEliminarPara entenderlo mejor puedes verlo aqui...
ResponderEliminarEl atributo imagenes, lo he llamado archivos ..
https://github.com/ReyDoz/Vecinos2.0/blob/master/src/Vecinos/IncidenciaBundle/Entity/Incidencia.php
Aquí esta el build form, que es igual que el que pones ..
https://github.com/ReyDoz/Vecinos2.0/blob/master/src/Vecinos/IncidenciaBundle/Form/Frontend/IncidenciaType.php
Y este es el controlador donde se llama a uploadVarios()
https://github.com/ReyDoz/Vecinos2.0/blob/master/src/Vecinos/IncidenciaBundle/Controller/DefaultController.php
Grep Villalba me podrías mostrar tu vista twig del formulario? Tenía el mismo problema que el compañero de arriba y lo he solucionado siguiendo esto: http://gitnacho.github.com/symfony-docs-es/reference/forms/types/collection.html#agregando-y-quitando-elementos
ResponderEliminarPero me gustaría saber como tienes tu vista twig del formulario para que me quede más claro.
Gracias por el aporte
ResponderEliminarHola estoy haciendo pruebas pero me serviría mucho ver el Type y la entidad para guiarme por ello te pido el gran favor que me ayudes con eso! :)...
ResponderEliminar