Custom Module in Drupal 9
Tags: php, drupal, drupal9
Published: 2022-01-03 06:21:27

We will be creating a custom module in Drupal 9 to build a custom form & store the data in a custom content type.

**Step 1: Name of the Module**
We need to create a custom module under 'modules/custom' folder. We will name the folder as 'candidates'

![Custom module folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zrq65u7w5i0km55r102a.jpg)

**Step 2: Creating the info.yml file**
We have to create a yaml file with the machine name of our module for Drupal to be able recognize the module. We will name the file as 'candidates.info.yml'

```
name: Candidates Data
type: module
description: A custom module to enter candidate details
package: Custom
version: 1.0
core_version_requirement: ^8 || ^9
```

**Step 3: Creating the routing.yml file**
Next step is to add a candidates.routing.yml file under the 'candidates' directory.
Under path, we specify the URL path for adding Candidate data.
Under defaults, the _controller which references a method on the CandidatesController class and the _title specifies the default page title.
Under requirements, we specify the permission to view the page.

```
candidates.form:
 path: '/add-candidate'
 defaults:
  _title: 'Add Candidates'
  _form: '\Drupal\candidates\Form\CandidatesForm'
 requirements:
  _permission: 'access content'
```

**Step 4: Adding the controller**
We will create a controller file named 'CandidatesController.php' under 'modules/custom/candidates/src/Controller'. In this file, we will create a custom form to validate & submit candidate data. We will store the data into a custom content type named 'candidate'.

```
<?php

/**
 * @file
 * Contains \Drupal\candidates\Form\CandidatesForm.
*/

namespace Drupal\candidates\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\Entity\Node;

class CandidatesForm extends FormBase {
	/**
	* {@inheritdoc}
	*/
	public function getFormId() {
		return 'candidates_form';
	}

	/**
	* {@inheritdoc}
	*/
	public function buildForm(array $form, FormStateInterface $form_state) {
		$form['candidate_name'] = array(
			'#type' => 'textfield',
			'#title' => t('Candidate Name'),
			'#required' => TRUE,
		);
		$form['candidate_dob'] = array(
			'#type' => 'date',
			'#title' => t('Birth Date'),
			'#required' => TRUE,
		);
		$form['candidate_gender'] = array(
			'#type' => 'select',
			'#title' => ('Gender'),
			'#required' => TRUE,
			'#options' => array(
				'male' => t('Male'),
				'female' => t('Female'),
				'other' => t('Other'),
			),
		);
		$form['candidate_mobile'] = array(
			'#type' => 'textfield',
			'#title' => t('Mobile'),
			'#required' => TRUE,
			'#maxlength' => 10,
		);
		$form['candidate_email'] = array(
			'#type' => 'email',
			'#title' => t('Email-ID'),
			'#required' => TRUE,
		);
		$form['candidate_city'] = array(
			'#type' => 'textfield',
			'#title' => t('City'),
			'#required' => TRUE,
		);
		$form['candidate_country'] = array(
			'#type' => 'textfield',
			'#title' => t('Country'),
			'#required' => TRUE,
		);
		$form['candidate_description'] = array(
			'#type' => 'textarea',
			'#title' => t('Description'),
			'#required' => TRUE,
		);
		$form['actions']['#type'] = 'actions';
		$form['actions']['submit'] = array(
			'#type' => 'submit',
			'#value' => $this->t('Save Candidate Data'),
			'#button_type' => 'primary',
		);
		return $form;
	}

	/**
	* {@inheritdoc}
	*/
	public function validateForm(array &$form, FormStateInterface $form_state) {
		if ($form_state->getValue('candidate_name') == '') {
			$form_state->setErrorByName('candidate_name', $this->t('Please Enter Name'));
		}
		if ($form_state->getValue('candidate_dob') == '') {
			$form_state->setErrorByName('candidate_dob', $this->t('Please Enter Birth Date'));
		}
		if ($form_state->getValue('candidate_gender') == '') {
			$form_state->setErrorByName('candidate_gender', $this->t('Please Select Gender'));
		}
		if ($form_state->getValue('candidate_mobile') == '') {
			$form_state->setErrorByName('candidate_mobile', $this->t('Please Enter Mobile'));
		}
		if ($form_state->getValue('candidate_email') == '') {
			$form_state->setErrorByName('candidate_email', $this->t('Please Enter Email-ID'));
		}
		if ($form_state->getValue('candidate_city') == '') {
			$form_state->setErrorByName('candidate_city', $this->t('Please Enter City'));
		}
		if ($form_state->getValue('candidate_country') == '') {
			$form_state->setErrorByName('candidate_country', $this->t('Please Enter Country'));
		}
		if ($form_state->getValue('candidate_description') == '') {
			$form_state->setErrorByName('candidate_description', $this->t('Please Enter Description'));
		}
	}

	/**
	* {@inheritdoc}
	*/
	public function submitForm(array &$form, FormStateInterface $form_state) {
		$node = Node::create(['type' => 'candidate']);
		$node->langcode = "en";
		$node->uid = 1;
		$node->promote = 0;
		$node->sticky = 0;
		$node->title= $form_state->getValue('candidate_name');
		$node->field_birth_date = $form_state->getValue('candidate_dob');
		$node->field_gender = $form_state->getValue('candidate_gender');
		$node->field_mobile = $form_state->getValue('candidate_mobile');
		$node->field_email_id = $form_state->getValue('candidate_email');
		$node->field_city = $form_state->getValue('candidate_city');
		$node->field_country = $form_state->getValue('candidate_country');
		$node->field_description = $form_state->getValue('candidate_description');
		$node->save();

		\Drupal::messenger()->addMessage(t("Candidate Data Save Successful"));
	}
}
```

**Step 5: Creating custom content type**
Create a custom content type named 'candidate' to store the data

![Custom content type fields](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j5di3qfjvr5iqglwy1wm.jpg)