Makina Blog

Le blog Makina-corpus

Utiliser des bundles Symfony dans Drupal 7


Notre module Drupal Symfony DIC permet d'apporter la puissance de Symfony, dans Drupal, démonstration.

Dans le cas où un client n'a pas confiance en Drupal 8 pour le moment, 2 possibilités :

  • vous pouvez anticiper l'utilisation de l'API de Drupal 8 dans D7.
  • vous pouvez développer des Bundles Symfony dans Drupal 7 pour les utiliser ensuite dans un Symfony full-stack

Voici donc comment créer certains formulaires métiers en formulaire SF3 afin de pouvoir utiliser les bundles de la communauté (en l'occurrence un bundle de Captcha). Pour cela nous auront besoin du module Drupal Symfony DIC.


Création du Bundle Symfony

Prenons l'exemple de la création d'un formulaire pour contacter un poney, avec un recaptcha, car les poneys detestent le spam. Ajoutez vos deux bundles dans app/AppKernel.php:

new \EWZ\Bundle\RecaptchaBundle\EWZRecaptchaBundle(), new PoneyBundle\PoneyBundle(),

Créer le fichier src/PoneyBundle/PoneyBundle.php :

<?php

namespace PoneyBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class PoneyBundle extends Bundle
{
}

Puis le contrôleur src/PoneyBundle/Controller/FormController.php :

<?php

namespace PoneyBundle\Controller;

use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrue;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Constraints as Assert;

class FormController extends Controller
{
    public function contactAction(Request $request)
    {
        $form = $this->createFormBuilder()
                     ->add('name', TextType::class, [
                         'label'    => "Nom",
                         'attr'     => ['placeholder' => "Jean Dupont"],
                         'required' => true,
                     ])
                     ->add('mail', EmailType::class, [
                         'label'       => "Adresse e-mail",
                         'attr'        => ['placeholder' => "jean.dupont@example.com"],
                         'required'    => true,
                         'constraints' => [
                             new Assert\Email(),
                             new Assert\Length(['max' => 63]),
                         ],
                     ])
                     ->add('reason_text', TextareaType::class, [
                         'label'       => "Message",
                         'required'    => true,
                         'attr'        => [
                             'placeholder' => "",
                             'rows'        => 10,
                         ],
                         'constraints' => [
                             new Assert\NotBlank(),
                         ],
                     ])
                     ->add('recaptcha', EWZRecaptchaType::class, [
                         'mapped'      => false,
                         'constraints' => [
                             new IsTrue(),
                         ],
                     ])
                     ->add('submit', SubmitType::class, [
                         'label' => "Envoyer",
                     ])
                     ->getForm()
        ;
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $values = $form->getData();
            // @TODO faire quelque chose de ces données
        }

        return $this->render('PoneyBundle:Form:contact.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}

et src/PoneyBundle/Resources/config/routing.yml :

contact:
    path: contact
    defaults:
        _controller: PoneyBundle:Form:contact
    methods: [GET, POST]
    options:
        drupal:
          title: Contact
          access arguments: ['use contact form']
          type: MENU_NORMAL_ITEM

et la vue src/PoneyBundle/Resources/views/Form/contact.html.twig

{{ form_start(form) }}
{{ form_errors(form) }}

<fieldset>
    <legend>Informations personnelles</legend>

    {{ form_row(form.name) }}
    {{ form_row(form.mail) }}
</fieldset>

<fieldset>
    <legend>Message</legend>

    {{ form_row(form.reason_text) }}
</fieldset>

{{ form(form) }}

{{ form_end(form) }}

Ajoutez la configuration ewz_recaptcha dans app/config/config.yml de votre application:

ewz_recaptcha:
    public_key:  here_is_your_public_key
    private_key: here_is_your_private_key

Ainsi la configuration du routeur dans app/config/routing.yml :

app:
    resource: "@PoneyBundle/Resources/config/routing.yml"
    prefix: /

Vous pouvez dès maintenant utiliser ce bundle dans Symfony, la preuve en est sur votre serveur de dev (<http://127.0.0.1:8000/contact>) :

La totalité du code est dans <https://gist.github.com/SebCorbin/95feefd34fc5c447158b31d8bbf00ac3> (attention la structure des dossiers n'a pas été conservée).


Intégration dans Drupal

Pour bootstraper Symfony dans Drupal, nous allons avoir besoin d'une configuration un peu particulière. Tous d'abord le fichier composer.json sera grandement repris de notre configuration Drupal pour composer.

{
  "name" : "Example site",
  "description" : "Drupal Site",
  "repositories": [
    { 
      "type": "composer", 
      "url": "https://packages.drupal.org/7"
    }
  ],
  "minimum-stability" : "dev",
  "prefer-stable" : true,
  "require" : {
    "composer/installers" : "^1.0.20",
    "cweagans/composer-patches" : "~1.0",
    "drush/drush": "8.*",
    "drupal/drupal": "7.*",
    "slowprog/composer-copy-file": "^0.1.2",
    "tfd7/tfd7": "dev-master",
    "makinacorpus/drupal-sf-dic": "^3.1",
    "excelwebzone/recaptcha-bundle": "^1.4",
    "twig/twig": "^1.28",
    "twig/extensions": "~1.3",
    "symfony/symfony": "~3.0"
  },
  "config" : {
    "vendor-dir" : "lib/vendor"
  },
  "extra" : {
    "installer-paths": {
      "www" : [ "type:drupal-core" ],
      "www/sites/all/modules/composer/{$name}" : [ "type:drupal-module" ],
      "www/sites/all/libraries/composer/{$name}" : [ "type:drupal-library" ],
      "www/sites/all/themes/composer/{$name}" : [ "type:drupal-theme" ]
    },
    "copy-file": {
      "www/sites/all/modules/composer/drupal-sf-dic/Resources/engine": "www/sites/all/themes/engines/twig"
    }
  },
  "scripts": {
    "copy_settings": "grep -Fq \"require_once DRUPAL_ROOT . '/../lib/vendor/autoload.php';\" www/sites/default/default.settings.php || echo \"\nrequire_once DRUPAL_ROOT . '/../lib/vendor/autoload.php';\n\n\\$GLOBALS['conf']['kernel.cache_dir'] = DRUPAL_ROOT . '/../cache/';\n\\$GLOBALS['conf']['kernel.logs_dir'] = DRUPAL_ROOT . '/../logs/';\n\" >> www/sites/default/default.settings.php",
    "post-install-cmd": [
      "SlowProg\\CopyFile\\ScriptHandler::copy",
      "@copy_settings"
    ],
    "post-update-cmd": [
      "SlowProg\\CopyFile\\ScriptHandler::copy",
      "@copy_settings"
    ]
  },
  "autoload": {
    "files": [
      "app/AppKernel.php"
    ],
    "psr-4": {
      "": "src/"
    }
  }
}

Nous avons donc ajouté la section "autoload" pour charger automatiquement le Kernel et supporter les bundles dans le dossier src/. Il suffit ensuite d'activer le module sf_dic et le configurer dans settings.php :

<?php

$conf['kernel.symfony_all_the_way'] = true;
$conf['kernel.symfony_router_enable'] = true;

Le app/AppKernel.php change légérement :

<?php

use MakinaCorpus\Drupal\Sf\Kernel;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        return [
            new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
            new \Symfony\Bundle\SecurityBundle\SecurityBundle(),
            new \Symfony\Bundle\TwigBundle\TwigBundle(),
            new \EWZ\Bundle\RecaptchaBundle\EWZRecaptchaBundle(),
            new PoneyBundle\PoneyBundle(),
        ];
    }

    public function registerContainerConfiguration(\Symfony\Component\Config\Loader\LoaderInterface $loader)
    {
        $loader->load($this->getRootDir().'/config/config.yml');
    }
}

et le app/config.yml est beaucoup plus léger :

imports:
    - { resource: parameters.yml }
    - { resource: services.yml }

parameters:
    locale: en

framework:
    secret:          "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    templating:
        engines: ['twig']
    default_locale:  "%locale%"
    trusted_hosts:   ~
    trusted_proxies: ~
    session:
        # handler_id set to null will use default session handler from php.ini
        handler_id:  ~
    fragments:       ~
    http_method_override: true

# Twig Configuration
twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"

ewz_recaptcha:
    public_key:  here_is_your_public_key
    private_key: here_is_your_private_key

Un petit flush de cache Drupal et tadaaaa :

Actualités en lien

Image
Symfony
11/04/2024

Access Control : une biblio­thèque PHP pour gérer des droits d’ac­cès

Suite à un projet de gestion métier opéra­tion­nel dont la durée de vie et la main­te­nance sont à long termes, nous avons expé­ri­menté un passage de celui-ci sur l’archi­tec­ture hexa­go­nale et la clean archi­tec­ture.

Voir l'article
Image
Migration Drupal 7 à Drupal 10
04/04/2024

Migration d'un site Drupal 7 en Drupal 10

Trucs, astuces et "bouts" de code pour migrer votre site web de Drupal 7 à Drupal 10. Compte-rendu d'une conférence donnée au Drupalcamp Rennes 2024.

Voir l'article
Image
Formation Migration Drupal 10
03/04/2024

Du nouveau dans notre gamme de forma­tions Drupal

Maîtri­sez le CMS Drupal de bout en bout avec notre panel complet de forma­tions couvrant la migra­tion (notre petite dernière), l’ad­mi­nis­tra­tion, le déve­lop­pe­ment et l’in­té­gra­tion Drupal. Pour deve­nir expert, plon­gez dans l’uni­vers Drupal !

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus