L’idée est de pouvoir éditer une question et d’y associer via multi select des réponses à notre Poll
On commence par modifier ses Yml de configuration
-
poll.routing.yml
-
poll.links.action.yml
-
poll.links.menu.yml
poll.routing.yml
poll.question.overview:
path: '/admin/poll/list'
defaults:
_controller: '\Drupal\poll\Controller\QuestionController::overview'
_title: 'Polls'
requirements:
_permission: 'administer poll'
poll.question.edit:
path: '/admin/poll_question/edit/{id}'
defaults:
_form: '\Drupal\poll\Form\Question\EditForm'
_title: 'Poll Question edit'
id: null
requirements:
_permission: 'administer poll'
poll.question.delete:
path: '/admin/poll_question/delete/{id}'
defaults:
_form: '\Drupal\poll\Form\Question\DeleteForm'
_title: 'Poll Question delete'
requirements:
_permission: 'administer poll'
poll.links.action.yml
poll.question.edit:
route_name: poll.question.edit
title: 'Add question'
appears_on:
- poll.question.overview
poll.links.menu.yml
poll.question:
title: 'Poll'
description: 'Administer Polls'
route_name: poll.question.overview
parent: system.admin_reports
weight: -1
On crée le controller QuestionController.php dans le répertoire src/Controller puis les formulaires EditForm.php et DeleteForm.php dans le répertoire src/Form/Question
src/Controller/QuestionController.php
<?php
namespace Drupal\poll\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Question controller.
*/
class QuestionController extends ControllerBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database')
);
}
/**
* Construct
*
* @param \Drupal\Core\Database\Connection $databaseConnection
* A database connection.
*/
public function __construct(Connection $connection) {
$this->connection = $connection;
}
/**
* overview
*
* @return array
*/
public function overview() {
$rows = [];
$header = [
[
'data' => $this->t('ID'),
'field' => 'pq.id',
'class' => [RESPONSIVE_PRIORITY_MEDIUM],
],
[
'data' => $this->t('Name'),
'field' => 'pq.name',
'class' => [RESPONSIVE_PRIORITY_MEDIUM],
],
[
'data' => $this->t('Operations'),
'class' => [RESPONSIVE_PRIORITY_LOW],
],
];
$query = $this->connection->select('poll_question', 'pq')
->extend('\Drupal\Core\Database\Query\PagerSelectExtender')
->extend('\Drupal\Core\Database\Query\TableSortExtender');
$query->fields('pq', [
'id',
'name'
]);
$pollQuestions = $query
->limit(50)
->orderByHeader($header)
->execute();
foreach ($pollQuestions as $pollQuestion) {
$rows[] = [
'data' => [
$pollQuestion->id,
$this->t($pollQuestion->name),
$this->l($this->t('Edit'), new Url('poll.question.edit', ['id' => $pollQuestion->id])),
$this->l($this->t('Delete'), new Url('poll.question.delete', ['id' => $pollQuestion->id]))
]
];
}
$build['poll_question_table'] = [
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
'#empty' => $this->t('No question available.'),
];
$build['poll_question_pager'] = ['#type' => 'pager'];
return $build;
}
}
src/Form/Question/EditForm.php
<?php
namespace Drupal\Poll\Form\Question;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Url;
/**
* Configure question edit form
*/
class EditForm extends FormBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* Question id
*
* @var int
*/
protected $questionId = null;
/**
* Construct
*
* @param \Drupal\Core\Database\Connection $connection The database connection
*/
public function __construct(Connection $connection) {
$this->connection = $connection;
}
/**
* create
*
* @param ContainerInterface $container
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'poll_admin_question';
}
/**
* @param array $form
* @param FormStateInterface $form_state
*
* @return void
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
if (strlen($form_state->getValue('poll_question')) == 0) {
$form_state->setErrorByName('poll_question', $this->t('You must specify a question (alphanumeric).'));
}
}
/**
* @param array $form
* @param FormStateInterface $form_state
* @param int|null $answerId
*
* @return array
*/
public function buildForm(array $form, FormStateInterface $form_state, $id = null) {
$this->questionId = $id;
$editedQuestion = $this->getQuestion();
$selectedAnswers = $this->getSelectedAnswers();
if ($id > 0 && !$editedQuestion) {
throw new \Exception($this->t('Poll Question - The question provided does not exist'));
}
$form['poll_question'] = [
'#type' => 'textfield',
'#title' => $this->t('Question'),
'#default_value' => $editedQuestion,
'#required' => true
];
$form['poll_answers'] = [
'#type' => 'select',
'#multiple' => true,
'#title' => $this->t('Select answers'),
'#options' => $this->getAnswers(),
'#default_value' => $selectedAnswers,
'#required' => true
];
$form['submit'] = [
'#type' => 'submit',
'#title' => $this->t('Save'),
'#default_value' => "Save",
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$question = $form_state->getValue('poll_question');
$answers = $form_state->getValue('poll_answers');
$id = $this->questionId;
if ($id > 0) {
$this->connection->update('poll_question')
->fields(['name' => $question])
->condition('id', $id, "=")
->execute();
$this->connection->delete('poll_question_answer')
->condition('question_id', $id, '=')
->execute();
} else {
$id = $this->connection->insert('poll_question')
->fields(['name' => $question])
->execute();
}
$query = $this->connection->insert('poll_question_answer')->fields(['question_id', 'answer_id']);
foreach ($answers as $answerId) {
$query->values([
'question_id' => $id,
'answer_id' => $answerId
]);
}
$query->execute();
$response = Url::fromRoute('poll.question.overview');
$form_state->setRedirectUrl($response);
}
/**
* @param int|null $id
*
* @return mixed
*/
private function getQuestion() {
if (is_null($this->questionId))
return null;
return $this->connection->select('poll_question')
->fields('poll_question', ['name'])
->condition('id', $this->questionId, "=")
->execute()
->fetchAll()[0]
->name;
}
/**
* Get answers
*
* @return array
*/
private function getAnswers() {
$d = [];
$answers = $this->connection->select('poll_answer')
->fields('poll_answer')
->execute()
->fetchAll();
foreach ($answers as $answer) {
$d[$answer->id] = $answer->name;
}
return $d;
}
/**
* Get selected answers
*
* @return array
*/
private function getSelectedAnswers() {
if (is_null($this->questionId))
return null;
$d = [];
$relations = $this->connection->select('poll_question_answer')
->fields('poll_question_answer', ['answer_id'])
->condition('question_id', $this->questionId, "=")
->execute()
->fetchAll();
foreach ($relations as $relation) {
$d[] = $relation->answer_id;
}
return $d;
}
}
En passant, concernant :
$form['poll_answers'] = [
'#type' => 'select',
'#multiple' => true,
'#title' => $this->t('Select answers'),
'#options' => $this->getAnswers(),
'#default_value' => $selectedAnswers,
'#required' => true
];
Il n’y a pas de type multiselect d’ou l’entrée #multiple = true, #options attend un tableau key => value et #default_value, un tableau de keys.
src/Form/Question/DeleteForm.php
<?php
namespace Drupal\Poll\Form\Question;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Url;
use Drupal\Core\Database\Connection;
class DeleteForm extends ConfirmFormBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* Question to delete
*
* @var int
*/
protected $questionId = null;
/**
* Construct
*
* @param \Drupal\Core\Database\Connection $connection The database connection
*/
public function __construct(Connection $connection) {
$this->connection = $connection;
}
/**
* create
*
* @param ContainerInterface $container
*/
public static function create(ContainerInterface $container) {
return new static($container->get('database'));
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'poll_admin_question';
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Do you really want to remove this question ?');
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('poll.question.overview');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $id = null) {
$this->questionId = $id;
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->connection->delete('poll_question')->condition('id', $this->questionId)->execute();
$this->connection->delete('poll_question_answer')->condition('question_id', $this->questionId, "=")->execute();
$this->messenger()->addMessage($this->t('The question has been deleted'));
$response = Url::fromRoute('poll.question.overview');
$form_state->setRedirectUrl($response);
}
}
On a nos questions et nos réponses administrables en BO, avant de s’attaquer au dashboard admin pour voir les résultats des sondages, on va s’occuper un peu du front en créant un bloc Poll pour pouvoir le positionner où on veut sur la page. C'est parti !