Hablemos de su proyecto
Partitech Sonata Extra Bundle

Sonata Extra Bundle: módulo de blog

Sonata Extra Bundle proporciona un módulo de blog integrado en Sonata Page, con rutas personalizables y un renderizado adaptado a sitios multilingües. Integración de las rutas principales Actualización de las rutas principales del blog Integre las páginas ...

Contrôles de compatibilité Symfony et Sonata

Sonata Extra Bundle proporciona un módulo de blog integrado en Sonata Page, con rutas personalizables y un renderizado adaptado a sitios multilingües.

Integración de las rutas principales

Actualización de las rutas principales del blog

Integre las páginas de su sitio con el controlador de blog ejecutando el update-core-route pedido:

php bin/console sonata:page:update-core-routes --site={id}

La ejecución de este comando sincroniza la página Sonata con las siguientes rutas híbridas:

  • Categoría del blog: /blog-category/{category}
  • Etiqueta de blog: /blog-tag/{tag}
  • Artículo de blog : /blog-article/{article}

Estas rutas corresponden a páginas generadas dinámicamente que están vinculadas a sus respectivos controladores.

Personalización de rutas

Personalice los modelos de ruta predeterminados para localizar o modificar la estructura de su URL mientras mantiene el enlace con el controlador modificando los detalles de la página:

  • Un oyente de eventos en routing.loader se añade automáticamente.
  • Se crea una nueva ruta con su modelo personalizado a partir del campo custom_url.

Blog_UrlPersonalizada.png

Consulte el siguiente modelo para generar rutas de URL en Twig:

{{  path('sonata_extra_blog_category', {'category': category.getSlug()}) }}
{{  path('sonata_extra_blog_tag', {'tag': tag.getSlug()}) }}
{{  path('sonata_extra_blog_article', {'article': article.getSlug()}) }}

Plantillas y renderizado

Conecte la producción de contenido de su blog con la configuración de su modelo utilizando el Blog page type. Este tipo de servicio de página se explica en detalle en el Documentación de SonataPageBundle.

Variables Twig disponibles

El Blog page el servicio proporciona las siguientes variables a su modelo para una integración sin problemas:

Blog_TipoDeServicio.png

  • content : El contenido HTML de su blog.
  • page : El SonataPagePage instancia de entidad.
  • site : El SonataPageSite instancia de entidad.

Muestre el contenido de su blog en su plantilla Twig de la siguiente manera:

{{ content|raw }}

Para el artículo de página, la categoría y las etiquetas, el servicio también pondrá a disposición parámetros SEO:

  • ogTitle
  • ogDescription
  • ogImage : La ruta de la imagen ya se calculará. Asegúrese de tener un formato de imagen nombrado og_image si no reference será utilizado. Como las redes sociales tienen un ancho/alto máximo, no se recomienda utilizar el reference formato.
  • seoTitle
  • seoKeyword
  • seoDescription

En su modelo, puede usarlo así

{% block sonata_seo_title %}
    {% apply spaceless %}
        <title>{{ seoTitle|default('Titre par défaut') }}</title>
    {% endapply %}
{% endblock %}

{% block sonata_seo_metadatas %}
    {% apply spaceless %}
        {% if seoDescription is defined %}
            <meta name="description" content="{{ seoDescription }}">
        {% endif %}
        {% if seoKeyword is defined %}
            <meta name="keywords" content="{{ seoKeyword }}">
        {% endif %}
    {% endapply %}
{% endblock %}

{% block app_og_metadatas %}
    {% apply spaceless %}
        {% if ogTitle is defined %}
            <meta property="og:title" content="{{ ogTitle }}">
        {% endif %}
        {% if ogDescription is defined %}
            <meta property="og:description" content="{{ ogDescription }}">
        {% endif %}
        {% if ogImage is  defined %}
            <meta property="og:image" content="{{ absolute_url(ogImage) }}">
        {% endif %}
        <meta property="og:type" content="article">
    {% endapply %}
{% endblock %}

y en su modelo base

    {% block sonata_seo_title %}
        {{ sonata_seo_title() }}
    {% endblock %}
    {% block sonata_seo_metadatas %}
        {{ sonata_seo_metadatas() }}
    {% endblock %}
    {% block app_og_metadatas %}
        {{ app_og_metadatas() }}
    {% endblock %}

La entidad Categoría y Etiqueta debería tener los campos de referencia

  • App\Entyty\SonataClassificationCategory.php :
<?php
namespace App\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Sonata\ClassificationBundle\Entity\BaseCategory;
use Partitech\SonataExtra\Traits\EntityTranslationTrait;
use Partitech\SonataExtra\Contract\MediaInterface;

#[ORM\Entity]
#[ORM\Table(name: 'classification__category')]
class SonataClassificationCategory extends BaseCategory
{
    use EntityTranslationTrait;
    #[ORM\Id]
    #[ORM\Column(type: Types::INTEGER)]
    #[ORM\GeneratedValue]
    protected ?int $id = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    #[ORM\ManyToOne(targetEntity: MediaInterface::class, cascade: ["persist"])]
    #[ORM\JoinColumn(name: "featured_image__media_id", referencedColumnName: "id", nullable: true, onDelete: "SET NULL")]
    private $featured_image = null;


    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $seo_title = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $seo_keywords = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $seo_description = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $seo_og_title = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $seo_og_description = null;

    #[ORM\ManyToOne(targetEntity: MediaInterface::class, cascade: ["persist"])]
    #[ORM\JoinColumn(name: "seo_og_image__media_id", referencedColumnName: "id", nullable: true, onDelete: "SET NULL")]
    private $seo_og_image = null;

    public function getFeaturedImage()
    {
        return $this->featured_image;
    }

    public function setFeaturedImage($featured_image): self
    {
        $this->featured_image = $featured_image;

        return $this;
    }

    public function getSeoTitle(): ?string {
        return $this->seo_title;
    }

    public function setSeoTitle(?string $seo_title): self {
        $this->seo_title = $seo_title;
        return $this;
    }

    public function getSeoKeywords(): ?string {
        return $this->seo_keywords;
    }

    public function setSeoKeywords(?string $seo_keywords): self {
        $this->seo_keywords = $seo_keywords;
        return $this;
    }

    public function getSeoDescription(): ?string {
        return $this->seo_description;
    }

    public function setSeoDescription(?string $seo_description): self {
        $this->seo_description = $seo_description;
        return $this;
    }

    public function getSeoOgTitle(): ?string {
        return $this->seo_og_title;
    }

    public function setSeoOgTitle(?string $seo_og_title): self {
        $this->seo_og_title = $seo_og_title;
        return $this;
    }

    public function getSeoOgDescription(): ?string {
        return $this->seo_og_description;
    }

    public function setSeoOgDescription(?string $seo_og_description): self {
        $this->seo_og_description = $seo_og_description;
        return $this;
    }

    public function getSeoOgImage() {
        return $this->seo_og_image;
    }

    public function setSeoOgImage($seo_og_image): self {
        $this->seo_og_image = $seo_og_image;
        return $this;
    }
}
  • App\Entyty\SonataClassificationTag :
<?php

declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\DBAL\Types\Types;
use App\Repository\SonataClassificationTagRepository;
use Sonata\ClassificationBundle\Entity\BaseTag;
use Partitech\SonataExtra\Traits\EntityTranslationTrait;
use Partitech\SonataExtra\Contract\MediaInterface;

#[ORM\Entity(repositoryClass: SonataClassificationTagRepository::class)]
#[ORM\Table(name: 'classification__tag')]
#[ORM\HasLifecycleCallbacks]

class SonataClassificationTag extends BaseTag
{
    use EntityTranslationTrait;

    #[ORM\Id]
    #[ORM\Column(type: Types::INTEGER)]
    #[ORM\GeneratedValue]
    protected ?int $id = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    #[ORM\ManyToOne(targetEntity: MediaInterface::class, cascade: ["persist"])]
    #[ORM\JoinColumn(name: "featured_image__media_id", referencedColumnName: "id", nullable: true, onDelete: "SET NULL")]
    private $featured_image = null;


    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $seo_title = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $seo_keywords = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $seo_description = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $seo_og_title = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $seo_og_description = null;

    #[ORM\ManyToOne(targetEntity: MediaInterface::class, cascade: ["persist"])]
    #[ORM\JoinColumn(name: "seo_og_image__media_id", referencedColumnName: "id", nullable: true, onDelete: "SET NULL")]
    private $seo_og_image = null;

    public function getFeaturedImage()
    {
        return $this->featured_image;
    }

    public function setFeaturedImage($featured_image): self
    {
        $this->featured_image = $featured_image;

        return $this;
    }

    public function getSeoTitle(): ?string {
        return $this->seo_title;
    }

    public function setSeoTitle(?string $seo_title): self {
        $this->seo_title = $seo_title;
        return $this;
    }

    public function getSeoKeywords(): ?string {
        return $this->seo_keywords;
    }

    public function setSeoKeywords(?string $seo_keywords): self {
        $this->seo_keywords = $seo_keywords;
        return $this;
    }

    public function getSeoDescription(): ?string {
        return $this->seo_description;
    }

    public function setSeoDescription(?string $seo_description): self {
        $this->seo_description = $seo_description;
        return $this;
    }

    public function getSeoOgTitle(): ?string {
        return $this->seo_og_title;
    }

    public function setSeoOgTitle(?string $seo_og_title): self {
        $this->seo_og_title = $seo_og_title;
        return $this;
    }

    public function getSeoOgDescription(): ?string {
        return $this->seo_og_description;
    }

    public function setSeoOgDescription(?string $seo_og_description): self {
        $this->seo_og_description = $seo_og_description;
        return $this;
    }

    public function getSeoOgImage() {
        return $this->seo_og_image;
    }

    public function setSeoOgImage($seo_og_image): self {
        $this->seo_og_image = $seo_og_image;
        return $this;
    }
}

Adaptar el ejemplo a la versión instalada

Los ejemplos de Symfony y Sonata permanecen ligados a las versiones indicadas en el artículo. Symfony 4.x y Symfony 6.2 ya no se mantienen: para un proyecto actual, utilice una rama mantenida y la documentación que corresponda exactamente a sus dependencias.

php bin/console about
composer show symfony/framework-bundle sonata-project/admin-bundle

Antes de retomar el código, controle las firmas, los servicios, las rutas y las plantillas correspondientes. Después, agregue una prueba funcional que cubra los permisos, el código HTTP y el resultado visible.

Referencia: versiones de Symfony mantenidas.

Compartir este artículo