Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Encontrar y Utilizar los Servicios de un Bundle

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.

Acabamos de instalar KnpTimeBundle. ¡Hurra! Pero... eh... ¿qué significa eso? ¿Qué nos da eso?

Lo primero que nos da un bundle son... ¡servicios! ¿Qué servicios nos da este bundle? Bueno, podríamos, por supuesto, leer la documentación, bla, bla. Bueno, vale, deberías hacerlo... pero, ¡vamos! ¡Aventurémonos con temeridad y aprendamos explorando!

En el último tutorial, conocimos un comando que nos muestra todos los servicios de nuestra aplicación: debug:autowiring:

php bin/console debug:autowiring

Por ejemplo, si buscamos "logger", parece que hay un servicio llamadoLoggerInterface. También aprendimos que podemos autoconectar cualquier servicio de esta lista en nuestro controlador utilizando su tipo. Usando este tipo LoggerInterface -que en realidad es Psr\Log\LoggerInterface - Symfony sabe que debe pasarnos este servicio. Luego, aquí abajo, llamamos a métodos sobre él como $logger->info().

Hemos instalado KnpTimeBundle hace un momento, así que busquemos "tiempo":

php bin/console debug:autowiring time

Y... ¡eh! ¡Mira esto! ¡Tenemos un nuevo servicio DateTimeFormatter! Es del nuevo bundle y seguro que es lo que buscamos. Vamos a utilizarlo en nuestro controlador.

Utilizar el nuevo servicio DateTimeFormatter

La pista de tipo que necesitamos es Knp\Bundle\TimeBundle\DateTimeFormatter. De acuerdo EnVinylController, busca browse(), y añade el nuevo argumento.

Por cierto, el orden de los argumentos no importa... excepto cuando se trata de argumentos opcionales. He hecho que el argumento $slug sea opcional y normalmente necesitas tus argumentos opcionales al final de la lista. Así que añadiré DateTimeFormatterjusto aquí y pulsaré "tab" para añadir la declaración use en la parte superior.

Podemos nombrar el argumento como queramos, como $sherlockHolmes o$timeFormatter:

... lines 1 - 4
use Knp\Bundle\TimeBundle\DateTimeFormatter;
... lines 6 - 10
class VinylController extends AbstractController
{
... lines 13 - 31
public function browse(DateTimeFormatter $timeFormatter, string $slug = null): Response
{
... lines 34 - 45
}
... lines 47 - 71
}

Para usar esto, haz un bucle sobre las mezclas - foreach ($mixes as $key => $mix)

... lines 1 - 4
use Knp\Bundle\TimeBundle\DateTimeFormatter;
... lines 6 - 10
class VinylController extends AbstractController
{
... lines 13 - 31
public function browse(DateTimeFormatter $timeFormatter, string $slug = null): Response
{
... lines 34 - 36
foreach ($mixes as $key => $mix) {
... line 38
}
... lines 40 - 45
}
... lines 47 - 71
}

luego, en cada una, añade una nueva clave ago: $mixes[$key]['ago'] =... y aquí es donde necesitamos el nuevo servicio. ¿Cómo utilizamos el DateTimeFormatter? ¡No tengo ni idea! Pero hemos utilizado su tipo, así que PhpStorm debería decirnos qué métodos tiene. Escribe$timeFormatter->... y ¡bien! Tiene 4 métodos públicos.

El que queremos es formatDiff(). Pásale el tiempo "desde"... que es$mix['createdAt']:

... lines 1 - 4
use Knp\Bundle\TimeBundle\DateTimeFormatter;
... lines 6 - 10
class VinylController extends AbstractController
{
... lines 13 - 31
public function browse(DateTimeFormatter $timeFormatter, string $slug = null): Response
{
... lines 34 - 36
foreach ($mixes as $key => $mix) {
$mixes[$key]['ago'] = $timeFormatter->formatDiff($mix['createdAt']);
}
... lines 40 - 45
}
... lines 47 - 71
}

¡Eso es todo lo que necesitamos! Estamos haciendo un bucle sobre estos $mixes, tomando la clave createdAt, que es un objeto DateTime, pasándolo al método formatDiff(), que debería devolver una cadena con el formato "ago". Para ver si esto funciona, a continuación,dd($mixes):

... lines 1 - 4
use Knp\Bundle\TimeBundle\DateTimeFormatter;
... lines 6 - 10
class VinylController extends AbstractController
{
... lines 13 - 31
public function browse(DateTimeFormatter $timeFormatter, string $slug = null): Response
{
... lines 34 - 36
foreach ($mixes as $key => $mix) {
$mixes[$key]['ago'] = $timeFormatter->formatDiff($mix['createdAt']);
}
dd($mixes);
... lines 41 - 45
}
... lines 47 - 71
}

¡Vamos a probarlo! Gira, refresca... y abramos. ¡Sí! Mira esto: "ago" => "7 months ago"... "ago" => "18 days ago"... Funciona. Así que elimina ese volcado:

... lines 1 - 10
class VinylController extends AbstractController
{
... lines 13 - 31
public function browse(DateTimeFormatter $timeFormatter, string $slug = null): Response
{
... lines 34 - 36
foreach ($mixes as $key => $mix) {
$mixes[$key]['ago'] = $timeFormatter->formatDiff($mix['createdAt']);
}
return $this->render('vinyl/browse.html.twig', [
... lines 42 - 43
]);
}
... lines 46 - 70
}

Y ahora que cada mezcla tiene un nuevo campo ago, en browse.html.twig, sustituye el códigomix.createdAt|date por mix.ago:

... lines 1 - 3
<div class="container">
... lines 5 - 25
<div>
<h2 class="mt-5">Mixes</h2>
<div class="row">
{% for mix in mixes %}
<div class="col col-md-4">
<div class="mixed-vinyl-container p-3 text-center">
... lines 32 - 35
<span>{{ mix.genre }}</span>
|
<span>{{ mix.ago }}</span>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
... lines 45 - 46

Y ahora... mucho mejor.

Así que: teníamos un problema... y sabíamos que había que resolverlo con un servicio... porque los servicios sí funcionan. Todavía no teníamos un servicio que hiciera lo que necesitábamos, así que salimos, encontramos uno y lo instalamos. ¡Problema resuelto! El propio Symfony tiene un montón de paquetes diferentes, y cada uno de ellos nos proporciona varios servicios. Pero a veces necesitarás un bundle de terceros como éste para hacer el trabajo. Normalmente, puedes buscar en Internet el problema que intentas resolver, más "Symfony bundle", para encontrarlo.

Utilizar el filtro Twig de hace años

Además del bonito servicio DateTimeFormatter que acabamos de utilizar, este bundle también nos proporcionó otro servicio. Pero no es un servicio que debamos utilizar directamente, como en el controlador. No Este servicio está destinado a ser utilizado por el propio Twig... ¡para alimentar un nuevo filtro Twig! ¡Así es! Puedes añadir funciones personalizadas, filtros... o cualquier cosa a Twig.

Para ver el nuevo filtro, vamos a probar otro útil comando de depuración:

php bin/console debug:twig

Esto imprime una lista de todas las funciones, filtros y pruebas de Twig, junto con la única variable global de Twig que tenemos. Si subes a Filtros, ¡hay uno nuevo llamado "hace"! Eso no estaba allí antes de que instaláramos KnpTimeBundle.

Así que todo el trabajo que hicimos en nuestro controlador está perfectamente bien ... pero resulta que hay una manera más fácil de hacer todo esto. Elimina el foreach... elimina el servicio DateTimeFormatter... y, aunque es opcional, limpia la declaración extra use de la parte superior:

... lines 1 - 9
class VinylController extends AbstractController
{
... lines 12 - 29
#[Route('/browse/{slug}', name: 'app_browse')]
public function browse(string $slug = null): Response
{
$genre = $slug ? u(str_replace('-', ' ', $slug))->title(true) : null;
$mixes = $this->getMixes();
return $this->render('vinyl/browse.html.twig', [
'genre' => $genre,
'mixes' => $mixes,
]);
}
... lines 41 - 65
}

En browse.html.twig, ya no tenemos un campo ago... pero seguimos teniendo un campocreatedAt. En lugar de canalizarlo en el filtro date, canalízalo en ago:

... lines 1 - 3
<div class="container">
... lines 5 - 25
<div>
<h2 class="mt-5">Mixes</h2>
<div class="row">
{% for mix in mixes %}
<div class="col col-md-4">
<div class="mixed-vinyl-container p-3 text-center">
... lines 32 - 35
<span>{{ mix.genre }}</span>
|
<span>{{ mix.createdAt|ago }}</span>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
... lines 45 - 46

¡Eso es todo lo que necesitamos! Volvemos a la actualización del sitio y... obtenemos exactamente el mismo resultado.

Por cierto, no lo haremos en este tutorial, pero al final, podrás seguir fácilmente la documentación para crear tus propias funciones y filtros Twig personalizados.

Vale, nuestra aplicación aún no tiene una base de datos... y no la tendrá hasta el próximo episodio. Pero para hacer las cosas más interesantes, vamos a obtener los datos de nuestras mezclas haciendo una llamada HTTP a un repositorio especial de GitHub. Eso a continuación.

Leave a comment!

3
Login or Register to join the conversation
Stefaaan Avatar
Stefaaan Avatar Stefaaan | posted hace 6 meses | edited

Hey,

I get at using this bundle the exception ClassNotFoundError in the file mixed_vinyl\vendor\symfony\translation\LocaleSwitcher.php at line 37.

Reply

Hey Stefaaan,

Do you have installed the PHP intl extension on your computer?

Reply
Stefaaan Avatar

Hey MolloKhan,

thanks for your reply.

No, i hadn't installed this extension. After installing it in the php.ini and restarting the local web server it works. Thank you.

Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "knplabs/knp-time-bundle": "^1.18", // v1.19.0
        "symfony/asset": "6.1.*", // v6.1.0-RC1
        "symfony/console": "6.1.*", // v6.1.0-RC1
        "symfony/dotenv": "6.1.*", // v6.1.0-RC1
        "symfony/flex": "^2", // v2.1.8
        "symfony/framework-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/http-client": "6.1.*", // v6.1.0-RC1
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/runtime": "6.1.*", // v6.1.0-RC1
        "symfony/twig-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/ux-turbo": "^2.0", // v2.1.1
        "symfony/webpack-encore-bundle": "^1.13", // v1.14.1
        "symfony/yaml": "6.1.*", // v6.1.0-RC1
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.0
    },
    "require-dev": {
        "symfony/debug-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/maker-bundle": "^1.41", // v1.42.0
        "symfony/stopwatch": "6.1.*", // v6.1.0-RC1
        "symfony/web-profiler-bundle": "6.1.*" // v6.1.0-RC1
    }
}
userVoice