Skip to content

Instantly share code, notes, and snippets.

@lcube45
Forked from WengerK/ContactForm-basic.php
Created May 11, 2022 16:03
Show Gist options
  • Save lcube45/8592a7b8a35f86983206492ed18c52b1 to your computer and use it in GitHub Desktop.
Save lcube45/8592a7b8a35f86983206492ed18c52b1 to your computer and use it in GitHub Desktop.
Drupal 8 — Inline validation in forms

Article Ressources - Drupal 8 — Inline validation in forms

This is the Gist repository for my article Drupal 8 — Inline validation in forms.

Be aware that this article has been wrote for the Blog of Antistatique — Web Agency in Lausanne, Switzerland. A place where I work as Full Stack Web Developer.

Feel free to read it the full article on Medium or check it out on Antistatique.

Content of this Gist :

  • ContactForm-basic.php : Basic form whitout validation
  • ContactForm-validations.php : Complete form using standard Drupal 8 validations
  • ContactForm-validations-inline.php : Complete form using inline validations
  • InlineErrorFormTrait.php : Apply all errors as inline field error
<?php
/**
* @file
* Contains \Drupal\my_contact\Form\ContactForm.
*/
namespace Drupal\my_contact\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
// Traits
use Drupal\Core\StringTranslation\StringTranslationTrait;
class ContactForm extends FormBase {
use StringTranslationTrait;
/**
* {@inheritdoc}.
*/
public function getFormId() {
return 'my_contact_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
// This will generate an anchor scroll to the form when submitting
$form['#action'] = '#my-contact-form';
$form['personnal'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Your personnal data'),
);
$form['personnal']['firstname'] = array(
'#title' => $this->t('Your firstname *'),
'#placeholder' => $this->t('Alain'),
'#type' => 'textfield',
'#attributes' => ['size' => 25],
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['personnal']['lastname'] = array(
'#title' => $this->t('Your lastname *'),
'#placeholder' => $this->t('Rochat'),
'#type' => 'textfield',
'#attributes' => ['size' => 24],
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['personnal']['email'] = array(
'#title' => $this->t('Your email *'),
'#placeholder' => $this->t('alain.rochat@domain.ltd'),
'#type' => 'textfield',
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['message'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Your message'),
);
$form['message']['subject'] = array(
'#title' => $this->t('Subject *'),
'#type' => 'textfield',
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['message']['message'] = array(
'#title' => $this->t('Message *'),
'#type' => 'textarea',
'#required' => false,
'#attributes' => ['cols' => 59],
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Send'),
'#attributes' => ['class' => array('btn-lg btn-primary pull-right')],
'#button_type' => 'primary',
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$data = array(
'firstname' => $form_state->getValue('firstname'),
'lastname' => $form_state->getValue('lastname'),
'email' => $form_state->getValue('email'),
'subject' => $form_state->getValue('subject'),
'message' => $form_state->getValue('message'),
);
drupal_set_message($this->t('Thank you very much @firstname @lastname for your message. You will receive a confirmation email shortly.', [
'@firstname' => $form_state->getValue('firstname'),
'@lastname' => $form_state->getValue('lastname'),
]));
}
}
<?php
/**
* @file
* Contains \Drupal\my_contact\Form\ContactForm.
*/
namespace Drupal\my_contact\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
// Traits
use Drupal\Core\StringTranslation\StringTranslationTrait;
class ContactForm extends FormBase {
use StringTranslationTrait;
/**
* {@inheritdoc}.
*/
public function getFormId() {
return 'my_contact_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
// This will generate an anchor scroll to the form when submitting
$form['#action'] = '#my-contact-form';
$form['personnal'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Your personnal data'),
);
$form['personnal']['firstname'] = array(
'#title' => $this->t('Your firstname *'),
'#placeholder' => $this->t('Alain'),
'#type' => 'textfield',
'#attributes' => ['size' => 25],
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['personnal']['lastname'] = array(
'#title' => $this->t('Your lastname *'),
'#placeholder' => $this->t('Rochat'),
'#type' => 'textfield',
'#attributes' => ['size' => 24],
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['personnal']['email'] = array(
'#title' => $this->t('Your email *'),
'#placeholder' => $this->t('alain.rochat@domain.ltd'),
'#type' => 'textfield',
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['message'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Your message'),
);
$form['message']['subject'] = array(
'#title' => $this->t('Subject *'),
'#type' => 'textfield',
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['message']['message'] = array(
'#title' => $this->t('Message *'),
'#type' => 'textarea',
'#required' => false,
'#attributes' => ['cols' => 59],
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Send'),
'#attributes' => ['class' => array('btn-lg btn-primary pull-right')],
'#button_type' => 'primary',
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Assert the firstname is valid
if (!$form_state->getValue('firstname') || empty($form_state->getValue('firstname'))) {
$form_state->setErrorByName('firstname', $this->t('Votre prénom est obligatoire.'));
}
// Assert the lastname is valid
if (!$form_state->getValue('lastname') || empty($form_state->getValue('lastname'))) {
$form_state->setErrorByName('lastname', $this->t('Votre nom est obligatoire.'));
}
// Assert the email is valid
if (!$form_state->getValue('email') || !filter_var($form_state->getValue('email'), FILTER_VALIDATE_EMAIL)) {
$form_state->setErrorByName('email', $this->t('Votre adresse e-mail semble invalide.'));
}
// Assert the subject is valid
if (!$form_state->getValue('subject') || empty($form_state->getValue('subject'))) {
$form_state->setErrorByName('subject', $this->t('Le sujet de votre demande est important.'));
}
// Assert the message is valid
if (!$form_state->getValue('message') || empty($form_state->getValue('message'))) {
$form_state->setErrorByName('message', $this->t('Le message de votre demande est important.'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$data = array(
'firstname' => $form_state->getValue('firstname'),
'lastname' => $form_state->getValue('lastname'),
'email' => $form_state->getValue('email'),
'subject' => $form_state->getValue('subject'),
'message' => $form_state->getValue('message'),
);
drupal_set_message($this->t('Thank you very much @firstname @lastname for your message. You will receive a confirmation email shortly.', [
'@firstname' => $form_state->getValue('firstname'),
'@lastname' => $form_state->getValue('lastname'),
]));
}
}
<?php
/**
* @file
* Contains \Drupal\my_contact\Form\ContactForm.
*/
namespace Drupal\my_contact\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
// Traits
use Drupal\Core\StringTranslation\StringTranslationTrait;
class ContactForm extends FormBase {
use StringTranslationTrait;
/**
* {@inheritdoc}.
*/
public function getFormId() {
return 'my_contact_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
// This will generate an anchor scroll to the form when submitting
$form['#action'] = '#my-contact-form';
// Disable caching & HTML5 validation
$form['#cache']['max-age'] = 0;
$form['#attributes']['novalidate'] = 'novalidate';
$form['personnal'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Your personnal data'),
);
$form['personnal']['firstname'] = array(
'#title' => $this->t('Your firstname *'),
'#placeholder' => $this->t('Alain'),
'#type' => 'textfield',
'#attributes' => ['size' => 25],
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['personnal']['lastname'] = array(
'#title' => $this->t('Your lastname *'),
'#placeholder' => $this->t('Rochat'),
'#type' => 'textfield',
'#attributes' => ['size' => 24],
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['personnal']['email'] = array(
'#title' => $this->t('Your email *'),
'#placeholder' => $this->t('alain.rochat@domain.ltd'),
'#type' => 'textfield',
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['message'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Your message'),
);
$form['message']['subject'] = array(
'#title' => $this->t('Subject *'),
'#type' => 'textfield',
'#required' => false,
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['message']['message'] = array(
'#title' => $this->t('Message *'),
'#type' => 'textarea',
'#required' => false,
'#attributes' => ['cols' => 59],
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Send'),
'#attributes' => ['class' => array('btn-lg btn-primary pull-right')],
'#button_type' => 'primary',
'#prefix' => '<div class="form-group">',
'#suffix' => '</div>',
);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Assert the firstname is valid
if (!$form_state->getValue('firstname') || empty($form_state->getValue('firstname'))) {
$form_state->setErrorByName('[personnal][firstname]', $this->t('Votre prénom est obligatoire.'));
}
// Assert the lastname is valid
if (!$form_state->getValue('lastname') || empty($form_state->getValue('lastname'))) {
$form_state->setErrorByName('[personnal][lastname]', $this->t('Votre nom est obligatoire.'));
}
// Assert the email is valid
if (!$form_state->getValue('email') || !filter_var($form_state->getValue('email'), FILTER_VALIDATE_EMAIL)) {
$form_state->setErrorByName('[personnal][email]', $this->t('Votre adresse e-mail semble invalide.'));
}
// Assert the subject is valid
if (!$form_state->getValue('subject') || empty($form_state->getValue('subject'))) {
$form_state->setErrorByName('[message][subject]', $this->t('Le sujet de votre demande est important.'));
}
// Assert the message is valid
if (!$form_state->getValue('message') || empty($form_state->getValue('message'))) {
$form_state->setErrorByName('[message][message]', $this->t('Le message de votre demande est important.'));
}
// If validation errors, add inline errors
if ($errors = $form_state->getErrors()) {
// Add error to fields using Symfony Accessor
$accessor = PropertyAccess::createPropertyAccessor();
foreach ($errors as $field => $error) {
if ($accessor->getValue($form, $field)) {
$accessor->setValue($form, $field.'[#prefix]', '<div class="form-group error">');
$accessor->setValue($form, $field.'[#suffix]', '<div class="input-error-desc">' .$error. '</div></div>');
}
}
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$data = array(
'firstname' => $form_state->getValue('firstname'),
'lastname' => $form_state->getValue('lastname'),
'email' => $form_state->getValue('email'),
'subject' => $form_state->getValue('subject'),
'message' => $form_state->getValue('message'),
);
drupal_set_message($this->t('Thank you very much @firstname @lastname for your message. You will receive a confirmation email shortly.', [
'@firstname' => $form_state->getValue('firstname'),
'@lastname' => $form_state->getValue('lastname'),
]));
}
}
<?php
/**
* @file - PARTIAL
* Contains \Drupal\my_contact\Form\ContactForm.
*/
...
use Symfony\Component\PropertyAccess\PropertyAccess;
...
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Assert the firstname is valid
if (!$form_state->getValue('firstname') || empty($form_state->getValue('firstname'))) {
$form_state->setErrorByName('[personnal][firstname]', $this->t('Votre prénom est obligatoire.'));
}
// Assert the lastname is valid
if (!$form_state->getValue('lastname') || empty($form_state->getValue('lastname'))) {
$form_state->setErrorByName('[personnal][lastname]', $this->t('Votre nom est obligatoire.'));
}
// Assert the email is valid
if (!$form_state->getValue('email') || !filter_var($form_state->getValue('email'), FILTER_VALIDATE_EMAIL)) {
$form_state->setErrorByName('[personnal][email]', $this->t('Votre adresse e-mail semble invalide.'));
}
// If validation errors, add inline errors
if ($errors = $form_state->getErrors()) {
// Add error to fields using Symfony Accessor
$accessor = PropertyAccess::createPropertyAccessor();
foreach ($errors as $field => $error) {
if ($accessor->getValue($form, $field)) {
$accessor->setValue($form, $field.'[#prefix]', '<div class="form-group error">');
$accessor->setValue($form, $field.'[#suffix]', '<div class="input-error-desc">' .$error. '</div></div>');
}
}
}
}
...
<?php
/**
* @file - PARTIAL
* Contains \Drupal\my_contact\Form\ContactForm.
*/
...
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Assert the firstname is valid
if (!$form_state->getValue('firstname') || empty($form_state->getValue('firstname'))) {
$form_state->setErrorByName('firstname', $this->t('Votre prénom est obligatoire.'));
}
// Assert the lastname is valid
if (!$form_state->getValue('lastname') || empty($form_state->getValue('lastname'))) {
$form_state->setErrorByName('lastname', $this->t('Votre nom est obligatoire.'));
}
// Assert the email is valid
if (!$form_state->getValue('email') || !filter_var($form_state->getValue('email'), FILTER_VALIDATE_EMAIL)) {
$form_state->setErrorByName('email', $this->t('Votre adresse e-mail semble invalide.'));
}
// Assert the subject is valid
if (!$form_state->getValue('subject') || empty($form_state->getValue('subject'))) {
$form_state->setErrorByName('subject', $this->t('Le sujet de votre demande est important.'));
}
// Assert the message is valid
if (!$form_state->getValue('message') || empty($form_state->getValue('message'))) {
$form_state->setErrorByName('message', $this->t('Le message de votre demande est important.'));
}
}
...
<?php
namespace Drupal\my_contact\Form;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Drupal\Core\Form\FormStateInterface;
/**
* Provides helper methods for inlining error form.
*/
trait InlineErrorFormTrait {
/**
* Apply all errors as inline field error.
*
* @param array $form
* The current form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public static function applyErrorsInline(array &$form, FormStateInterface $form_state) {
// If validation errors, add inline errors.
if ($errors = $form_state->getErrors()) {
// Add error to fields using Symfony Accessor.
$accessor = PropertyAccess::createPropertyAccessor();
foreach ($errors as $field_accessor => $error) {
try {
$accessor->getValue($form, $field_accessor);
if ($field = $accessor->getValue($form, $field_accessor)) {
$prefix = str_replace('form-group', 'form-group has-danger error', $field['#prefix']);
$suffix = '<div class="input-error-desc" id="' . $field['#id'] . '-error">' . $error . '</div>' . $field['#suffix'];
$accessor->setValue($form, $field_accessor . '[#prefix]', $prefix);
$accessor->setValue($form, $field_accessor . '[#suffix]', $suffix);
$accessor->setValue($form, $field_accessor . '[#attributes][aria-invalid]', 'true');
$accessor->setValue($form, $field_accessor . '[#attributes][aria-describedby]', $field['#id'] . '-error');
}
}
catch (\Exception $e) {
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment