Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Rutas Inteligentes: Solo POST y Validación de {Comodín}

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Dentro de nuestro JavaScript, estamos haciendo una petición POST a la API. Y tiene sentido. El tema de "cual método HTTP" - como GET, POST, PUT, etc - se supone debes usar para un llamado a la API... puede ser complicado. Pero como nuestra ruta eventualmente va a cambiar algo en la base de datos, como práctica recomendable, no queremos permitir a la gente que hagan llamados tipo GET a nuestra ruta. Por ahora, podemos hacer un llamado GET con tan solo poner la URL en nuestro navegador. Hey! Acabo de votar!

Para mejorar esto, en el CommentController, podemos hacer más inteligente a nuestra ruta, podemos hacer que solo funcione cuando el método sea POST. Para lograrlo agrega methods="POST".

... lines 1 - 8
class CommentController extends AbstractController
{
/**
* @Route("/comments/{id}/vote/{direction}", methods="POST")
*/
public function commentVote($id, $direction)
{
... lines 16 - 25
}
}

Tan pronto lo hagamos, al refrescar... error 404! La ruta ya no se encuentra

Tip

De hecho, es un error 405! Método HTTP no permitido.

El Comando router:match

Otra buena forma de ver esto es en tu terminal. Corre: php bin/console router:match. Luego copia la URL... y pegala.

php bin/console router:match /comments/10/vote/up

Este divertido comando nos dice cuál ruta le pertenece a una URL. En este caso, ninguna ruta fue encontrada pero esto nos dice que casi encuentra la ruta app_comment_commentvote.

Para ver si un llamado POST sería encontrado, pasa --method=POST:

php bin/console router:match /comments/10/vote/up --method=POST

Y... Bum! Nos muestra la ruta que pudo encontrar y todos los detalles, incluyendo el controlador.

Restringiendo un {Comodín}

Pero hay algo más que no está del todo bien con nuestra ruta. La ruta espera que la parte {direction} sea arriba o abajo. Pero... técnicamente, alguien podría poner plátano en la URL. De hecho, probémoslo: Cambia la dirección por plátano:

php bin/console router:match /comments/10/vote/banana --method=POST

Si! Votamos "plátano" para este comentario! No es el fin del mundo... si un usuario intenta hackear nuestro sistema y hace esto, solo significaría un voto negativo. Pero podemos hacerlo mejor.

Como has de saber, normalmente un comodín se empareja con cualquier cosa. Sin embargo, si quisieras, puedes controlarlo con una expresión regular. Dentro de {}, pero después del nombre, agrega <>. Dentro, escribe up|down.

... lines 1 - 8
class CommentController extends AbstractController
{
/**
* @Route("/comments/{id}/vote/{direction<up|down>}", methods="POST")
*/
public function commentVote($id, $direction)
{
... lines 16 - 25
}
}

Ahora prueba el comando router:match

php bin/console router:match /comments/10/vote/banana --method=POST

Si! No encuentra la ruta porque plátano no es arriba o abajo. Si cambiamos esto por arriba, funciona:

php bin/console router:match /comments/10/vote/up --method=POST

Como Hacer que el id Solo Funcione con Enteros?

Por cierto, podrías ser tentado a hacer más inteligente el comodín {id}. Asumiendo que usamos ids con auto incremento en la base de datos, sabemos que el id debe de ser un entero. Para hacer que esta ruta solo funcione si la parte del id es un número, puedes agregar <\d+>, lo que significa: encuentra un "dígito" con cualquier tamaño.

... lines 1 - 8
class CommentController extends AbstractController
{
/**
* @Route("/comments/{id<\d+>}/vote/{direction<up|down>}", methods="POST")
*/
public function commentVote($id, $direction)
{
... lines 16 - 25
}
}

Pero... En realidad no voy a poner esto aquí. Por qué? Eventualmente vamos a usar $id para llamar a la base de datos. Si alguien escribe plátano aquí, a quien le importa? El query no va a encontrar ningún comentario con plátano como id y vamos a agregar algo de código para retornar una página 404. Incluso si alguien intenta hacer un ataque de inyección de SQL, como aprenderás más tarde en nuestro tutorial de base de datos, no habría problema, porque la capa de la base de datos nos protege de ello.

... lines 1 - 8
class CommentController extends AbstractController
{
/**
* @Route("/comments/{id}/vote/{direction<up|down>}", methods="POST")
*/
public function commentVote($id, $direction)
{
... lines 16 - 25
}
}

Hay que asegurarnos que todo aún funciona. Voy a cerrar una pestaña del navegador y refrescar la página. Eso! los votos aún se ven bien.

A continuación, demos un vistazo a la parte más fundamental de Symfony: Los servicios.

Leave a comment!

11
Login or Register to join the conversation
hanen Avatar

Hi, When I run bin/console router:match /comments/10/vote/up --method=POST
//dir Path: hanen@hanen-PC /d/symfony5/cauldron_overflow (master)
I got an error [ERROR] None of the routes match the path "C:/Users/hanen/Downloads/vendor/git-for-windows/comments/10/vote/up"
the issue is missing vendors libraries ?!!

1 Reply
Default user avatar

I have the same problem. Seems like the Git Bash console I'm using is interpeting "/" as git-bash.exe location folder. Not sure how make it stop adding the "C:/Users/hanen/Downloads/vendor/git-for-windows" in front of the route. Seems like a Git Bash console thing. Works fine in cmd.exe

2 Reply

Hey guys,

Try to wrap that path in quotes! Probably single quotes may not work in windows, I suppose you need to wrap it in double quotes. But just in case, it's a good idea to try both, some quotes should work for you I think. So, basically you need to run the next command:

$ bin/console router:match "/comments/10/vote/up" --method=POST

This should do the trick. And thanks JoxTheFix for some ideas about why it may happen, it's clearer for me where the problem might be.

I hope this helps!

Cheers!

1 Reply
Joao P. Avatar

Hi, I'm getting the same error with git bash (MINGW64) and single or doubles quotes didn't help. As with Jox, with windows prompt it works. Thanks.

Reply

Hey Joao,

Thanks for confirming that JoxTheFox solution works for you.

Cheers!

Reply
hanen Avatar
hanen Avatar hanen | victor | posted hace 2 años | edited

@victor thanks :)))

Reply

Hey hanen

Let's double check a couple of things
1) Check that you have defined the route /comments/{id}/vote/up. You can run bin/console debug:router to see all your routes
2) Check that you have a comment in your database with ID 10

Let me know if you still have problems. Cheers!

Reply
hanen Avatar

The problem comes from my route where I specify that I only want to run it in POST so I add methods={"POST", "GET"}
/**
* @Route("/comments/{id}/vote/{direction<up|down>}", methods={"POST", "GET"})
*/

Reply

Did Victor comment answered to your problem? If not, could you please check if you are importing the right Route class? It should be this one Symfony\Component\Routing\Annotation\Route

1 Reply
hanen Avatar

I add double quotes and execute the command in the terminal..everything works fine:)

Reply
hanen Avatar
hanen Avatar hanen | posted hace 2 años | edited

Hi everyone , Thanks for your reply :))).. there Actually I'm using cmder software package on Windows but when I go to terminal from phpstorm run command adding double quotes: php bin/console router:match "/comments/10/vote/up" --method=POST
looks like it should work fine
[OK] Route "app_comment_commentvote" matches

+--------------+-------------------------------------------------------------+
| Property | Value |
+--------------+-------------------------------------------------------------+
| Route Name | app_comment_commentvote |
| Path | /comments/{id}/vote/{direction} |
| Path Regex | #^/comments/(?P<id>[^/]++)/vote/(?P<direction>up|down)$#sDu |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | POST |
| Requirements | direction: up|down |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: App\Controller\CommentController::commentVote |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
| | utf8: true |
+--------------+-------------------------------------------------------------+

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.3.0 || ^8.0.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "easycorp/easy-log-handler": "^1.0.7", // v1.0.9
        "sensio/framework-extra-bundle": "^6.0", // v6.2.1
        "symfony/asset": "5.0.*", // v5.0.11
        "symfony/console": "5.0.*", // v5.0.11
        "symfony/debug-bundle": "5.0.*", // v5.0.11
        "symfony/dotenv": "5.0.*", // v5.0.11
        "symfony/flex": "^1.3.1", // v1.17.5
        "symfony/framework-bundle": "5.0.*", // v5.0.11
        "symfony/monolog-bundle": "^3.0", // v3.5.0
        "symfony/profiler-pack": "*", // v1.0.5
        "symfony/routing": "5.1.*", // v5.1.11
        "symfony/twig-pack": "^1.0", // v1.0.1
        "symfony/var-dumper": "5.0.*", // v5.0.11
        "symfony/webpack-encore-bundle": "^1.7", // v1.8.0
        "symfony/yaml": "5.0.*" // v5.0.11
    },
    "require-dev": {
        "symfony/profiler-pack": "^1.0" // v1.0.5
    }
}