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!

7
Login or Register to join the conversation
Gitanjali-N Avatar
Gitanjali-N Avatar Gitanjali-N | posted hace 2 meses

Hi there,

I completed the previous course and it went well! On downloading a fresh copy of the code for this course and setting it up as per the readme file, the website is up and everthing works, except that the audios do not play and the turbo function is also not working. Any hints as to why this could be ?
Thanks!

Reply

Hey @Gitanjali-N

Can you tell me if you get any console errors in your browser? Did you run yarn watch? I'm guessing this problem could be related to your browser, if you try with a different one, does it work?
Also, try hard-refreshing the page

1 Reply
Gitanjali-N Avatar
Gitanjali-N Avatar Gitanjali-N | MolloKhan | posted hace 2 meses | edited

Hi @MolloKhan , thank you so much for your response. Indeed, it worked in another browser-profile window!

Reply

Git Versioning

I'm keeping a git version of this course as I code along. One challenge with downloading a fresh copy of the code is that it creates conflicts in my version control. Do you have any thoughts on to address this? If the changes are code specific, I don't think it's too big of a deal as I can just update the specific code changes where they exist. Are there any package changes between the first tutorial and this one-or even subsequent ones?

Thanks

Reply

Hey robertocannella,

I'm not sure I understand your problem completely. Do you mean, you have a course code from a different (past) tutorial, and wanted to follow the current course base on the finish code of the previous tutorial? If so, that's not something we recommend. We always recommend users to download a fresh course code for each tutorial to code along with us - this way you will have the exact code as the course author has. The reason behind of this is that we always d some upgrades and minor changes between our courses, so "finish course 1 code" != "start course 2 code", always.

But if you want, of course, you can try to follow the current course base on finish course code from the past tutorial, but be aware of possible changes and conflicts that we may done between courses that you would need to resolve manually. It's up to you :)

Cheers!

Reply

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