Hoy traigo un pequeño CODEKATA sobre una consulta que me ha hecho un lector. Se trata de unos códigos fuentes en Symfony 4 para subir ficheros al servidor, pero sin usar ningún componente extra en el proyecto.
Se trata de unas pocas modificaciones que le he hecho al código fuente de ejemplo de la documentación oficial. Así el código dejará de chequear la extensión, el mime type del fichero, y además de que no renombra los ficheros con un identificador único. Esto puede tener doble filo porque puedes acabar machacando los ficheros en nuevas subidas, pero siempre se le puede añadir después la lógica necesaria para comprobar si el fichero ya existía.. 😉
Al grano, el código de la entidad
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass="App\Repository\MyDownloadableFileRepository")
*/
class MyDownloadableFile
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $title;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $description;
/**
* @ORM\Column(type="string")
*
* @Assert\NotBlank(message="Please, upload the file.")
*/
private $filename;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(?string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getFilename()
{
return $this->filename;
}
public function setFilename($filename)
{
$this->filename = $filename;
return $this;
}
}
El código del formulario
<?php
namespace App\Form;
use App\Entity\MyDownloadableFile;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class MyDownloadableFileType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('description')
->add('filename', FileType::class, ['label' => 'The file'])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => MyDownloadableFile::class,
]);
}
}
El código de la función para crear nueva entidad subiendo el fichero
/**
* @Route("/new", name="my_downloadable_file_new", methods={"GET","POST"})
*/
public function new(Request $request)
{
$myDownloadableFile = new MyDownloadableFile();
$form = $this->createForm(MyDownloadableFileType::class, $myDownloadableFile);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$file = $myDownloadableFile->getFilename();
//$fileName = md5(uniqid()).'.'.$file->guessExtension();
try {
$file->move(
'uploads/',
$file->getClientOriginalName()
);
} catch (FileException $e) {
// handle exception..
}
$myDownloadableFile->setFilename($file->getClientOriginalName());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($myDownloadableFile);
$entityManager->flush();
return $this->redirect($this->generateUrl('my_downloadable_file_index'));
}
return $this->render('my_downloadable_file/new.html.twig', [
'form' => $form->createView(),
]);
}
Queda en el tintero el poder editar o borrar los ficheros ya subidos. Falta la lógica en los controladores, pero eso ya es material para otro post..
Unas explicaciones y terminando
Cuidado con el nombre que le he puesto a la cadena de texto que guarda el nombre del fichero, filename. Porque en el formulario realmente es un input de tipo fichero, aunque sea una cadena de texto en la entidad para la base de datos.
¡OJO! Otra cosa, con los ficheros ejecutables de widows, dlls, o ficheros así.. me he encontrado con que la función guessExtension() devuelve valor nulo. Pero el código modificado de arriba te funcionará si es lo que necesitas.
Sólo me queda remitirme a la documentación oficial:
https://symfony.com/doc/current/controller/upload_file.html
Espero que sirva. ¡Un saludo!