1

How can I change form builder call in class in to dependency injection method?

My current code:

class CustomBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    $form = \Drupal::formBuilder()->getForm('Drupal\custom_module\Form\CustomForm');
    return $form;
  }

}

And I tried:

class CustomBlock extends BlockBase {

  /**
   * formBuilder.   *
   */
  protected $formBuilder;

  /**
   * Class constructor.
   */
  public function __construct($formBuilder) {
    $this->formBuilder = $formBuilder;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
        $container->get('form_builder')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    $form = $this->formBuilder->getForm('Drupal\custom_module\Form\CustomForm');
    return $form;
  }

}

But getting following error:

Fatal error: Call to a member function getForm() on a non-object in H:\wamp\www\myproject\modules\custom\custom_module\src\Plugin\Block\CustomBlock.php on line 44

1

You have to implement the \Drupal\Core\Plugin\ContainerFactoryPluginInterface. The \Drupal\Core\Block\BlockBase doesn't implement it by default.

Also, your IDE is probably not that good since it would show you the create() method is not implemented.

  • 1
    The constructor is also missing the type hint. – Kevin Jul 30 '17 at 12:42
0

AJAX form test mock module's AjaxFormBlock.php is quite a nice example for getting both in one, the form builder and the form interface! Look how it implements FormInterface, ContainerFactoryPluginInterface to then provide the form from within the block and injecting the form builder via dependency injection to then be used to get the form in the block's build() method at the same time.

Of course, when you only need the form builder, you don't need to implement the FormInterface! Then you just need the ContainerFactoryPluginInterface.

namespace Drupal\ajax_forms_test\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides an AJAX form block.
 *
 * @Block(
 *   id = "ajax_forms_test_block",
 *   admin_label = @Translation("AJAX test form"),
 *   category = @Translation("Forms")
 * )
 */
class AjaxFormBlock extends BlockBase implements FormInterface, ContainerFactoryPluginInterface {

  /**
   * The form builder.
   *
   * @var \Drupal\Core\Form\FormBuilderInterface
   */
  protected $formBuilder;

  /**
   * The messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * Constructs a new AjaxFormBlock.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin ID for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
   *   The form builder.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, FormBuilderInterface $form_builder, MessengerInterface $messenger) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->formBuilder = $form_builder;
    $this->messenger = $messenger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('form_builder'),
      $container->get('messenger')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    return $this->formBuilder->getForm($this);
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'ajax_forms_test_block';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['test1'] = [
      '#type' => 'select',
      '#title' => $this->t('Test 1'),
      '#required' => TRUE,
      '#options' => [
        'option1' => $this->t('Option 1'),
        'option2' => $this->t('Option 2'),
      ],
      '#ajax' => [
        'callback' => '::updateOptions',
        'wrapper' => 'edit-test1-wrapper',
      ],
      '#prefix' => '<div id="edit-test1-wrapper">',
      '#suffix' => '</div>',
    ];
    $form['actions'] = [
      '#type' => 'actions',
    ];
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];
    return $form;
  }

  /**
   * Updates the options of a select list.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return array
   *   The updated form element.
   */
  public function updateOptions(array $form, FormStateInterface $form_state) {
    $form['test1']['#options']['option1'] = $this->t('Option 1!!!');
    $form['test1']['#options'] += [
      'option3' => $this->t('Option 3'),
      'option4' => $this->t('Option 4'),
    ];
    return $form['test1'];
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->messenger->addStatus('Submission successful.');
  }

}

Also worth checking out the docs on Dependency injection in Plugin (Block).

-2

Simple Answer with updated code you just forgot to Import namespace at top and you have not defined the FormBuilderInterface type of object @ constructor

 use Drupal\Core\Form\FormBuilderInterface;
 class CustomBlock extends BlockBase {

  /**
   * The form builder.
   *
   * @var \Drupal\Core\Form\FormBuilderInterface
   */
   protected $formBuilder;

  /**
   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder The Form Builder.
   */

  public function __construct(FormBuilderInterface $formBuilder) {
    $this->formBuilder = $formBuilder;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
        $container->get('form_builder')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    $form = $this->formBuilder->getForm('Drupal\custom_module\Form\CustomForm');
    return $form;
  }

}
  • 1
    To use a namespace unfortunately is no dependency injection. – leymannx Sep 24 at 12:03
  • The usestatement declares which interfaces/classes/traits are used, but that doesn't inject dependencies. – kiamlaluno Oct 11 at 7:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.