`translate_object` Filtro Twig
Lucky you! You found an early release chapter - it will be fully polished and published shortly!
This Chapter isn't quite ready...
Rest assured, the gnomes are hard at work
completing this video!
Ya tenemos nuestro servicio ObjectTranslator
en pleno funcionamiento. Se puede inyectar y utilizar en código PHP como estamos haciendo en ArticleController::show()
. Ahora, vamos a animar un poco las cosas y crear un filtro Twig para él.
Clase de extensión Twig
En object-translation-bundle/src
, crea un nuevo directorio llamado Twig
. Dentro, una nueva clase PHP llamada ObjectTranslatorExtension
.
Márcala como final
y añade un docblock a nivel de clase. En él, escribe @internal
. Este es otro truco para que los usuarios sepan que esta clase no está pensada para ser utilizada directamente en sus aplicaciones. Shh... ¡es un secreto!
A continuación, haz que extienda AbstractExtension
desde Twig:
// ... lines 1 - 7 | |
/** | |
* @internal | |
*/ | |
final class ObjectTranslatorExtension extends AbstractExtension | |
{ | |
// ... lines 13 - 18 | |
} |
Ahora, anula un único método:getFilters()
, y marca el tipo de retorno como array
. Dentro, devuelve un array con un único elemento: new TwigFilter()
. El primer argumento es el nombre de nuestro filtro,translate_object
:
// ... lines 1 - 10 | |
final class ObjectTranslatorExtension extends AbstractExtension | |
{ | |
public function getFilters(): array | |
{ | |
return [ | |
new TwigFilter('translate_object'), | |
]; | |
} | |
} |
Cableado de la extensión
¡Es hora de conectar este bebé! En tu bundle services.php
, debajo de alias()
, define un nuevo servicio con ->set('symfonycasts.object_translator.twig_extension')
. Ahora, como se trata de un servicio interno que no queremos que vean los usuarios, podemos marcarlo como oculto anteponiendo al ID del servicio .
. Más adelante te mostraré cómo afecta esto a las cosas.
El segundo argumento es el nombre de la clase: ObjectTranslatorExtension::class
:
// ... lines 1 - 7 | |
return static function (ContainerConfigurator $container): void { | |
$container->services() | |
// ... lines 10 - 20 | |
->set('.symfonycasts.object_translator.twig_extension', ObjectTranslatorExtension::class) | |
// ... line 22 | |
; | |
}; |
Fíjate, PhpStorm formatea el nombre de la clase con un tachado. Esto se debe a la bandera @internal
. Detecta que estamos intentando utilizarla fuera del directorio src
de nuestro bundle. En este caso, es un falso positivo: realmente necesitamos utilizarlo aquí. Pero en la aplicación de un usuario, es de esperar que este tachado le disuada de utilizarlo directamente.
Por último, etiquétalo como twig.extension
con ->tag('twig.extension')
:
// ... lines 1 - 7 | |
return static function (ContainerConfigurator $container): void { | |
$container->services() | |
// ... lines 10 - 20 | |
->set('.symfonycasts.object_translator.twig_extension', ObjectTranslatorExtension::class) | |
->tag('twig.extension') | |
; | |
}; |
Código de extensión
Vuelve a ObjectTranslatorExtension
. Este filtro Twig aún no está haciendo nada. El segundo argumento de TwigFilter
es un callable que hace el trabajo. Podríamos inyectar nuestro ObjectTranslator
en un constructor y llamar aquí a su método translate()
pero... no es la mejor idea. Todas las extensiones de Twig se cargan cada vez que se carga Twig. Incluso si no estamos utilizando este filtro, se instanciaría este objeto y también nuestro ObjectTranslator
. Queremos evitar eso y hacerlo perezoso. ¡Twig Runtime al rescate!
Tiempo de ejecución Twig
Para el segundo argumento, después de translate_object
, crea una matriz:[ObjectTranslator::class, 'translate']
:
// ... lines 1 - 11 | |
final class ObjectTranslatorExtension extends AbstractExtension | |
{ | |
public function getFilters(): array | |
{ | |
return [ | |
new TwigFilter('translate_object', [ObjectTranslator::class, 'translate']), | |
]; | |
} | |
} |
No es una verdadera llamada, ya quetranslate()
no es estática. Pero Twig entiende que ObjectTranslator
puede ser un runtime y cargará perezosamente esta clase y llamará a translate()
en ella cuando se utilice el filtro.
Sólo tenemos que marcar ObjectTranslator
como tiempo de ejecución Twig. En services.php
, bajo el primer servicio, nuestro traductor de objetos, añade una etiqueta: ->tag('twig.runtime')
:
// ... lines 1 - 7 | |
return static function (ContainerConfigurator $container): void { | |
$container->services() | |
->set('symfonycasts.object_translator', ObjectTranslator::class) | |
// ... lines 11 - 16 | |
->tag('twig.runtime') | |
// ... lines 18 - 22 | |
; | |
}; |
Ahora bien, si has escrito tiempos de ejecución Twig antes, puede que hayas creado una clase dedicada para ello, ¡pero esto no es estrictamente necesario! Puedes hacer que cualquier servicio sea un tiempo de ejecución con esta etiqueta. Luego, en tus extensiones, puedes referenciarlo como hemos hecho aquí.
Utilizar nuestro filtro Twig
¡Vamos a probarlo! Nuestra página de presentación de artículos ya está traduciendo bien el objeto, así que vamos a utilizar el filtro en el índice, donde listamos todos los artículos. Abre templates/article/index.html.twig
.
Dentro del bucle de artículos, en la parte superior, sustituye article
por la versión traducida: {% set article = article|translate_object %}
:
// ... lines 1 - 2 | |
{% block body %} | |
// ... line 4 | |
<div class=""> | |
// ... line 6 | |
<div> | |
{% for article in articles %} | |
{% set article = article|translate_object %} | |
// ... lines 10 - 25 | |
{% endfor %} | |
</div> | |
// ... lines 28 - 86 | |
</div> | |
{% endblock %} |
Salta al navegador y actualiza. Estamos en la página de inicio en inglés, así que cambia al francés...
¡Ya está! El título y el contenido del primer artículo están en francés. ¡Nuestro filtro Twig funciona! Por supuesto, los demás artículos siguen en inglés, ya que aún no hemos configurado traducciones para ellos.
Comprender los servicios ocultos
Vamos a dar un pequeño rodeo para entender cómo funcionan los servicios ocultos, los que llevan el prefijo .
. En tu terminal, ejecuta:
symfony console debug:container symfonycasts
Vale, vemos dos servicios, symfonycasts.object_translator
y ObjectTranslator
como clase -este es nuestro alias-. No vemos nuestro servicio de extensión Twig porque está oculto. Oculto no significa "que no esté", ni siquiera "que no se pueda utilizar", simplemente están excluidos por defecto al listar los servicios. Ejecuta de nuevo el comando, pero añade --show-hidden
:
symfony console debug:container symfonycasts --show-hidden
¡Ya está! La primera entrada es nuestro servicio oculto de extensión Twig.
A continuación, vamos a trabajar en algunas optimizaciones de rendimiento para mantener las consultas a la base de datos bajo control.
Hi,
I was wondering if you had used the Twig Extension Attributes, what configurations would you have included in
object-translation-bundle/config/services.php
?