gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
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.
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é DateTimeFormatter
justo 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.
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 | |
'/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.
// 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
}
}
Hey,
I get at using this bundle the exception ClassNotFoundError in the file mixed_vinyl\vendor\symfony\translation\LocaleSwitcher.php at line 37.