
Como hago en symfony?
Symfony es un excelente framework de php, en ocasiones estamos desarrollando y necesitamos hacer algo y entonces le preguntamos a Google: como hago "esto" en symfony.
En este articulo, compuesto por varias versiones, iré poniendo algunas cosas que he ido recopilando que pueden ser utilizadas por muchos y podríamos guardar por si un día lo necesitamos.
Obtener el ip del Cliente:
El framework Symfony es ampliamente utilizado para construir aplicaciones web robustas y escalables. En muchos escenarios, es fundamental obtener la dirección IP del cliente por diversas razones, como:
En este articulo, compuesto por varias versiones, iré poniendo algunas cosas que he ido recopilando que pueden ser utilizadas por muchos y podríamos guardar por si un día lo necesitamos.
Obtener el ip del Cliente:
El framework Symfony es ampliamente utilizado para construir aplicaciones web robustas y escalables. En muchos escenarios, es fundamental obtener la dirección IP del cliente por diversas razones, como:
- Rastrear actividades de usuarios.
- Implementar medidas de seguridad.
- Personalizar la experiencia del usuario.
- Desde el controlador
<?php namespace App\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; class TestController { #[Route('/')] public function index(Request $request): Response { $ip = $request->getClientIp(); return new Response($ip); } }
- Desde un servicio
<?php namespace App\Service; use Symfony\Component\HttpFoundation\RequestStack; class TestService { public function __construct(private RequestStack $requestStack) { } public function process(): void { $ip = $this->requestStack->getCurrentRequest()?->getClientIp(); } }
- Desde Twig:
{{ app.request.clientIp }}
Cómo verificar si una plantilla Twig existe en Symfony 7
Al trabajar con una aplicación Symfony que utiliza nombres dinámicos de plantillas Twig, es esencial asegurarse de que estas plantillas existan en el sistema de archivos. Verificar si una plantilla Twig existe antes de intentar renderizarla ayuda a prevenir errores en tiempo de ejecución y ofrece una experiencia de usuario más robusta.
<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Twig\Environment; class TestController extends AbstractController { #[Route('/')] public function index(Environment $twig): Response { $loader = $twig->getLoader(); if (!$loader->exists('test/index.html.twig')) { return new Response('Twig template not exists'); } return new Response(); } }
Crear un slug:
En el desarrollo web, la construcción de URLs limpias y amigables para motores de búsqueda es un aspecto crucial para optimizar aplicaciones tanto para usuarios como para sistemas de búsqueda. El uso de caracteres Unicode en URLs se considera inseguro. Symfony ofrece el componente String, que permite convertir una cadena de texto en una versión modificada que solo contiene caracteres ASCII seguros.
Dentro de una aplicación Symfony, podemos inyectar SluggerInterface en un servicio o controlador. Al utilizar el método slug(), podemos convertir una cadena de texto en un slug seguro para URLs.
<?php namespace App\Controller; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\String\Slugger\SluggerInterface; class TestController { #[Route('/')] public function index(SluggerInterface $slugger): Response { $slug = $slugger->slug('symfony y php'); return new Response($slug); // symfony-y-php } }
Obtener el ejecutable de PHP
Al trabajar con una aplicación Symfony, existen situaciones en las que podemos necesitar ejecutar un script PHP externo. Sin embargo, para lograrlo, es crucial conocer la ruta del ejecutable de PHP. Symfony simplifica el proceso de encontrar la ubicación de este ejecutable, la cual puede variar según el entorno.
<?php require_once __DIR__.'/vendor/autoload.php'; use Symfony\Component\Process\PhpExecutableFinder; $finder = new PhpExecutableFinder(); $phpBinaryPath = $finder->find(); echo $phpBinaryPath; // /usr/bin/php
Ejecutar un comando desde otro en Symfony
Symfony ofrece el componente Console que permite a los desarrolladores crear y ejecutar comandos. En ciertos escenarios, puede ser necesario ejecutar un comando de consola desde otro comando. Esto es útil cuando un comando depende de otro o cuando se desea crear un comando compuesto para ejecutar varios comandos en conjunto.
<?php namespace App\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; #[AsCommand(name: 'app:demo')] class DemoCommand extends Command { protected function configure(): void { $this ->addArgument('username', InputArgument::REQUIRED) ->addOption('create'); } protected function execute(InputInterface $input, OutputInterface $output): int { $output->writeln($input->getArgument('username')); $output->writeln($input->getOption('create')); return Command::SUCCESS; } }
<?php //ejecutar el command DemoCommand namespace App\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; #[AsCommand(name: 'app:test')] class TestCommand extends Command { protected function execute(InputInterface $input, OutputInterface $output): int { $cmdInput = new ArrayInput([ 'command' => 'app:demo', 'username' => 'john', '--create' => true, ]); $returnCode = $this->getApplication()?->doRun($cmdInput, $output); $output->writeln($returnCode); return Command::SUCCESS; } }
Evitar que se ejecute mas de un comando a la vez:
El componente Console de Symfony es una herramienta potente para construir aplicaciones de línea de comandos en PHP. Sin embargo, existen escenarios en los que es necesario garantizar que un comando de consola específico no se ejecute múltiples veces de forma concurrente. Esto es especialmente crucial cuando un comando realiza operaciones críticas o modifica el estado de la aplicación.
<?php namespace App\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\LockableTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; #[AsCommand(name: 'app:test')] class TestCommand extends Command { use LockableTrait; protected function execute(InputInterface $input, OutputInterface $output): int { if (!$this->lock()) { $output->writeln('The command is already running within a different process.'); return Command::SUCCESS; } sleep(5); $output->writeln('Long-running task done.'); return Command::SUCCESS; } }
Obtener el directorio del proyecto
Symfony ofrece diversas características y mejoras para agilizar el proceso de desarrollo. Un requisito frecuente durante el desarrollo con Symfony es la necesidad de acceder dinámicamente al directorio del proyecto desde el código. Esto puede ser útil para ubicar archivos, configurar servicios u otras tareas relacionadas.
Controlador 1: Cuando el controlador extiende de AbstractController
<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; class TestController extends AbstractController { #[Route('/')] public function index(): Response { $dir = $this->getParameter('kernel.project_dir'); return new Response($dir); } }
Controlador 2: En algunos casos no extendemos el controlador de AbstractController, por lo cual podemos usar el atributo Autowire
<?php namespace App\Controller; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; class TestController { public function __construct(#[Autowire('%kernel.project_dir%')] private string $dir) { } #[Route('/')] public function index(): Response { return new Response($this->dir); } }
Servicio: En ocasiones lo necesitamos desde un servicio, e igual usamos el atributo Autowire
<?php namespace App\Service; use Symfony\Component\DependencyInjection\Attribute\Autowire; class TestService { public function __construct(#[Autowire('%kernel.project_dir%')] private string $dir) { } }
Generar hash de contraseñas usando un comando de consola
Symfony ofrece múltiples comandos predefinidos diseñados para ayudar en los procesos de desarrollo y pruebas. Entre estos comandos, existe uno integrado específicamente para generar hashes de contraseñas según la configuración de seguridad. Esto puede ser útil al configurar la autenticación de usuarios en memoria o actualizar contraseñas almacenadas en la base de datos durante la fase de desarrollo de la aplicación.
php bin/console security:hash-password pwd123
Obtendremos algo como esto:
--------------- -----------------------------------------------------------------
Key Value
--------------- -----------------------------------------------------------------
Hasher used Symfony\Component\PasswordHasher\Hasher\MigratingPasswordHasher
Password hash $2y$13$nx3NLGjxKnO42KNdKCQR3ek9P3UpolB0yhGmY3Gic9LLfAo24BIBC
--------------- -----------------------------------------------------------------
! [NOTE] Self-salting hasher used: the hasher generated its own built-in salt.
Comprobar si existe una ruta
Al desarrollar una aplicación web, podemos necesitar verificar si una ruta existe. .
Podemos inyectar la dependencia UrlGeneratorInterface en un controlador o servicio para generar una URL o ruta para un nombre de ruta específico. El método generate lanza una excepción RouteNotFoundException si la ruta no existe. Podemos capturar esta excepción y realizar la acción correspondiente.
<?php namespace App\Controller; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Exception\RouteNotFoundException; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class TestController { #[Route('/')] public function index(UrlGeneratorInterface $urlGenerator): Response { try { $url = $urlGenerator->generate('wrong'); } catch (RouteNotFoundException) { return new Response('Route not exists'); } return new Response($url); } }
Bloquear acceso por dirección IP
En algunas aplicaciones, puede ser necesario bloquear el acceso al sitio web para ciertos usuarios mediante su dirección IP. En tales casos, se puede utilizar una lista negra de IPs para filtrar direcciones IP maliciosas y evitar que accedan al sitio.
1. Configurar la lista negra de IPs:
En el archivo .env, agrega una nueva variable de entorno IP_BLACKLIST que contenga las direcciones IP bloqueadas, separadas por comas.
En algunas aplicaciones, puede ser necesario bloquear el acceso al sitio web para ciertos usuarios mediante su dirección IP. En tales casos, se puede utilizar una lista negra de IPs para filtrar direcciones IP maliciosas y evitar que accedan al sitio.
1. Configurar la lista negra de IPs:
En el archivo .env, agrega una nueva variable de entorno IP_BLACKLIST que contenga las direcciones IP bloqueadas, separadas por comas.
IP_BLACKLIST=192.168.0.4,192.168.0.10
2. Crear un suscriptor de eventos (event subscriber):
Crea un suscriptor que escuche el evento kernel.request. Esto es útil para detener tempranamente el manejo de solicitudes no deseadas. Verifica si la dirección IP del cliente está en la lista negra y, de ser así, lanza la excepción AccessDeniedHttpException.
<?php namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class RestrictIpAddressSubscriber implements EventSubscriberInterface { public function __construct(private array $ipBlacklist) { } public static function getSubscribedEvents(): array { return [RequestEvent::class => 'onKernelRequest']; } public function onKernelRequest(RequestEvent $event): void { if (!$event->isMainRequest()) { return; } if (in_array($event->getRequest()->getClientIp(), $this->ipBlacklist, true)) { throw new AccessDeniedHttpException('Access Denied'); } } }
Luego en services.yml agrega como argumento IP_BLACKLIST
services: # ... App\EventSubscriber\RestrictIpAddressSubscriber: arguments: ['%env(csv:IP_BLACKLIST)%']
Por hoy es todo, si necesitas o deseas saber mas, como hago, comenta y agregaremos en un nuevo articulo, proximamente.
Deja un comentario: