Custom Poll module - part 4 - Les résultats

Posté le: mer 27/03/2019 - 21:41 Par: rcowebdev

Concernant les résultats, je ne vois trop comment les présenter en BO; juste un tableau, un truc de fou avec des graphs de partout… Bon on va le faire dans un simple tableau pour commencer avec un lien View result.

Du coup, il nous faut un nouveau controller que j’ai nommé ResultController qui va nous permettre de sauvegarder les votes après validation (toujours être parano concernant les données soumises par un visiteur).

Alors c’est parti, on commence par nos fichiers de configuration.

poll.routing.yml

poll.result.overview:
  path: '/admin/poll_result/list'
  defaults:
    _controller: '\Drupal\poll\Controller\ResultController::overview'
    _title: 'Poll result list'
  requirements:
    _permission: 'administer poll' 
poll.result.view:
  path: '/admin/poll_result/view/{question_id}'
  defaults:
    _controller: '\Drupal\poll\Controller\ResultController::view'
    _title: 'Poll Result view'
  requirements:
    _permission: 'administer poll'
poll.result.save:
  path: '/admin/poll_result/save/{question_id}/{answer_id}'
  defaults:
    _controller: '\Drupal\poll\Controller\ResultController::save'
    _title: 'Poll result save'
  requirements:
    _permission: 'administer poll' 

Pourquoi question_id pour la route poll.result.save ? Parce qu’il peut y avoir sur la page 0 à n blocs Poll avec des questions différentes.

poll.links.menu.yml

poll.result:
  title: 'Poll Result'
  description: 'Show Poll s results'
  route_name: poll.result.overview
  parent: poll.question
  weight: 1 

Petite mésaventure à l’instant, mon lien Poll Result ne s’affichait pas en BO, c’était une erreur de synthaxe dans le fichier poll.links.menu.yml ('Show Poll's results au lieu de 'Show Poll s results', bizarre qu’en vidant les caches, Drupal ne m’ait rien dit, mais bon).

src/Controller/ResultController.php

<?php

namespace Drupal\poll\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Poll\PollManager;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Result controller.
 */
class ResultController extends ControllerBase {

  /**
   * @var Drupal\Poll\PollManager
   */
  protected $pollManager;

  /**
   * @var Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * Construct
   *
   * @param \Drupal\Poll\PollManager                       $pollManager  Poll Manager
   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack Request stack
   */
  public function __construct(
    PollManager $pollManager,
    RequestStack $requestStack
  ) {

    $this->pollManager    = $pollManager;
    $this->requestStack   = $requestStack;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('poll.manager'),
      $container->get('request_stack')
    );
  }
  
  /**
   * Overview
   *
   * @return array
   */
  public function overview() {

    $rows = [];

    $header = [
      [
        'data' => $this->t('ID'),
        'class' => [RESPONSIVE_PRIORITY_MEDIUM],
      ],
      [
        'data' => $this->t('Name'),
        'class' => [RESPONSIVE_PRIORITY_MEDIUM],
      ],
      [
        'data' => $this->t('Operations'),
        'class' => [RESPONSIVE_PRIORITY_MEDIUM],
      ]
    ];

    foreach ($this->pollManager->getQuestions() as $pollQuestion) {
      $rows[] = [
        'data' => [
          $pollQuestion->id,
            $this->t($pollQuestion->name),
            $this->l($this->t('View result'), new Url('poll.result.view', ['question_id' => $pollQuestion->id])),
        ]
      ];
    }

    $build['poll_question_table'] = [
      '#type'   => 'table',
      '#header' => $header,
      '#rows'   => $rows,
      '#empty'  => $this->t('No result available.'),
    ];

    return $build;
  }

  /**
   * Save
   *
   * @param int $question_id
   * @param int $answer_id
   */
  public function save(int $question_id, int $answer_id) {
    $currentRequest = $this->requestStack->getCurrentRequest();
    $clientIp       = $currentRequest->getClientIp();

    $errors   = $this->validate($question_id, $answer_id, $clientIp);

    if (!empty($errors)) {
      foreach ($errors as $error) {
        \Drupal::messenger()->addMessage($error, 'error');
      }
    } else {
      $this->pollManager->saveResult($question_id, $answer_id, $clientIp);
      \Drupal::messenger()->addMessage($this->t('Thank you for your vote'), 'success');
    }

    $redirectUrl = ($currentRequest->headers->get('referer'))
    ?: \Drupal\Core\Url::fromRoute('<front>')->toString();

    return new RedirectResponse($redirectUrl);
  }

  /**
   * Validate
   *
   * @param int    $question_id
   * @param int    $answer_id
   * @param string $clientIp

   * @return array
   */
  protected function validate(int $question_id, int $answer_id, $clientIp) {
    $errors = [];

    if (!($this->pollManager->isAvailable($question_id, $answer_id))) {
      $errors[] = $this->t('This poll is not available.');
    }
    
    if ($this->pollManager->hasPolled($question_id, $clientIp)) {
      $errors[] = $this->t('You have already vote for this poll');
    }

    return $errors;
  }
  /**
   * view
   *
   * @param int $question_id
   */
  public function view(int $question_id) {
    $result = $this->pollManager->getPoll($question_id);
    
    return [
      '#theme'  => 'poll_admin_result_template',
      '#poll'   => $result,
    ];
  }
}

En repassant sur la table de BDD poll_result, je remarque qu’il y a pas mal de trucs qui ne vont pas, le champ value ne sert à rien et je n’ai mis aucune contrainte sur les clés étrangères, bref va falloir mettre au propre tout ca.

On remplace value par IP qui est maintenant de type varchar dans le fichier poll.install et on réinstalle le module.

On s’attaque au dashboard des résultats en BO (dashboard qui ne fait que le strict nécessaire hein). On crée un nouveau fichier de template nommé poll-admin-result-template.html.twig dans le dossier template du module et on y met le contenu du fichier poll-result-template.html.twig (en gros, celui du front, je ne me suis pas foulé). Rudimentaire mais fonctionnel.

Ce dossier Custom Poll touche à sa fin, du moins pour ce premier jet, mais on va quand même régler quelques trucs histoire de chipoter.

Mots clés
Créer un module Drupal 8
Drupal 8
Dossier