Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Nuevo Bundle, nuevo servicio: KnpTimeBundle

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.

En nuestro sitio, puedes crear tu propia mezcla de vinilo. (O podrás hacerlo con el tiempo... ahora mismo, este botón no hace nada). Pero otra gran característica de nuestro sitio es la posibilidad de explorar las mezclas de otros usuarios.

Ahora que lo estoy viendo, podría ser útil si pudiéramos ver cuándo se creó cada mezcla.

Si no recuerdas en qué parte de nuestro código se creó esta página, puedes utilizar un truco. Abajo, en la barra de herramientas de depuración de la web, pasa el ratón por encima del código de estado 200. Ah, ¡ja! Esto nos muestra que el controlador detrás de esta página es VinylController::browse.

¡Genial! Ve a abrir src/Controller/VinylController.php. Aquí está la acción browse:

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

Por cierto, he actualizado un poco el código desde el primer episodio... así que asegúrate de tener una copia fresca si estás codificando conmigo.

Este método llama a $this->getMixes()... que es una función privada que he creado en la parte inferior:

... lines 1 - 9
class VinylController extends AbstractController
{
... lines 12 - 41
private function getMixes(): array
{
// temporary fake "mixes" data
return [
[
'title' => 'PB & Jams',
'trackCount' => 14,
'genre' => 'Rock',
'createdAt' => new \DateTime('2021-10-02'),
],
[
'title' => 'Put a Hex on your Ex',
'trackCount' => 8,
'genre' => 'Heavy Metal',
'createdAt' => new \DateTime('2022-04-28'),
],
[
'title' => 'Spice Grills - Summer Tunes',
'trackCount' => 10,
'genre' => 'Pop',
'createdAt' => new \DateTime('2019-06-20'),
],
];
}
}

Esto devuelve una gran matriz de datos falsos que representa las mezclas que vamos a representar en la página. Eventualmente, obtendremos esto de una fuente dinámica, como una base de datos.

Impresión de fechas en Twig

Observa que cada mezcla tiene un campo de fecha createdAt. Obtenemos estas mezclas en browse()... y las pasamos como una variable mixes a vinyl/browse.html.twig. Vamos a saltar a esa plantilla.

Aquí abajo, utilizamos el bucle for de Twig para recorrer mixes. ¡Es muy sencillo!

... 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">
<img src="https://via.placeholder.com/300" data-src="https://via.placeholder.com/300" alt="Square placeholder img">
<p class="mt-2"><strong>{{ mix.title }}</strong></p>
<span>{{ mix.trackCount }} Tracks</span>
|
<span>{{ mix.genre }}</span>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
... lines 43 - 44

Ahora imprimamos también la fecha "creada en". Añade un |, otro <span> y luego digamos {{ mix.createdAt }}.

Sólo hay un problema. Si miras createdAt... es un objeto DateTime. Y no puedes imprimir simplemente objetos DateTime... obtendrás un gran error que te recordará... que no puedes imprimir simplemente objetos DateTime. ¡Qué mundo más cruel!

Afortunadamente, Twig tiene un práctico filtro date. Ya hablamos brevemente de los filtros en el primer episodio: los utilizamos añadiendo un | después de algún valor y el nombre del filtro. Este filtro en particular también toma un argumento, que es el formato en el que debe imprimirse la fecha. Para simplificar las cosas, vamos a utilizar Y-m-d, o "año-mes-día".

... 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|date('Y-m-d') }}</span>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
... lines 45 - 46

Ve y actualiza y... ¡bien! Ahora podemos ver cuándo se creó cada uno, aunque el formato no es muy atractivo. Podríamos hacer más trabajo para arreglar esto... pero sería mucho más genial si pudiéramos imprimir esto en el formato "hace".

Probablemente lo hayas visto antes.... como en los comentarios de una entrada de blog... dicen algo así como "publicado hace tres meses" o "publicado hace 10 minutos".

Así que... la pregunta es: ¿Cómo podemos convertir un objeto DateTime en ese bonito formato "hace"? Bueno, eso me suena a trabajo y, como he dicho antes, el trabajo en Symfony lo hace un servicio. Así que la verdadera pregunta es: ¿Existe un servicio en Symfony que pueda convertir los objetos DateTime al formato "ago"? La respuesta es... no. Pero hay un bundle de terceros que puede darnos ese servicio.

Instalación de KnpTimeBundle

Ve a https://github.com/KnpLabs/KnpTimeBundle. Si miras la documentación de este bundle, verás que nos proporciona un servicio que puede hacer esa conversión. Así que... ¡vamos a instalarlo!

Desplázate hasta la línea composer require, cópiala, gira a nuestro terminal y pégala.

composer require knplabs/knp-time-bundle

¡Genial! Esto agarró knplabs/knp-time-bundle... así como symfony/translation: el componente de traducción de Symfony, que es una dependencia de KnpTimeBundle. Cerca de la parte inferior, también configuró dos recetas. Veamos qué hacen. Ejecuta:

git status

¡Impresionante! Cada vez que instales un paquete de terceros, Composer siempre modificará tus archivos composer.json y composer.lock. Esto también ha actualizado el archivoconfig/bundles.php:

<?php
return [
... lines 4 - 11
Knp\Bundle\TimeBundle\KnpTimeBundle::class => ['all' => true],
];

Eso es porque acabamos de instalar un bundle - KnpTimeBundle - y su receta se encargó de ello automáticamente. También parece que la receta de traducción añadió un archivo de configuración y un directorio translations/. El traductor es necesario para utilizar KnpTimeBundle... pero no necesitaremos trabajar con él directamente.

Entonces... ¿qué nos ha aportado la instalación de este nuevo bundle? Servicios, por supuesto ¡Busquemos y utilicemos esos a continuación!

Leave a comment!

2
Login or Register to join the conversation

can we use Carbon library in a Symfony project ?

Reply

Hi,

Of course you can! I don't see any problem with it. It's a cool library!

Cheers!

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