This course is still being released! Check back later for more chapters.
Clase de servicio bundle
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Bien, nuestro bundle está instalado y listo para funcionar. Es hora de añadir algo de funcionalidad añadiendo nuestra primera clase de servicio. Ésta será la estrella del espectáculo. Nuestro bundle es para traducir objetos, así que éste parece el lugar adecuado para empezar.
En el directorio src
de nuestro bundle, crea una nueva clase PHP: ObjectTranslator
.
ObjectTranslator
En primer lugar, marca esta clase como final. No está pensada para ser ampliada. Al desarrollar bundles, es importante ser explícito sobre el diseño de tus clases y sus intenciones. Esto facilita mantener la compatibilidad hacia atrás. Eliminar final
más adelante no es un cambio de ruptura, pero añadir final
sí lo es. Exploraremos más trucos de este tipo a medida que avancemos:
// ... lines 1 - 4 | |
final class ObjectTranslator | |
{ | |
// ... lines 7 - 17 | |
} |
Crear un método: public function translate(object $object)
. Tipo de retorno: object
. Con el tiempo, albergará la lógica para traducir objetos. Por ahora, sólo devuelve el$object
pasado:
// ... lines 1 - 4 | |
final class ObjectTranslator | |
{ | |
// ... lines 7 - 13 | |
public function translate(object $object): object | |
{ | |
return $object; | |
} | |
} |
Nuestro servicio necesita un constructor para inyectar algunas cosas. Añade public
function __construct(private LocaleAwareInterface $localeAware, private
string $defaultLocale)
. Necesitamos el servicio LocaleAwareInterface
para obtener la configuración regional actual de la petición, y también necesitaremos la configuración regional por defecto de nuestra aplicación:
// ... lines 1 - 6 | |
final class ObjectTranslator | |
{ | |
public function __construct( | |
private LocaleAwareInterface $localeAware, | |
private string $defaultLocale, | |
) { | |
} | |
// ... lines 14 - 33 | |
} |
Abajo, en translate()
, podemos añadir algo de lógica sencilla. Obtén la configuración regional actual con$locale = $this->localeAware->getLocale()
. Ahora bien, si la configuración regional actual es la misma que la configuración regional por defecto, no necesitamos hacer ninguna traducción, así que añade un if ($this->defaultLocale === $locale)
y, en este caso, sólo devuelve el objeto sin procesar:
// ... lines 1 - 6 | |
final class ObjectTranslator | |
{ | |
// ... lines 9 - 21 | |
public function translate(object $object): object | |
{ | |
$locale = $this->localeAware->getLocale(); | |
if ($this->defaultLocale === $locale) { | |
return $object; | |
} | |
// ... lines 29 - 32 | |
} | |
} |
A continuación es donde añadiremos la lógica de traducción real, pero de momento añade un comentario: todo translate object
:
// ... lines 1 - 6 | |
final class ObjectTranslator | |
{ | |
// ... lines 9 - 21 | |
public function translate(object $object): object | |
{ | |
// ... lines 24 - 29 | |
// todo translate object | |
return $object; | |
} | |
} |
Utilicemos este nuevo servicio en ArticleController::show()
. Amplía un poco este método e inyéctalo: ObjectTranslator $translator
:
// ... lines 1 - 11 | |
final class ArticleController extends AbstractController | |
{ | |
// ... lines 14 - 22 | |
'/news/{slug:article}', name: 'app_article_show') | (|
public function show(Article $article, ObjectTranslator $translator): Response | |
// ... lines 25 - 36 | |
} |
Ejecuta el Article
inyectado a través de nuestro nuevo servicio:$article = $translator->translate($article)
:
// ... lines 1 - 11 | |
final class ArticleController extends AbstractController | |
{ | |
// ... lines 14 - 23 | |
public function show(Article $article, ObjectTranslator $translator): Response | |
{ | |
$article = $translator->translate($article); | |
// ... lines 27 - 35 | |
} | |
} |
¡Genial!
Genéricos PHP
Observa que si intentamos acceder a un método de $article
antes de ejecutarlo a través de nuestro servicio, PhpStorm puede autocompletar todos los métodos de $article
. Pero... si intentamos acceder a un método en $article
después de ejecutarlo a través de$translator->translate()
, no tenemos autocompletado. PhpStorm no tiene ni idea de qué es ahora $article
- sólo que es "un objeto". Esto es un fastidio... ¡Pero podemos arreglarlo con los genéricos de PHP!
Los genéricos son una forma de proporcionar información de tipo adicional a nuestro editor.
Fíjate en esto: encima de ObjectTranslator::translate()
, genera algunos bloques doc. Esto sólo coincide con la firma del método y no es superútil... así que añade@template T of object
encima. Esto declara un tipo de plantilla T
que debe ser un objeto. T
es como un alias, o marcador de posición y puede ser cualquier cadena.
Ahora, para @param
y @return
, sustituye object
por T
:
// ... lines 1 - 6 | |
final class ObjectTranslator | |
{ | |
// ... lines 9 - 14 | |
/** | |
* @template T of object | |
* | |
* @param T $object | |
* | |
* @return T | |
*/ | |
public function translate(object $object): object | |
// ... lines 23 - 33 | |
} |
Esto le dice a nuestro editor: "Sea cual sea el tipo de objeto que se pase a este método, el tipo devuelto será el mismo tipo de objeto"
De vuelta en ArticleController::show()
, después de llamar a translate()
, intenta autocompletar de nuevo en $article
. ¡Pum! Ahora PhpStorm sabe exactamente qué es $article
. ¡Esto me encanta!
Elimina ese código extra - el artículo traducido se pasa ahora a nuestra plantilla, así que nuestro trabajo aquí está hecho.
Volvemos a nuestro navegador y visitamos la página del artículo... Un error... "No se puede autohilar el argumento $translator..."
Symfony no conoce el servicio de nuestro bundle - sigue siendo una simple clase PHP...
¡Arreglémoslo a continuación!