preloader

Intégration du Carousel Bootst...

Intégration du Carousel Bootstrap 5 avec Symfony 5.1

Contexte

On souhaite mettre en place un Slider Bootstrap sur toutes les pages du site de notre application Symfony 5 (SF 5). Ce Carousel sera placé dans le template principal.

Les données alimentant le Carousel proviennent de la la base de données. Dans le cas qui nous concerne, notre Carousel va afficher les 1O films les mieux notés.

Concernant l'intégration de Bootstrap 5, confère ce tuto .

Tout d'abord nous allons mettre en place un listener(Subscriber) qui va écouter l'événement kernel.controller', lequel événement est déclenché avant que le contrôleur ne s'exécute. C'est à ce moment que nous allons injecter une variable globale à Twig juste avant que le contrôleur ne génère le template.

 

Le modèle de données

Nous disposons des entités suivantes:


//entité Movie

class Movie {
	/**
	 * @ORM\Id
	 * @ORM\GeneratedValue
	 * @ORM\Column(type="integer")
	 */
	private $id;

	/**
	 * @ORM\Column(type="string", length=255)
	 */
	private $title;

	/**
	 * @ORM\Column(type="integer")
	 */
	private $year;

	/**
	 * @ORM\Column(type="text", nullable=true)
	 */
	private $description;

	/**
	 * @ORM\OneToMany(targetEntity=Picture::class, mappedBy="movie", orphanRemoval=true, cascade={"persist"},fetch="EAGER")
	 */
	private $pictures;

	/**
	 * @ORM\ManyToMany(targetEntity=Genre::class, mappedBy="movies")
	 */
	private $genres;

	/**
	 * @ORM\Column(type="integer", nullable=true)
	 */
	private $likes;

	/**
	 * @ORM\ManyToMany(targetEntity=Actor::class, mappedBy="movies", fetch="EAGER")
	 */
	private $actors;

// ...
}

//entité Actor
class Actor {
	/**
	 * @ORM\Id
	 * @ORM\GeneratedValue
	 * @ORM\Column(type="integer")
	 */
	private $id;

	/**
	 * @ORM\Column(type="string", length=50)
	 */
	private $name;

    /**
     * @ORM\ManyToMany(targetEntity=Movie::class, inversedBy="actors")
     */
    private $movies;

//...
}

//entité  Genre
class Genre {
	/**
	 * @ORM\Id
	 * @ORM\GeneratedValue
	 * @ORM\Column(type="integer")
	 */
	private $id;

	/**
	 * @ORM\Column(type="string", length=255)
	 */
	private $name;

	/**
	 * @ORM\ManyToMany(targetEntity=Movie::class, inversedBy="genres")
	 */
	private $movies;

//...
}

//entité Picture

class Picture {
	/**
	 * @ORM\Id
	 * @ORM\GeneratedValue
	 * @ORM\Column(type="integer")
	 */
	private $id;

	/**
	 * @ORM\Column(type="string", length=255, nullable=true)
	 */
	private $name;

	/**
	 * @ORM\ManyToOne(targetEntity=Movie::class, inversedBy="pictures")
	 * @ORM\JoinColumn(nullable=false)
	 */
	private $movie;

//...
}

On récupère les 10 films les mieux notés:


//MovieRepository.php
public function findMostLovedMovies(?int $limit = 10): ?iterable {

  return $this->createQueryBuilder('m')
	 ->addSelect('m', 'p')
	 ->leftJoin('m.pictures', 'p')
	 ->orderBy('m.likes', 'DESC')
	 ->getQuery()
	 ->setMaxResults($limit)
	->getArrayResult();
}

Générer un Subscriber:

Exécuter la commande suivante pour générer un subscriber:

php bin/console make:subscriber MostLovedMoviesSubscriber

Cette commande va demander  l'événement  qu'on veut écouter. Choisir l'événement kernel.controller


namespace App\EventSubscriber;

use App\Repository\MovieRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Twig\Environment;

/**
 * Class MostLovedMoviesSubscriber
 * @package App\EventSubscriber
 *
 *  Représente le Listener écoutant l'événement 'kernel.controller'.
 */
class MostLovedMoviesSubscriber implements EventSubscriberInterface {
	/**
	 * @var Environment
	 */
	private $environment;
	/**
	 * @var MovieRepository
	 */
	private $movieRepository;

	/**
	 * MostLovedMoviesSubscriber constructor.
	 * @param Environment $environment
	 * @param MovieRepository $movieRepository
	 */
	public function __construct(Environment $environment, MovieRepository $movieRepository) {
		$this->environment = $environment;
		$this->movieRepository = $movieRepository;
	}

	/**
         *  Méthode appelée au déclenchement de l'Event kernel.controller
	 * Injection de la variable globale mostLovedMovies à Twig
	 *
	 * @param ControllerEvent $event
	 */
	public function onKernelController(ControllerEvent $event) {

		$this->environment->addGlobal('mostLovedMovies', $this->movieRepository->findMostLovedMovies());
	}

	/**
	 *
	 * @return array
	 */
	public static function getSubscribedEvents(): array {
		return [
			'kernel.controller' => 'onKernelController',
		];
	}
}

 

Le template principal base.html.twig , contiendrait le Carousel qui lui même est constitué des films les mieux notés:

<div id="carouselExampleCaptions" class="carousel slide mt-0" data-ride="carousel" >
    <ol class="carousel-indicators">

        {% for item in mostLovedMovies %}
            <li data-target="#carouselExampleCaptions" data-slide-to="{{ loop.index-1 }}" class="{{ loop.first ? 'active': '' }} "></li>
        {% endfor %}

    </ol>

    <div class="carousel-inner">
        {#
        variable gobale mostLovedMovies contenant les 10 films les mieux notés( films à la une).
        On boucle sur cette variable pour afficher les films à la une( titre, image
        et une partie de la description du film).
        #}
        {% for item in mostLovedMovies %}
            <div class="carousel-item {{ loop.first ? 'active': '' }} ">
                <img src="{{ asset('images/'~item['pictures'][0]['name']) }}" class="d-block img-fluid" alt="...">
                <div class="carousel-caption d-none d-md-block bg-primary text-white">
                    <h5 class="text-"> {{  item['title'] }}</h5>
                    <p >{{  item['description'] | slice(0,100)}} </p>
                </div>
            </div>
        {% endfor %}

    </div>
    <a class="carousel-control-prev" href="#carouselExampleCaptions" role="button" data-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="sr-only">Previous</span>
    </a>
    <a class="carousel-control-next" href="#carouselExampleCaptions" role="button" data-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="sr-only">Next</span>
    </a>
</div>

codes sources