gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
La página de inicio será el lugar donde el usuario podrá diseñar y construir su próxima cinta de mezclas. Pero además de crear nuevas cintas, los usuarios también podrán explorar las creaciones de otras personas.
Vamos a crear una segunda página para eso. ¿Cómo? Añadiendo un segundo controlador: función pública, qué tal browse
: el nombre no importa realmente. Y para ser responsable, añadiré un tipo de retorno Response
.
Por encima de esto, necesitamos nuestra ruta. Ésta será exactamente igual, salvo que pondremos la URL en /browse
. Dentro del método, ¿qué es lo que siempre devolvemos de un controlador? Así es: ¡un objeto Response
! Devuelve un nuevo Response
... con un mensaje corto para empezar.
... lines 1 - 7 | |
class VinylController | |
{ | |
... lines 10 - 15 | |
'/browse') ( | |
public function browse(): Response | |
{ | |
return new Response('Breakup vinyl? Angsty 90s rock? Browse the collection!'); | |
} | |
} |
¡Vamos a probarlo! Si actualizamos la página de inicio, no cambia nada. Pero si vamos a /browse
... ¡lo machacamos! ¡Una segunda página en menos de un minuto! ¡Caramba!
En esta página, acabaremos por listar las cintas de mezclas de otros usuarios. Para ayudar a encontrar algo que nos guste, quiero que los usuarios también puedan buscar por género. Por ejemplo, si voy a /browse/death-metal
, eso me mostraría todas las cintas de vinilo de death metal. Hardcore.
Por supuesto, si probamos esta URL ahora mismo... no funciona.
No se ha encontrado la ruta
No se han encontrado rutas coincidentes para esta URL, por lo que nos muestra una página 404. Por cierto, lo que estás viendo es la elegante página de excepciones de Symfony, porque estamos desarrollando. Nos da muchos detalles cuando algo va mal. Cuando finalmente despliegues a producción, puedes diseñar una página de error diferente que verían tus usuarios.
De todos modos, la forma más sencilla de hacer que esta URL funcione es simplemente... cambiar la URL a/browse/death-metal
... lines 1 - 7 | |
class VinylController | |
{ | |
... lines 10 - 15 | |
'/browse/death-metal') ( | |
public function browse(): Response | |
{ | |
return new Response('Breakup vinyl? Angsty 90s rock? Browse the collection!'); | |
} | |
} |
Pero... no es súper flexible, ¿verdad? Necesitaríamos una ruta para cada género... ¡que podrían ser cientos! Y además, ¡acabamos de matar la URL /browse
! Ahora es 404.
Lo que realmente queremos es una ruta que coincida con /browse/<ANYTHING>
. Y podemos hacerlo con un comodín. Sustituye el código duro death-metal
por {}
y, dentro,slug
. Slug es sólo una palabra técnica para designar un "nombre seguro para la URL". En realidad, podríamos haber puesto cualquier cosa dentro de las llaves, como {genre}
o {coolMusicCategory}
: no hay ninguna diferencia. Pero sea lo que sea que pongamos dentro de este comodín, se nos permite tener un argumento con ese mismo nombre: $slug
.
... lines 1 - 7 | |
class VinylController | |
{ | |
... lines 10 - 15 | |
'/browse/{slug}') ( | |
public function browse(): Response | |
{ | |
return new Response('Breakup vinyl? Angsty 90s rock? Browse the collection!'); | |
} | |
} |
Sí, si vamos a /browse/death-metal
, coincidirá con esta ruta y pasará la cadenadeath-metal
a ese argumento. La coincidencia se hace por nombre: {slug}
conecta con $slug
.
Para ver si funciona, devolvamos una respuesta diferente: Genre
y luego la $slug
.
... lines 1 - 7 | |
class VinylController | |
{ | |
... lines 10 - 15 | |
'/browse/{slug}') ( | |
public function browse($slug): Response | |
{ | |
return new Response('Genre: '.$slug); | |
//return new Response('Breakup vinyl? Angsty 90s rock? Browse the collection!'); | |
} | |
... lines 23 - 24 |
¡Hora de probar! Vuelve a /browse/death-metal
y... ¡sí! Prueba con /browse/emo
y ¡sí! ¡Estoy mucho más cerca de mi cinta de mezcla de Dashboard Confessional!
Ah, y es opcional, pero puedes añadir un tipo string
al argumento $slug
. Eso no cambia nada... es sólo una bonita forma de programar: el $slug
ya iba a ser siempre una cadena.
... lines 1 - 7 | |
class VinylController | |
{ | |
... lines 10 - 15 | |
'/browse/{slug}') ( | |
public function browse(string $slug): Response | |
{ | |
... lines 19 - 21 | |
} | |
... lines 23 - 24 |
Un poco más adelante, aprenderemos cómo puedes convertir un comodín numérico -como el número 5- en un número entero si así lo deseas.
Hagamos esta página un poco más elegante. En lugar de imprimir el slug exactamente, vamos a convertirlo en un título. Digamos $title = str_replace()
y sustituyamos los guiones por espacios. Luego, aquí abajo, utiliza el título en la respuesta. En un futuro tutorial, vamos a consultar la base de datos para estos géneros, pero, por ahora, al menos podemos hacer que tenga un aspecto más agradable.
... lines 1 - 7 | |
class VinylController | |
{ | |
... lines 10 - 15 | |
'/browse/{slug}') ( | |
public function browse(string $slug): Response | |
{ | |
$title = str_replace('-', ' ', $slug); | |
return new Response('Genre: '.$title); | |
... line 23 | |
} | |
... lines 25 - 26 |
Si lo probamos, el Emo no se ve diferente... pero el death metal sí. ¡Pero quiero que sea más elegante! Añade otra línea con $title =
y luego escribe u
y autocompleta una función que se llama literalmente... u
.
No utilizamos muchas funciones de Symfony, pero éste es un ejemplo raro. Proviene de una biblioteca de Symfony llamada symfony/string
. Como he mencionado, Symfony tiene muchas bibliotecas diferentes -también llamadas componentes- y vamos a aprovechar esas bibliotecas todo el tiempo. Esta te ayuda a hacer transformaciones de cadenas... y resulta que ya está instalada.
Mueve el str_replace()
al primer argumento de u()
. Esta función devuelve un objeto sobre el que podemos hacer operaciones de cadena. Uno de los métodos se llama title()
. Digamos ->title(true)
para convertir todas las palabras en mayúsculas y minúsculas.
... lines 1 - 8 | |
class VinylController | |
{ | |
... lines 11 - 15 | |
'/browse/{slug}') ( | |
public function browse(string $slug): Response | |
{ | |
$title = u(str_replace('-', ' ', $slug))->title(true); | |
return new Response('Genre: '.$title); | |
... lines 23 - 24 | |
} | |
... lines 26 - 27 |
Ahora, cuando lo probamos... ¡qué bien! ¡Pone las letras en mayúsculas! El componente de la cadena no es especialmente importante, sólo quiero que veas cómo podemos aprovechar partes de Symfony para hacer nuestro trabajo.
Bien: un último reto. Ir a /browse/emo
o /browse/death-metal
funciona. Pero ir a /browse
... no funciona. ¡Está roto! Un comodín puede coincidir con cualquier cosa, pero, por defecto, se requiere un comodín. Tenemos que ir a/browse/<something>
.
¿Podemos hacer que el comodín sea opcional? Por supuesto Y es deliciosamente sencillo: haz que el argumento correspondiente sea opcional.
... lines 1 - 8 | |
class VinylController | |
{ | |
... lines 11 - 15 | |
'/browse/{slug}') ( | |
public function browse(string $slug = null): Response | |
{ | |
... lines 20 - 24 | |
} | |
... lines 26 - 27 |
En cuanto lo hagamos, le dirá a la capa de enrutamiento de Symfony que no es necesario que el {slug}
esté en la URL. Así que ahora cuando refrescamos... funciona. Aunque no es un buen mensaje para la página.
Veamos. Si hay un slug, pon el título como estábamos. Si no, pon$title
a "Todos los géneros". Ah, y mueve el "Género:" aquí arriba... para que abajo en el Response
podamos pasar simplemente $title
.
... lines 1 - 8 | |
class VinylController | |
{ | |
... lines 11 - 15 | |
'/browse/{slug}') ( | |
public function browse(string $slug = null): Response | |
{ | |
if ($slug) { | |
$title = 'Genre: '.u(str_replace('-', ' ', $slug))->title(true); | |
} else { | |
$title = 'All Genres'; | |
} | |
return new Response($title); | |
... lines 27 - 28 | |
} | |
... lines 30 - 31 |
Inténtalo. En /browse
... "Todos los géneros". En /browse/emo
... "Género: Emo".
Siguiente: poner un texto como éste en un controlador.... no es muy limpio ni escalable, especialmente si empezamos a incluir HTML. No, tenemos que hacer una plantilla. Para ello, vamos a instalar nuestro primer paquete de terceros y seremos testigos del importantísimo sistema de recetas de Symfony en acción.
Hey boban_dj
The fuction import is not shown in the video but if you look on the code blocks from the script, you'll see Ryan used exactly that function. Good job finding it out.
Cheers!
i really want to say i appreciate these videos ...for someone who is new on symfony your way of doing things makes super sense
Hey @Mazzucato ,
Both ways work actually. If you would read the last sentence in that explanation:
And even though {highlight} is in the route, you do not need to have an argument for that!
we mean that you don't have to give every wildcard a corresponding argument in the method signature. You can skip that $highlight
at all as in our example. E.g. it may just exist there but you don't need it in the method's code, i.e. don't use it there. That's what we meant there :)
Cheers!
i really want to say i appreciate these videos ...for someone who is new on symfony your way of doing things makes super sense sure
Hi!
My application has to manage multiple domains. When I'm using the 'host' route parameter, it matches differently if user entered 'www' or not in the browser: www.example.com and example.com are not considered as the same host. How can I add a wildcard that could solve that?
Thanks!
Hey Sebastien D.
I think a better solution would be to add a redirect at the web server level, for example all requests coming from www.example.com should redirect to example.com, or viceversa.
Cheers!
Hi, I am working on Ubuntu 20.04 and installed apache2,php, mysql and composer. On symfony 6 , #[Route('/browse')] doesn't work. I have 404 page "The requested URL was not found on this server." I have installed "symfony/apache-pack". I still have the same result.
`#[Route('/browse')]
public function browse(): Response
{
return new Response('Browse page');
}`
Best regards
Hey Eskinder,
First of all, please, make sure the route is exist in the system - for this, run:
$ bin/console debug:router | grep browse
Do you see the route in the output? is it just "/browse" or does it has a prefix? Also, make sure this route is registered for GET (or any) requests. If so, then most probably the problem in your Apache config. First of all, make sure you set the public/ directory as your document root. Then, double-check the other config. Actually, Symfony gives the correct Apache/Nginx configs in the docs, see: https://symfony.com/doc/cur... - there's important to know if you configure it via PHP-FPM or in a different way - there are different configs. But basically, if the route exist and you configured the host well using the config from the docs - it should work. Also, don't forget to restart your Apache server after tweaking any config - that's important, most users forget to do this :)
I hope this helps!
Cheers!
Hi,
I have a strange question, I hope you will understand me.
In your example, "/browse" is hard coded.
Is it possible to save "/ browse" in the database and call from there.
Problem is if user wants to change "/browse" to "/somethig-else" he can't do that from cms it must be changed in code.
Best regards
Yes, that is why you have the {wildcard}
route. So all you need to do is change the /browse
route to /{browse}
now it matches anything you pass to it and you can check if that route or slug exists in your database
// composer.json
{
"require": {
"php": ">=8.0.2",
"ext-ctype": "*",
"ext-iconv": "*",
"symfony/asset": "6.0.*", // v6.0.3
"symfony/console": "6.0.*", // v6.0.3
"symfony/dotenv": "6.0.*", // v6.0.3
"symfony/flex": "^2", // v2.1.5
"symfony/framework-bundle": "6.0.*", // v6.0.4
"symfony/monolog-bundle": "^3.0", // v3.7.1
"symfony/runtime": "6.0.*", // v6.0.3
"symfony/twig-bundle": "6.0.*", // v6.0.3
"symfony/ux-turbo": "^2.0", // v2.0.1
"symfony/webpack-encore-bundle": "^1.13", // v1.13.2
"symfony/yaml": "6.0.*", // v6.0.3
"twig/extra-bundle": "^2.12|^3.0", // v3.3.8
"twig/twig": "^2.12|^3.0" // v3.3.8
},
"require-dev": {
"symfony/debug-bundle": "6.0.*", // v6.0.3
"symfony/stopwatch": "6.0.*", // v6.0.3
"symfony/web-profiler-bundle": "6.0.*" // v6.0.3
}
}
I have to add: use function Symfony\Component\String\u; to make it work. VSCodium does not show autocomplete, but here is well explained too https://symfony.com/doc/cur...