Drupal 8 Module Port - Forms

This is Part 3 of a blog series about my recent experiences of porting the Instagram Block module from Drupal 7 to Drupal 8. Since Drupal 8 is still in alpha, APIs are subject to change. Also I may not be using best practises so commenting is heavily appreciated!

Now we are going to have a look at getting a form on a page. You may have noticed this line in the last post when we created a configuration page:

  pattern: '/admin/config/content/instagram_block'
  defaults:
    _form: 'Drupal\instagram_block\Form\InstagramBlockForm'

Rather than telling Drupal to create a page and then render a form on that page, we are telling the routing system straight away that at that url we will be putting a form.

Now lets have a look at OOP. Because Drupal 8 doesn't require all classes to have unique names, we need to make sure any classes we define are not only located in the correct folders, but also have the correct 'namespaces'.

For example, the correct place to put a class that creates a form in Drupal 8 is

'MODULEFOLDER/lib/Drupal/MODULENAME/Form/CLASSNAME.php'.

In our case, as above the correct place is

'instagram_block/lib/Drupal/instagram_block/Form/InstagramBlockForm.php'

This may look very strange, but this will make perfect sense later.

Show me code!

Now lets have a look at the code and then go through it piece by piece:

Important Notes

Class definition

Now the top of the file is used mainly for telling Drupal about this class and making sure it can find it if needed. Drupal finds this class by combining the class name, InstagramBlockForm, and the namespace, Drupal\instagram_block\Form, which as it turns out is also the directory we are in. It isn't so much of a problem with this particular class, because it is unlikely that another class has the same name, but if there were another implementation of the same class name elsewhere, then in the top of the class implementing our form object there would be a line:

use Drupal\instagram_block\Form\InstagramBlockForm;

This translates as 'Whenever the following class uses the InstagramBlockForm class, look for that class in the Drupal\instagram_block\Form directory'.

In our form we also have a 'use' statement, 'use Drupal\Core\Form\ConfigFormBase'. This means that in our class definition 'class InstagramBlockForm extends ConfigFormBase', we are referring to the Drupal\Core\Form\ConfigFormBase class.

Form build and submit

Now the rest is quite straight forward. We set a unique form_id using getFormID(), we build out renderable form array in buildFrom() and we submit our form in submitForm(). We could also have implemented validateForm(), but we aren't going to do that for this form.

The interesting stuff happens with the lines:

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

and

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

Because we have chosen to extend ConfigFormBase and not FormBase (which we would have done for a generic form), we can call the parent implementations of those two methods to some nice things like create a submit button for us, or set a confirmation message when the form is saved.

Thanks ConfigFormBase!

We will have a closer look at what is happening in the buildForm() and submitForm() methods after we have looked at blocks.