Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Personalizar el Slugger de Contentful

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.

Antes de que sigamos personalizando el aspecto de nuestro sitio, quiero arreglar las URL de las habilidades para que en lugar de ser /mashing, la página sea /skills/mashing. Recuerda: el hecho de que nuestro contenido Contentful tenga instantáneamente URL en nuestro sitio proviene del paquete Contentful que instalamos antes. Pero esa magia no tiene nada que ver con los Diseños. Por tanto, personalizar esta URL también es específico de Contentful, no de Layouts. Pero... Realmente quiero arreglarlo.

Crear la clase Slugger

En el directorio src/Layouts/, crea una nueva clase llamada ContentfulSlugger. Haz que implemente EntrySluggerInterface... y genera el único método que necesitamos: getSlug():

... lines 1 - 2
namespace App\Layouts;
use Netgen\Layouts\Contentful\Entity\ContentfulEntry;
use Netgen\Layouts\Contentful\Routing\EntrySluggerInterface;
class ContentfulSlugger implements EntrySluggerInterface
{
public function getSlug(ContentfulEntry $contentfulEntry): string
{
// TODO: Implement getSlug() method.
}
}

Vamos a configurar las cosas para que se llame a este método cuando se creen las URL dinámicas de todas las entradas de Contentful. Nos permitirá controlar el "slug", que en realidad es la URL de cada elemento.

Para facilitarte las cosas, utiliza FilterSlugTrait para acceder a un método que utilizaremos dentro de un minuto:

... lines 1 - 5
use Netgen\Layouts\Contentful\Routing\EntrySlugger\FilterSlugTrait;
... lines 7 - 8
class ContentfulSlugger implements EntrySluggerInterface
{
use FilterSlugTrait;
... lines 12 - 20
}

Vale, en Contentful tenemos tanto Habilidades como Anuncios. Pero en realidad no queremos que los anuncios tengan su propia página. Por desgracia, con la integración de Contentful, no hay forma de desactivar las URL para un tipo de contenido específico. Hablaré de cómo solucionarlo en un minuto.

En cualquier caso, este método se pasará tanto a las habilidades como a los anuncios. Utiliza la nueva función PHP match() para que coincida con $contentfulEntry->getContentType()->getId(). Eso devolverá el nombre interno de cada tipo, que puedes encontrar en Contentful. Si es skill, devuelve /skills/ y luego $this->filtersSlug() -que viene del rasgo- pasando $contentfulEntry->get('title'):

... lines 1 - 8
class ContentfulSlugger implements EntrySluggerInterface
{
... lines 11 - 12
public function getSlug(ContentfulEntry $contentfulEntry): string
{
return match ($contentfulEntry->getContentType()->getId()) {
'skill' => '/skills/'.$this->filterSlug($contentfulEntry->get('title')),
... lines 17 - 18
};
}
}

Para advertisement, devuelve /_ad para todos ellos:

... lines 1 - 8
class ContentfulSlugger implements EntrySluggerInterface
{
... lines 11 - 12
public function getSlug(ContentfulEntry $contentfulEntry): string
{
return match ($contentfulEntry->getContentType()->getId()) {
'skill' => '/skills/'.$this->filterSlug($contentfulEntry->get('title')),
'advertisement' => '/_ad',
... line 18
};
}
}

Al menos, en este punto, sólo un anuncio podría tener una página en nuestro sitio: si el usuario fuera a /_ad, coincidiría con el primero.

Al final, lanza una nueva Excepción con "Tipo no válido":

... lines 1 - 8
class ContentfulSlugger implements EntrySluggerInterface
{
... lines 11 - 12
public function getSlug(ContentfulEntry $contentfulEntry): string
{
return match ($contentfulEntry->getContentType()->getId()) {
'skill' => '/skills/'.$this->filterSlug($contentfulEntry->get('title')),
'advertisement' => '/_ad',
default => throw new \Exception('Invalid type'),
};
}
}

Así que, sí, en este punto, los anuncios seguirán teniendo su propia página. No hay forma de desactivar eso desde el principio. Pero si te importa lo suficiente, yo asignaría todos los anuncios a la misma URL o patrón de URL de esta forma. Luego crearía una ruta y un controlador con la misma URL y devolvería un 404. Esa ruta tendrá prioridad sobre la dinámica.

Etiquetar y configurar el Slugger

Para decirle a Contentful que utilice nuestro slugger, necesitamos, por supuesto, ¡darle una etiqueta! Añade#[AutoconfigureTag] y éste se llamará netgen_layouts.contentful.entry_slugger. Esto también necesita una opción type... que puedes establecer en cualquier cadena. Utilicemosdefault_slugger:

... lines 1 - 7
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
#[AutoconfigureTag('netgen_layouts.contentful.entry_slugger', ['type' => 'default_slugger'])]
class ContentfulSlugger implements EntrySluggerInterface
{
... lines 13 - 22
}

¿Cómo se utiliza? En config/packages/, necesitamos crear un nuevo archivo de configuración para el paquete contentful de layouts. Llamémoslo netgen_layouts_contentful.yaml.

Repite eso para la clave raíz. A continuación, añade entry_slug_type, luego default configurado con el tipo que hemos utilizado en nuestra etiqueta: default_slugger:

netgen_layouts_contentful:
entry_slug_type:
default: default_slugger

Esta curiosa sintaxis dice

Para cada tipo de contenido en Contentful, utiliza default_slugger al generar la URL. Por lo tanto, utiliza nuestro ContentfulSlugger.

Vale, ¡listo! Pero... esto no se llama cuando recargamos la página. No. Se llama cuando "sincronizamos" nuestro contenido desde Contentful. Bien, ¡vamos a resincronizar! En tu terminal, ejecuta:

symfony console contentful:sync

Esto actualiza nuestra base de datos local con los últimos datos de Contentful... y funcionó bien. Pero cuando ejecutamos:

symfony console contentful:routes

¡Las URL no cambiaron! Esto es una peculiaridad... o quizás una característica para que las páginas existentes no se rompan. En cualquier caso, una vez que se importa una ruta por primera vez, su URL nunca cambia.

La forma más fácil de restablecer las cosas es eliminar la tabla de rutas y volver a importar todo.

Y esto es bastante divertido. Podemos Ejecuta:

symfony console doctrine:migrations:migrate current-1

Eso anulará la migración más reciente, haciendo que se eliminen las tablas contentful y de rutas. Vuelve a ponerlas con:

symfony console doctrine:migrations:migrate

Vuelve a sincronizar el contenido:

symfony console contentful:sync

Y ahora comprueba las rutas:

symfony console contentful:routes

¡Sí! ¡La URL es /skills/mashing! Así, en /mashing, obtenemos un 404 a la antigua usanza. Pero /skills/mashing funciona.

Siguiente: aún no tenemos una página que enumere todas las habilidades. ¡Vamos a arreglarlo!

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.7", // v3.7.0
        "doctrine/doctrine-bundle": "^2.7", // 2.7.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.13", // 2.13.3
        "easycorp/easyadmin-bundle": "^4.4", // v4.4.1
        "netgen/layouts-contentful": "^1.3", // 1.3.2
        "netgen/layouts-standard": "^1.3", // 1.3.1
        "pagerfanta/doctrine-orm-adapter": "^3.6",
        "sensio/framework-extra-bundle": "^6.2", // v6.2.8
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.0
        "symfony/console": "5.4.*", // v5.4.14
        "symfony/dotenv": "5.4.*", // v5.4.5
        "symfony/flex": "^1.17|^2", // v2.2.3
        "symfony/framework-bundle": "5.4.*", // v5.4.14
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "5.4.*", // v5.4.6
        "symfony/runtime": "5.4.*", // v5.4.11
        "symfony/security-bundle": "5.4.*", // v5.4.11
        "symfony/twig-bundle": "5.4.*", // v5.4.8
        "symfony/ux-live-component": "^2.x-dev", // 2.x-dev
        "symfony/ux-twig-component": "^2.x-dev", // 2.x-dev
        "symfony/validator": "5.4.*", // v5.4.14
        "symfony/webpack-encore-bundle": "^1.15", // v1.16.0
        "symfony/yaml": "5.4.*", // v5.4.14
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.3
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "5.4.*", // v5.4.11
        "symfony/maker-bundle": "^1.47", // v1.47.0
        "symfony/stopwatch": "5.4.*", // v5.4.13
        "symfony/web-profiler-bundle": "5.4.*", // v5.4.14
        "zenstruck/foundry": "^1.22" // v1.22.1
    }
}
userVoice