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

Generando URLs

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.

Vuelve a la página "show" para una cuestión. El logo de arriba es un link... que no va a ninguna parte aún. Este debería llevarnos a la página de inicio.

Como forma parte del layout, el link vive en base.html.twig. Aquí está: navbar-brand con href="#".

... line 1
<html>
... lines 3 - 12
<body>
<nav class="navbar navbar-light bg-light" style="height: 100px;">
<a class="navbar-brand" href="#">
... lines 16 - 17
</a>
... line 19
</nav>
... lines 21 - 26
</body>
</html>

Para hacer que esto nos lleve a la página de inicio, podemos simplemente cambiarlo a /, ¿Cierto? Podrías hacerlo, pero en Symfony, una mejor forma es pedirle a Symfony que genere una URL hacia esta ruta. De esta forma, si decidimos cambiar esta URL en el futuro, todos nuestros links se actualizarán automáticamente.

¡Cada Ruta Tiene un Nombre!

Para ver cómo hacer esto, ve a tu terminal y corre:

php bin/console debug:router

Esto muestra un listado de cada ruta del sistema... ¡Y, hey! Desde la última vez que lo corrimos, hay un montón de rutas nuevas. Estas alimentan a la barra de herramientas debug y el profiler y son agregadas automáticamente por el WebProfilerBundle cuando estamos en modo dev.

De todas formas, lo que realmente quiero ver es la columna "Name". Toda ruta tiene un nombre interno, incluyendo las dos rutas que hicimos. Aparentemente sus nombres son app_question_homepage y app_question_show. Pero... eh... ¿De dónde vinieron? ¡No recuerdo haber escrito ninguno de éstos!

Entonces... A cada ruta debe serle dada un nombre interno. Pero cuando usas rutas en anotación... te deja hacer trampa: elige un nombre por ti basado en la clase y método del controlador... ¡Lo cual es asombroso!

Pero... tan pronto como necesitas generar la URL de una ruta, yo recomiendo darle un nombre explícito, en lugar de depender de este nombre autogenerado, el cual podría cambiar de repente si le cambias el nombre al método. Para darle un nombre a una ruta, agrega name="" y... Que tal: app_homepage.

... lines 1 - 8
class QuestionController extends AbstractController
{
/**
* @Route("/", name="app_homepage")
*/
public function homepage()
{
... line 16
}
... lines 18 - 34
}

Me gusta mantener los nombres de mis rutas cortos, pero app_ lo hace lo suficientemente largo como para poder realizar una búsqueda a partir de esta cadena si alguna vez lo necesito.

Ahora, si corremos debug:router nuevamente:

php bin/console debug:router

¡Bien! Tomamos el control del nombre de nuestra ruta. Copia el nombre app_homepage y luego vuelve a base.html.twig. El objetivo es simple, queremos decir:

¡Hey symfony! ¿Puedes por favor decirme la URL para la ruta app_homepage?

Para hacer esto en Twig, usa {{ path() }} y pásale el nombre de la ruta.

... line 1
<html>
... lines 3 - 12
<body>
<nav class="navbar navbar-light bg-light" style="height: 100px;">
<a class="navbar-brand" href="{{ path('app_homepage') }}">
... lines 16 - 17
</a>
... line 19
</nav>
... lines 21 - 26
</body>
</html>

¡Eso es todo! Cuando volvemos y refrescamos... Ahora esto va hacia la página principal.

Apuntando a una Ruta con {Comodines}

En la página principal, tenemos dos preguntas escritas a mano... y cada una tiene dos links que actualmente no van a ninguna parte. ¡Arreglémoslos!

Paso uno: ahora que queremos generar una URL de esta ruta, encuentra la ruta y agrega name="app_question_show".

... lines 1 - 8
class QuestionController extends AbstractController
{
... lines 11 - 18
/**
* @Route("/questions/{slug}", name="app_question_show")
*/
public function show($slug)
{
... lines 24 - 33
}
}

Copia esto y abre el template: templates/question/homepage.html.twig. Veamos... Justo debajo de la parte de votar, aquí está el primer link a una pregunta que dice "Reversing a spell". Quita el signo numeral, agrega {{ path() }} y pega app_question_show.

Pero... no podemos detenernos aquí. ¡Si probamos la página ahora, un error glorioso!

Algunos parámetros obligatorios están faltando - "slug"

¡Eso tiene sentido! ¡No podemos simplemente decir "genera la URL hacia app_question_show" porque esa ruta tiene un comodín! Symfony necesita saber qué valor debería usar para {slug}. ¿Cómo le decimos? Agrega un segundo parámetro a path() con {}. El {} es un array asociativo de Twig... nuevamente, tal como en JavaScript. Pásale slug igual a... Veamos... Esta es una pregunta escrita a mano por el momento, así que escribe reversing-a-spell.

... lines 1 - 2
{% block body %}
... lines 4 - 9
<div class="container">
... lines 11 - 15
<div class="row">
<div class="col-12">
<div style="box-shadow: 2px 3px 9px 4px rgba(0,0,0,0.04);">
<div class="q-container p-4">
<div class="row">
... lines 21 - 27
<div class="col">
<a class="q-title" href="{{ path('app_question_show', { slug: 'reversing-a-spell' }) }}"><h2>Reversing a Spell</h2></a>
... lines 30 - 34
</div>
</div>
</div>
<a class="answer-link" href="{{ path('app_question_show', { slug: 'reversing-a-spell' }) }}" style="color: #fff;">
... lines 39 - 41
</a>
</div>
</div>
... lines 45 - 71
</div>
</div>
{% endblock %}
... lines 75 - 76

Cópialo todo, porque hay un link más aquí abajo para la misma pregunta. Para la segunda pregunta... Pégalo nuevamente, pero cámbialo a pausing-a-spell para igualar el nombre. Copiaré eso... Encuentra la última ocurrencia... Y pégalo.

... lines 1 - 2
{% block body %}
... lines 4 - 9
<div class="container">
... lines 11 - 15
<div class="row">
... lines 17 - 45
<div class="col-12 mt-3">
<div class="q-container p-4">
<div class="row">
... lines 49 - 55
<div class="col">
<a class="q-title" href="{{ path('app_question_show', { slug: 'pausing-a-spell' }) }}"><h2>Pausing a Spell</h2></a>
... lines 58 - 62
</div>
</div>
</div>
<a class="answer-link" href="{{ path('app_question_show', { slug: 'pausing-a-spell' }) }}" style="color: #fff;">
... lines 67 - 69
</a>
</div>
</div>
</div>
{% endblock %}
... lines 75 - 76

Más adelante, cuando implementemos una base de datos, vamos a mejorar esto y evitaremos repetirnos tantas veces. ¡Pero! Si volvemos, refrescamos... ¡Y hacemos click en el link, funciona! Ambas páginas van hacia la misma ruta, pero con un valor diferente para el slug.

A continuación, llevemos nuestro sitio al siguiente nivel, al crear una interface API JSON que consumiremos con JavaScript.

Leave a comment!

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
    }
}