Sonata : Créer un MediaBlock personnalisé

Ce document se base sur la documentation de Sonata décrivant la procédure pour créer un block personnalisé.

Exposition du cas: On désire créer un slide show ou un carrousel quelconque on veut pouvoir le gérer via SonataPage, c’est à dire pouvoir gérer les images qui défilent via le CMS. L’idée est de créer un block container content_slide par exemple et pouvoir gérer les images du carrousel via des blocks media.

Nous aurons besoin des éléments suivants:

  • Créer un block media personnalisé qui contiendra une image, un titre et un lien
  • Créer un contexte personnalisé slide pour lequel on définira une taille de miniature spécifique

Pour réaliser cela, nous nous baserons la documentation de Sonata indiquée en début d’article. Le principe reste le même pour un MediaBlock avec quelques ajustements. Tout d’abord, voici la structure de notre Bundle :

/src
    /Coolcoyote
        /BlocksBundle
            /Block
                /SlideMediaBlockService.php
            /DependencyInjection
                /Configuration.php
                /CoolcoyoteBlocksExtension.php
            /Resources
                /config
                    /services.xml
                /views
                    /Block
                        block_slide_media.twig.html
            /CoolcoyoteBlocksBundle.php

Voilà, nous n’avons pas besoin de plus pour le moment. Dans le fichier SlideMediaBlockService.php, on rajoutera :

1
use Sonata\MediaBundle\Block\MediaBlockService;

puis on modifiera la déclaration pour étendre MediaBlockService au lieu de BaseBlockService :

1
class SlideMediaBlockService extends MediaBlockService

On personnalise setDefaultSettings() pour y inclure les informations du Media

1
2
3
4
5
6
7
8
9
10
11
12
public function setDefaultSettings(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'media'   => false,
            'title'   => false,
            'url'     => false,
            'context' => false,
            'mediaId'  => null,
            'format'  => false,
            'template' => 'CoolcoyoteBlocksBundle:Block:block_slide_media.html.twig'
        ));
    }

Les paramètres media, context, mediaId et format sont nécessaires pour la gestion des médias. les paramètres title et url représentent nos champs personnalisés.

On construit le formulaire comme suit :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
{
    $contextChoices = $this->getContextChoices();
    $formatChoices = $this->getFormatChoices($block->getSetting('mediaId'));
 
    $translator = $this->container->get('translator');
 
    $formMapper->add('settings', 'sonata_type_immutable_array', array(
        'keys' => array(
            array('title', 'text', array('required' => true)),
            array('url', 'url', array('required' => true)),
            array('context', 'choice', array('required' => true, 'choices' => $contextChoices)),
            array('format', 'choice', array('required' => count($formatChoices) > 0, 'choices' => $formatChoices)),
            array($this->getMediaBuilder($formMapper), null, array()),
        )
    ));
}

Voici le fichier complet :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?php
 
namespace Coolcoyote\BlocksBundle\Block;
 
use Sonata\MediaBundle\Block\MediaBlockService;
use Sonata\AdminBundle\Form\FormMapper;
 
use Sonata\BlockBundle\Block\BlockContextInterface;
use Sonata\BlockBundle\Model\BlockInterface;
 
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
 
/**
 * MediaExtension
 *
 */
class SlideMediaBlockService extends MediaBlockService
{
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'Slide Media';
    }
 
    /**
     * {@inheritdoc}
     */
    public function setDefaultSettings(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'media'   => false,
            'title'   => false,
            'url'     => false,
            'context' => false,
            'mediaId'  => null,
            'format'  => false,
            'template' => 'CoolcoyoteBlocksBundle:Block:block_slide_media.html.twig'
        ));
    }
 
    /**
     * {@inheritdoc}
     */
    public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
    {
        $contextChoices = $this->getContextChoices();
        $formatChoices = $this->getFormatChoices($block->getSetting('mediaId'));
 
        $translator = $this->container->get('translator');
 
        $formMapper->add('settings', 'sonata_type_immutable_array', array(
            'keys' => array(
                array('title', 'text', array('required' => true)),
                array('url', 'url', array('required' => true)),
                array('context', 'choice', array('required' => true, 'choices' => $contextChoices)),
                array('format', 'choice', array('required' => count($formatChoices) > 0, 'choices' => $formatChoices)),
                array($this->getMediaBuilder($formMapper), null, array()),
            )
        ));
    }
 
    /**
     * {@inheritdoc}
     */
    public function execute(BlockContextInterface $blockContext, Response $response = null)
    {
        return $this->renderResponse($blockContext->getTemplate(), array(
            'media'     => $blockContext->getSetting('mediaId'),
            'block'     => $blockContext->getBlock(),
            'settings'  => $blockContext->getSettings()
        ), $response);
    }
}

On va devoir aussi modifier un peu la déclaration du service dans services.xml :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <parameters>
        <parameter key="coolcoyote.media.block.slide.class">Coolcoyote\BlocksBundle\Block\SlideMediaBlockService</parameter>
    </parameters>
 
    <services>
        <service id="coolcoyote.media.block.slide">
            <tag name="sonata.block" />
            <argument>coolcoyote.media.block.slide</argument>
            <argument type="service" id="templating" />
            <argument type="service" id="service_container" />
            <argument type="service" id="sonata.media.manager.media" />
        </service>
    </services>
</container>

Pour info, si vous voulez pouvoir parser le fichier en XML, il faut modifier le fichier DependencyInjection/CoolcoyoteBlocksExtension.php et changer les lignes :

1
2
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');

Par

1
2
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');

Pour finir, ne pas oublier de préparer le template block_slide_media.twig.html :

{% extends sonata_block.templates.block_base %}

{% block block %}

    <div>

        <div>
            {% if media %}
                <a href="{{ settings.url }}">{% media media, settings.format %}</a>
            {% else %}
                {# no media selected ... #}
            {% endif %}
        </div>

        {% if settings.title %}
            <h3>{{ settings.title }}</h3>
        {% endif %}

        <div style="clear: both"></div>
    </div>
{% endblock %}

Le template ici est un peu fait à l’arrache, c’est juste à titre d’exemple.

Nous allons maintenant, activer notre bundle dans AppKernel.php :

1
2
3
4
5
6
7
8
9
public function registerBundles()
{
    $bundles = array(
        // ...
        new Coolcoyote\BlocksBundle\CoolcoyoteBlocksBundle(),
    );
 
    // ...
}

Puis ajouter notre block aux autres blocks disponibles dans config.yml :

sonata_block:
    # ...
    blocks:
        #...
        coolcoyote.media.block.slide:

Et pour finir ajouter notre contexte slide, toujours dans config.yml

sonata_media:
    # ...
    contexts:
        default:  # the default context is mandatory
            # ...

        slide:
            providers:
                - sonata.media.provider.image

            formats:
                small: { width: 100 , quality: 70}

L’avantage de ce nouveau contexte, c’est qu’il permet d’une part de définir un format spécifique, mais aussi de limiter les providers à une image, ce qui exclue les vidéos etc… Désormais, le nouveau block devrait être disponible !

Mots-clefs : , , ,



Laisser une réponse

Vous devez être connecté pour publier un commentaire.