Defining a block

Last updated on
13 September 2023

Remember at the beginning of this tutorial when I said we'd define a block with a form? Well, now's the time to get right on it.

/src/Form/LoremIpsumBlockForm.php

<?php

/**
 * @file
 * Contains \Drupal\loremipsum\Form\BlockFormController
 */

namespace Drupal\loremipsum\Form;

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

/**
 * Lorem Ipsum block form
 */
class LoremIpsumBlockForm extends FormBase {
  /** 
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'loremipsum_block_form';
  }

This file is pretty similar to the settings one, except that it extends the FormBase class.

It also has a buildForm() method like so:

  /**
   * {@inheritdoc}
   * Lorem ipsum generator block.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // How many paragraphs?
    for ($i = 1; $i <= 10; $i++) $options[$i] = $i;
    $form['paragraphs'] = array(
      '#type' => 'select',
      '#title' => t('Paragraphs'),
      '#options' => $options,
      '#default_value' => 4,
      '#description' => t('How many?'),
    );

    // How many phrases?
    $form['phrases'] = array(
      '#type' => 'textfield',
      '#title' => t('Phrases'),
      '#default_value' => '20',
      '#description' => t('Maximum per paragraph'),
    );

    // Submit
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Generate'),
    );

    return $form;
  }

This method is used to put a form inside a block, through which users customize how much dummy text they want to generate.

Don't forget the validateForm() method:

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $phrases = $form_state->getValue('phrases');
    // The value cannot be empty.
    if (is_null($phrases)) $form_state->setErrorByName('phrases', t('This field cannot be empty.'));
    // The value must be numeric.
    if (!is_numeric($phrases)) {
      $form_state->setErrorByName('phrases', t('Please use a number.'));
    }
    else {
      // A numeric value must still be an integer.
      if (floor($phrases) != $phrases) $form_state->setErrorByName('phrases', t('No decimals, please.'));
      // A numeric value cannot be zero or negative.
      if ($phrases < 1) $form_state->setErrorByName('phrases', t('Please use a number greater than zero.'));
    }
  }

The validation checks whether a valid number of phrases was entered, if it's not negative etc.

And the submitForm() method:

  /**
   * {@inheritdoc}
   * 
   * Redirects users to the results page with the Lorem ipsum text created
   * using the provided parameters.
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_state->setRedirect(
      'loremipsum.generate',
      array(
        'paragraphs' => $form_state->getValue('paragraphs'),
        'phrases' => $form_state->getValue('phrases'),
      )
    );
  }

The Submit method takes users to a page, defined in the routing YML file, with the selected number of paragraphs and phrases as parameters.

And now for the block itself.

/src/Plugin/Block/LoremIpsumBlock.php

<?php

namespace Drupal\loremipsum\Plugin\Block;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;

 /**
 * Provides a Lorem ipsum block with which you can generate dummy text anywhere
 *
 * @Block(
 *   id = "loremipsum_block",
 *   admin_label = @Translation("Lorem ipsum block"),
 *   category = @Translation("Forms")
 * )
 */
class LoremIpsumBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    // Return the form @ Form/LoremIpsumBlockForm.php
    return \Drupal::formBuilder()->getForm('Drupal\loremipsum\Form\LoremIpsumBlockForm');
  }

  /**
   * {@inheritdoc}
   */
  protected function blockAccess(AccountInterface $account) {
    return AccessResult::allowedIfHasPermission($account, 'generate lorem ipsum');
  }

The LoremIpsumBlock class extends BlockBase and, as such, has four methods that must be implemented: build(), blockAccess(), blockForm(), and blockSubmit(). Comments at the top have annotations which will make our Block definition discoverable by Drupal. The first one merely renders the form defined in our previous step. The remaining ones control who has access to view the Block, and its settings.

Next we deal with access control:

  /**
   * {@inheritdoc}
   */
  protected function blockAccess(AccountInterface $account) {
    return AccessResult::allowedIfHasPermission($account, 'generate lorem ipsum');
  }

Define our block form for the Block administration screen:

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    $form = parent::blockForm($form, $form_state);
    $config = $this->getConfiguration();
    return $form;
  }

A submit handler:

  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->setConfigurationValue(
      'loremipsum_block_settings',
      $form_state->getValue('loremipsum_block_settings')
    );
  } 

And we're done.

Help improve this page

Page status: No known problems

You can: