This course is still being released! Check back later for more chapters.
Arreglador de metadatos y PHP CS
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.
La codificación del bundle está terminada, y las pruebas están pasando en todas nuestras versiones de Symfony compatibles. ¡Estamos en la recta final!
Archivo de licencia
Vamos a añadir un archivo de licencia a nuestro bundle. En el directorio tutorial copia el archivoLICENSE.md a la raíz de nuestro bundle. Si no ves los archivos que estamos copiando en tu directorio tutorial, ¡no te preocupes! Están todos en el script de abajo:
| Copyright (c) SymfonyCasts <https://symfonycasts.com/> | |
| Permission is hereby granted, free of charge, to any person obtaining a copy | |
| of this software and associated documentation files (the "Software"), to deal | |
| in the Software without restriction, including without limitation the rights | |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| copies of the Software, and to permit persons to whom the Software is furnished | |
| to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in all | |
| copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| THE SOFTWARE. |
Esta es la licencia MIT estándar para que coincida con la que tenemos en nuestro archivo composer.json.
Documentación
Ahora, copia el archivo README.md del directorio tutorial a la raíz de nuestro bundle:
| # symfonycasts/object-translation-bundle | |
| This bundle provides a simple way to translate Doctrine entities in Symfony applications. | |
| ## Installation | |
| ### Install the bundle via Composer: | |
| ```bash | |
| composer require symfonycasts/object-translation-bundle | |
| ``` | |
| ### Enable the bundle in your `config/bundles.php` file: | |
| > [!NOTE] | |
| > This step is not required if you are using Symfony Flex. | |
| ```php | |
| return [ | |
| // ... | |
| ObjectTranslationBundle::class => ['all' => true], | |
| ]; | |
| ``` | |
| ### Create the translation entity in your app: | |
| > [!NOTE] | |
| > This step is not required if you are using Symfony Flex. | |
| ```php | |
| namespace App\Entity; | |
| use Doctrine\ORM\Mapping as ORM; | |
| use SymfonyCasts\ObjectTranslationBundle\Model\Translation as BaseTranslation; | |
| #[ORM\Entity] | |
| class Translation extends BaseTranslation | |
| { | |
| #[ORM\Id] | |
| #[ORM\GeneratedValue] | |
| #[ORM\Column] | |
| public int $id; | |
| } | |
| ``` | |
| ### Configure the entity in your `config/packages/object_translation.yaml` file: | |
| > [!NOTE] | |
| > This step is not required if you are using Symfony Flex. | |
| ```yaml | |
| symfonycasts_object_translation: | |
| translation_class: App\Entity\Translation | |
| ``` | |
| ### Create and run the migration to add the translation table: | |
| ```bash | |
| symfony console make:migration | |
| symfony console doctrine:migrations:migrate | |
| ``` | |
| ## Marking Entities as Translatable | |
| To mark an entity as translatable, use the `Translatable` attribute on the entity class | |
| and the `TranslatableProperty` attribute on the fields you want to translate. | |
| ```php | |
| namespace App\Entity; | |
| use Doctrine\ORM\Mapping as ORM; | |
| use SymfonyCasts\ObjectTranslationBundle\Mapping\Translatable; | |
| use SymfonyCasts\ObjectTranslationBundle\Mapping\TranslatableProperty; | |
| #[ORM\Entity] | |
| #[Translatable('product')] | |
| class Product | |
| { | |
| // ... | |
| #[ORM\Column(type: 'string', length: 255)] | |
| #[TranslatableProperty] | |
| public string $name; | |
| #[ORM\Column(type: 'text')] | |
| #[TranslatableProperty] | |
| public string $description; | |
| } | |
| ``` | |
| ## Usage | |
| ### `ObjectTranslator` Service | |
| You can inject the `ObjectTranslator` service to translate entities. | |
| ```php | |
| use SymfonyCasts\ObjectTranslationBundle\ObjectTranslator; | |
| class ProductController | |
| { | |
| public function show(Product $product, ObjectTranslator $objectTranslator) | |
| { | |
| // translate into the current request locale | |
| $translatedProduct = $objectTranslator->translate($product); | |
| $translatedProduct->getName(); // returns the translated name (if available) | |
| $translatedProduct->getDescription(); // returns the translated description (if available) | |
| // ... | |
| } | |
| } | |
| ``` | |
| The second argument of the `translate()` method allows you to specify a locale: | |
| ```php | |
| $product = $objectTranslator->translate($product, 'fr'); // translates into French | |
| ``` | |
| ### `translate_object` Twig Filter | |
| If using Twig, you can use the `translate_object` filter to translate entities directly in templates. | |
| ```twig | |
| {% set translatedProduct = product|translate_object %} {# translates into the current request locale #} | |
| {% set frenchProduct = product|translate_object('fr') %} {# translates into French #} | |
| ``` | |
| ## Managing Translations | |
| The `Translation` database table has the following structure: | |
| - `id`: Primary key (added by you) | |
| - `object_type`: The *alias* defined in the `Translatable` attribute (e.g., `product`) | |
| - `object_id`: The ID of the translated entity | |
| - `locale`: The locale of the translation (e.g., `fr`) | |
| - `field`: The entity property name being translated (e.g., `description`) | |
| - `value`: The translated value | |
| Each row represents a single property translation for a specific entity in a specific locale. | |
| You can manage these translations yourself but two console commands are provided to help: | |
| ### `object-translation:export` | |
| `` | |
| This command exports all entity translations, in your default locale, to a CSV file. | |
| ```bash | |
| symfony console object-translation:export translations.csv | |
| ``` | |
| This will create a `translations.csv` file at the root of your project with the following structure: | |
| ```csv | |
| type,id,field,value | |
| ``` | |
| You can then take this file to translation service for translation. Be sure to keep | |
| the `type`, `id`, and `field` columns intact. The `value` column is what needs to be translated | |
| into the desired language. | |
| ### `object-translation:import` | |
| This command imports translations from a CSV file created by the `export` command after | |
| the `value` column has been translated. | |
| ```bash | |
| symfony console object-translation:import translations_fr.csv fr | |
| ``` | |
| The first argument is the path to the CSV file, and the second argument is the locale | |
| of the translations in that file. | |
| ## Translation Caching | |
| For performance, translations are cached. By default, they use your `cache.app` pool | |
| and have no expiration time. This can be configured: | |
| ```yaml | |
| symfonycasts_object_translation: | |
| cache: | |
| pool: 'cache.object_translation' # a custom pool name | |
| ttl: 3600 # expire after one hour | |
| ``` | |
| ### Translation Tags | |
| If your cache pool supports *cache tagging*, tags are added to the cache keys. Two keys | |
| are added: | |
| - `object-translation`: All translations are tagged with this key. | |
| - `object-translation-{type}`: Where `{type}` is the translatable alias (e.g., `product`). | |
| You can invalidate these tags by using the `cache:pool:invalidate-tags` command: | |
| ```bash | |
| # invalidate all object translation caches | |
| symfony console cache:pool:invalidate-tags object-translation | |
| # invalidate only the translation cache for "product" entities | |
| symfony console cache:pool:invalidate-tags object-translation-product | |
| ``` | |
| ### `object-translation:warmup` Command | |
| This command preloads all translations into the cache for all your | |
| app's enabled locales. | |
| ```bash | |
| symfony console object-translation:warmup | |
| ``` | |
| ## Full Default Configuration | |
| ```yaml | |
| symfonycasts_object_translation: | |
| # The class name of your translation entity. | |
| translation_class: ~ # Required, Example: App\Entity\Translation | |
| # Cache settings for object translations. | |
| cache: | |
| enabled: true | |
| # The cache pool to use for storing object translations. | |
| pool: cache.app | |
| # The time-to-livefor cached translations, in seconds, null for no expiration. | |
| ttl: null | |
| ``` |
Ahora bien, la guía de buenas prácticas de Symfony Bundle recomienda un directorio docpara albergar la documentación y que ésta se escriba en formato "reStructuredText" (o rst).
Yo me alejo de esta recomendación por un par de razones. En primer lugar, rst no se muestra tan bien en GitHub como los archivos Markdown. En segundo lugar, a menos que la documentación empiece a ser realmente grande, me gusta que se muestre inmediatamente cuando alguien visita el repositorio de GitHub. Por tanto, prefiero que la documentación esté en el archivo README.
Hagamos un repaso rápido de lo que he escrito. Comienza con las instrucciones de instalación y cómo activar y configurar el bundle. A continuación, cómo marcar tus entidades como traducibles...
Una sección de uso para mostrar cómo utilizar el servicio ObjectTranslator y el filtro Twig translate_object.
La sección de gestión de traducciones ofrece detalles sobre la estructura de la base de datos y cómo utilizar los comandos de exportación e importación.
A continuación, algo de información sobre el sistema de caché, incluido el comando warmup.
Por último, me gusta incluir la configuración por defecto completa, ¡porque es muy fácil de generar! ¿Te acuerdas?
En el terminal, asegúrate de que estás en la raíz de nuestra aplicación, no en el bundle. Luego ejecuta:
symfony console config:dump-reference symfonycasts_object_translation
Me suena. Siempre que cambies la configuración, puedes actualizar fácilmente esta sección volviendo a ejecutar ese comando y copiando/pegando el resultado. ¡Configuración autodocumentada para ganar!
.editorconfig Archivo
A continuación, copia el archivo .editorconfig de la raíz de nuestro proyecto al bundle:
| # editorconfig.org | |
| root = true | |
| [*] | |
| charset = utf-8 | |
| end_of_line = lf | |
| indent_size = 4 | |
| indent_style = space | |
| insert_final_newline = true | |
| trim_trailing_whitespace = true | |
| [{compose.yaml,compose.*.yaml}] | |
| indent_size = 2 | |
| [*.md] | |
| trim_trailing_whitespace = false |
Este archivo garantiza la coherencia en aspectos como el espaciado y las nuevas líneas. Muchos IDEs, incluido PhpStorm, admiten este archivo. Ayuda a evitar confirmaciones extrañas con diferentes espacios en blanco y caracteres de salto de línea. Esto es especialmente útil cuando alguien está desarrollando en Windows, que utiliza diferentes terminaciones de línea que macOS o Linux.
.gitattributes Archivo
En la raíz de nuestro bundle, crea un nuevo archivo llamado .gitattributes. Dentro, añade /tests export-ignore:
| /tests export-ignore |
Esto indica a Composer que excluya el directorio testsal instalar este paquete como dependencia. No es necesario que las pruebas de nuestro bundle se incluyan en el proyecto de un usuario final.
Reparador PHP CS
Al igual que la coherencia que proporciona el archivo .editorconfig para los espacios en blanco y los saltos de línea, también es importante tener un estilo de codificación coherente. Se trata de cosas como el espacio entre el espacio de nombres y las declaraciones de uso, o dónde colocar las llaves. Un estilo de codificación coherente hace que tu código sea más fácil de leer y ayuda a los colaboradores.
Una gran herramienta para reforzar y automatizar esto es PHP CS Fixer. En el terminal, asegúrate de que estás en el directorio bundle y ejecuta:
symfony composer require --dev php-cs-fixer/shim
Si ya has utilizado antes esta herramienta pero este paquete shim es nuevo para ti, no es más que una versión compilada de PHP CS Fixer que facilita la instalación.
Una vez instalado, coge el archivo .php-cs-fixer.dist.php del directorio del tutorial y cópialo en la raíz de nuestro object-translation-bundle:
| return (new PhpCsFixer\Config()) | |
| ->setRules([ | |
| '@Symfony' => true, | |
| ]) | |
| ->setFinder( | |
| (new PhpCsFixer\Finder()) | |
| ->in([__DIR__.'/src', __DIR__.'/tests']) | |
| ) | |
| ; |
Este archivo configura las reglas de estilo de codificación para tu proyecto. Ábrelo y echa un vistazo.
Estamos utilizando el conjunto de reglas de Symfony, por lo que nuestro estilo de codificación coincidirá con el de Symfony. A continuación, le indicamos dónde buscar los archivos PHP que hay que corregir: los directorios src y tests.
Para ejecutarlo, en el terminal, ejecuta:
symfony php vendor/bin/php-cs-fixer fix -v
Genial, aquí están todos los archivos que se modificaron y las reglas que se aplicaron.
El primero, TranslatedObject aplicó la regla phpdoc_align. Abramos ese archivo para ver qué cambió. Ah, añadió espaciado para alinear los nombres de las variables @param. En general, son más fáciles de leer cuando están alineados.
Este archivo .php-cs-fixer.cache de la raíz de nuestro bundle se generó cuando lo ejecutamos. Es sólo una caché para que las siguientes ejecuciones de PHP CS Fixer sean más rápidas. Añade esto a nuestro archivo .gitignore para que no se confirme:
| // ... lines 1 - 4 | |
| .php-cs-fixer.cache |
A continuación, vamos a utilizar PHPStan para ejecutar un análisis estático del código de nuestro bundle