Drupal 8: Forms

Working with forms in Drupal 8 modules
Drupal Meetup Stuttgart

05/07/2015

 

1. Creating a form

<?php

/**
 * @file
 * Contains \Drupal\config\Form\ConfigExportForm.
 */

namespace Drupal\config\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class ConfigExportForm extends FormBase {

   public function getFormId() {
     return 'config_export_form';
   }

   public function buildForm(array $form, FormStateInterface $form_state) {
     $form['description'] = array(
       ...
     );
     ...
     return $form;
   }

   public function submitForm(array &$form, FormStateInterface $form_state) {
     ...
   }

}

Example: /modules/config/src/Form/ConfigExportForm.php

Forms

  • are classes
  • extending base forms
  • implementing parent methods / properties
  • using the Drupal Form API

Examples for base forms

  • FormBase (generic)
  • ConfigFormBase (settings forms)
  • ConfirmFormBase (confirmation forms)
  • XYZFormBase (roll your own)
<?php

/**
 * @file
 * Contains \Drupal\config\Form\ConfigExportForm.
 */

namespace Drupal\config\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class ConfigExportForm extends FormBase {

  public function getFormId() {
    return 'config_export_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['description'] = array(
      '#markup' => '<p>' . $this->t('Use the export button below to download your site configuration.') . '</p>',
    );
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Export'),
    );
    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_state->setRedirect('config.export_download');
  }

}

Complete class: \Drupal\config\Form\ConfigExportForm

2. Rendering a form


ban.delete:
  path: '/admin/config/people/ban/delete/{ban_id}'
  defaults:
    _form: '\Drupal\ban\Form\BanDelete'
    _title: 'Delete IP address'
  requirements:
    _permission: 'ban IP addresses'

ban.routing.yml

<?php

namespace Drupal\ban\Form;

use Drupal\Core\Form\ConfirmFormBase;
...

class BanDelete extends ConfirmFormBase {

...

}

Rendering a standalone form on a page

BanDelete.php

...

  public function translatePage() {
    return array(
      'filter' => $this->formBuilder()->getForm('Drupal\locale\Form\TranslateFilterForm'),
      'form' => $this->formBuilder()->getForm('Drupal\locale\Form\TranslateEditForm'),
    );
  }

...

\Drupal\locale\Controller\localeContoller

<?php

namespace Drupal\locale\Form;

use Drupal\Core\Form\FormStateInterface;

class TranslateFilterForm extends TranslateFormBase {

  ...

}

Embedding a form in other markup

\Drupal\locale\Form\TranslateFilterForm

3. Validating a form

Validate =

  • Checking form values
  • Create error messages
  • Prepare for form submission
  • ...

public function validateForm(array &$form, FormStateInterface $form_state) {

  $this->file = file_save_upload('file', $form['file']['#upload_validators'], 'translations://', 0);

  // Ensure we have the file uploaded.
  if (!$this->file) {
    $form_state->setErrorByName('file', $this->t('File to import not found.'))
  }

}

Example: \Drupal\locale\Form\ImportForm


public function validateForm(array &$form, FormStateInterface $form_state) {

  $name = trim($form_state->getValue('name'));
  // Try to load by email.
  $users = $this->userStorage->loadByProperties(array('mail' => $name, 'status' => '1'));
  if (empty($users)) {
    // No success, try to load by name.
    $users = $this->userStorage->loadByProperties(array('name' => $name, 'status' => '1'));
  }
  $account = reset($users);
  if ($account && $account->id()) {
    $form_state->setValueForElement(array('#parents' => array('account')), $account);
  }
  else {
    $form_state->setErrorByName('name', $this->t('Sorry, %name is not recognized as a
                                 username or an email address.', array('%name' => $name)));
  }

}

Example: \Drupal\user\Form\UserPasswordForm

4. Submitting a form

Submit =

  • Storing form values
  • Output messages
  • Write log information
  • Redirect to new URL
  • ...

public function submitForm(array &$form, FormStateInterface $form_state) {

  if ($form_state->getValue('confirm')) {
    $this->commentStorage->delete($this->comments);
    $count = count($form_state->getValue('comments'));
    $this->logger('content')->notice('Deleted @count comments.', array('@count' => $count));
    drupal_set_message($this->formatPlural($count, 'Deleted 1 comment.', 'Deleted @count comments.'));
  }

  $form_state->setRedirectUrl($this->getCancelUrl());

}

Example: \Drupal\comment\Form\ConfirmDeleteMultiple


public function submitForm(array &$form, FormStateInterface $form_state) {

  $allowed_types = array_filter($form_state->getValue('book_allowed_types'));
  // We need to save the allowed types in an array ordered by machine_name so
  // that we can save them in the correct order if node type changes.
  // @see book_node_type_update().
  sort($allowed_types);
  $this->config('book.settings')
  // Remove unchecked types.
    ->set('allowed_types', $allowed_types)
    ->set('child_type', $form_state->getValue('book_child_type'))
    ->save();

  parent::submitForm($form, $form_state);

}

Example: \Drupal\book\Form\BookSettingsForm

5. Reusing existing forms

Reuse =

  • Create a new form based on an existing form
<?php

/**
 * @file
 * Contains \Drupal\block\Form\BlockDeleteForm.
 */

namespace Drupal\block\Form;

use Drupal\Core\Entity\EntityDeleteForm;
use Drupal\Core\Url;

/**
 * Provides a deletion confirmation form for the block instance deletion form.
 */
class BlockDeleteForm extends EntityDeleteForm {

  /**
   * {@inheritdoc}
   */
  public function getCancelUrl() {
    return new Url('block.admin_display');
  }

}

Example: \Drupal\block\Form\BlockDeleteForm

6. Modifying forms

Some old friends:

  • hook_form_alter()
  • hook_form_FORM_ID_alter()
  • hook_form_BASE_FORM_ID_alter()
...
use Drupal\Core\Form\FormStateInterface;
...

function mymodule_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Add a checkbox to the node form about agreeing to terms of use.
  $form['terms_of_use'] = array(
    '#type' => 'checkbox',
    '#title' => t("I agree with the website's terms and conditions."),
    '#required' => TRUE,
  );

}

Example: mymodule.module

Thank You!

 

http://slides.com/drubb

http://slideshare.net/drubb

Drupal 8: Forms

By Boris Böhne

Drupal 8: Forms

Working with forms in Drupal 8 modules, a presentation at Drupal Meetup Stuttgart, 05/07/2015

  • 1,422