Crear variables globales en Symfony4

Abr. 2018 (es) Symfony 4 Symfony Services Twig

Albert Serra

El propósito de este artículo es orientar sobre la posibilidades que tenemos de pasar variables globales al render de symfony (twig). En mi caso, trabajando en desarrolo de web corporativa es habitual tener que pasar variables globales o variables que el usuario edita en el backend. También enfocado a tener un codigo recicable para futuros proyectos.

Entrando ya en el ejemplo, tengo una entidad (Entity) Project.php tabla project con el que guardamos variables del proyecto, por ejemplo, las url de las redes sociales, o el e-mail de contacto. Aquí también podemos guardar keys de api's o otras variables de configuración.

La tabla practicamente es una relación key => valor guardada en base de datos:

// src/Entity/Project.php

class Project
{
    token: string,  // por ejemplo: social_twitter
    name: string,   // por ejemplo: "URL Twitter"
    value: string,  // por ejemplo: "http://twitter.com/albertserra"
}

La finalidad es que después en twig, hacer:

<a href="{{ project.get('social_twitter') }}" target="_blank">Twitter</a>

y que imprima la url de twitter.

Así, que vamos allà.

1. Service

Vamos a crear un servicio de Symfony4 para que connecte a la base de datos, y a traves del método get le podamos pedir al ORM el valor de la key/token pedido.

// src/Service/ProjectService.php
namespace App\Service;

use Doctrine\ORM\EntityManager;
use App\Entity\Project;

class ProjectService
{

    protected $em;

    public function __construct( EntityManager $em )
    {
        $this->em = $em;
    }

    public function get( $token )
    {
        $item = $this->em->getRepository(Project::class)->findOneBy(array('token' => $token));
        return $item ? $item->getValue() : null;
    }
}

Ya hemos creado la clase y el método que devuelve el valor en función del token pasado.

2. Registro del Service

Falta registrar el servicio en la configuración de Symfony config/services.yaml dentro de la clave de services: le añadimos nuestro servicio llamado project y le pasamos como argumento el entity manager.

# config/services.yaml
services:
[ ... ]
    project:
        class: App\Service\ProjectService
        arguments: 
            - '@doctrine.orm.entity_manager'

3. Registro a twig

Le tenemos que especificar a twig que le vamos a pasar la clase de manera global, dentro de clave de twig:

# config/packages/twig.yaml

twig:
[ ... ]
    globals: 
      project: '@project'

4. Render

Ya podemos utilizar nuestra clase global en cualquier template de Twig con la sintaxis habitual {{ project.get('key') }}. En mi caso, la utilizo habitualmente para los datos del Footer: Redes sociales, Horario, E-mail de contacto, ...

Un ejemplo:

# templates/components/_PageFooter.html.twig
<footer class="PageFooter">
    <div class="PageFooter-container">
        <p>&copy; {{ project.get('project_name') }} {{ "now"|date('Y') }}</p>
        <div class="social-links">
            <a href="{{ project.get('social_facebook') }}" class="social-links__item" target="_blank">
                <i class="fa fa-fw fa-facebook" aria-hidden="true"></i>
            </a>
            <a href="{{ project.get('social_twitter') }}" class="social-links__item" target="_blank">
                <i class="fa fa-fw fa-twitter" aria-hidden="true"></i>
            </a>
            <a href="{{ project.get('social_instagram') }}" class="social-links__item" target="_blank">
                <i class="fa fa-fw fa-instagram" aria-hidden="true"></i>
            </a>
            <a href="{{ project.get('social_spotify') }}" class="social-links__item" target="_blank">
                <i class="fa fa-fw fa-spotify" aria-hidden="true"></i>
            </a>
            <a href="{{ project.get('social_youtube') }}" class="social-links__item" target="_blank">
                <i class="fa fa-fw fa-youtube" aria-hidden="true"></i>
            </a>
        </div>
    </div>
</footer>

EOF