Skip to main content
Category:

In this article, we'll create custom table in database and create custom form with CRUD Operations. this just is an example how to use database api and form api for create tips programmatically without Views module.

Create a module

In Drupal 8, it is necessary to create an info.yml file that contains the metadata for every custom module. you will need to create the mymodule.info.yml file under the modules/custom/mymodule folder. Inside this file enter following:

name: 'My Module'
description: 'Custom Module'
package: Custom
type: module
core: 8.x

Once the folder and file has been created, you can go to your Drupal dashboard and enable the custom module we have just created.

Create Custom Table in Database

To create a table in the database. I have created mymodule.install file, in this file I added a table called mytable.

hook_schema() helps to create the table and their fields into the database. In our custom form the crud database will be stored in mytable as the table name. If the value is stored in the database, it helps in performing CRUD operations,like edit or delete.

<?php

/**
 * create table mytable
 */
function mymodule_schema() {
  $schema['mytable'] = array(
    'fields' => array(
      'id' => array(
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'first_name' => array(
        'type' => 'varchar',
        'length' => 32,
        'not null' => TRUE,
        'default' => '',
      ),
      'last_name' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'email' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'phone' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'fid' => array(
        'type' => 'int',
        'length' => 20,
        'not null' => FALSE,
      ),
      'select' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'message' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
    ),
    'primary key' => array(
      'id',
    ),
  );

  return $schema;

}

The result in the database is like this:

 

How to use database api by creating custom Form with CRUD operations in Drupal 8

 

Create the routes

To create routes I have created mymodule.routing.yml file, in this file I added all the routes for add/edit data, delete data, show data and get all data.

mymodule.display_data:
  path: '/admin/mymodule/index'
  defaults:
    _controller: '\Drupal\mymodule\Controller\DisplayTableController::index'
    _title: 'All Data'
  requirements:
    _permission: 'access content'

mymodule.show_data:
  path: '/admin/mymodule/{id}/show'
  defaults:
    _controller: '\Drupal\mymodule\Controller\MydataController::show'
    _title: 'Show Data'
  requirements:
    _permission: 'access content'

mymodule.delete_form:
  path: '/admin/mymodule/{id}/delete'
  defaults:
    _form: '\Drupal\mymodule\Form\DeleteForm'
    _title: 'DeleteForm'
  requirements:
    _access: 'TRUE'

mymodule.add_form:
  path: '/admin/mymodule/add'
  defaults:
    _title: 'Add/Edit Data'
    _form: '\Drupal\mymodule\Form\MyModuleForm'
  requirements:
    _permission: 'access content'

 

Save data in database

The complete code for create our form and insert data is shown below. so let's create src/Form/MyModuleForm.php class.

this class contains : 

getFormId(): This needs to return a string that is the unique ID of your form. Namespace the form ID based on your module's name.

buildForm(): This returns a Form API array that defines each of the elements of your form.

submitForm(): collect data and save the data to the database.

validateForm(): used to validate the data that's being collected.

 

<?php

namespace Drupal\mymodule\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Symfony\Component\HttpFoundation\RedirectResponse;


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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state)
  {
    $form['first_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('first name'),
      '#required' => true,
      '#size' => 60,
      '#default_value' => ' ',
      '#maxlength' => 128,
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['last_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('last name'),
      '#required' => true,
      '#size' => 60,
      '#default_value' => ' ',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['email'] = [
      '#type' => 'email',
      '#title' => $this->t('email'),
      '#required' => true,
      '#default_value' => ' ',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['picture'] = array(
      '#title' => t('picture'),
      '#description' => $this->t('Chossir Image gif png jpg jpeg'),
      '#type' => 'managed_file',
      '#required' => true,
      '#upload_location' => 'public://images/',
      '#upload_validators' => array(
        'file_validate_extensions' => array('gif png jpg jpeg')),
    );
    $form['phone'] = [
      '#type' => 'tel',
      '#title' => $this->t('phone'),
      '#required' => true,
      '#default_value' => ' ',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['select'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Select element'),
      '#options' => [
        '1' => $this
          ->t('One'),
        '2' => [
          '2.1' => $this
            ->t('Two point one'),
          '2.2' => $this
            ->t('Two point two'),
        ],
        '3' => $this
          ->t('Three'),
      ],
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['message'] = [
      '#type' => 'textarea',
      '#title' => $this->t('message'),
      '#required' => true,
      '#default_value' => ' ',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('save'),
      '#buttom_type' => 'primary'
    ];
    return $form;
  }

  /**
   * @param array $form
   * @param FormStateInterface $form_state
   */
  public function validateForm(array &$form, FormStateInterface $form_state)
  {
    if (is_numeric($form_state->getValue('first_name'))) {
      $form_state->setErrorByName('first_name', $this->t('Error, The First Name Must Be A String'));
    }
  }


  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state)
  {
    $picture = $form_state->getValue('picture');
    $data = array(
      'first_name' => $form_state->getValue('first_name'),
      'last_name' => $form_state->getValue('last_name'),
      'email' => $form_state->getValue('email'),
      'phone' => $form_state->getValue('phone'),
      'select' => $form_state->getValue('select'),
      'message' => $form_state->getValue('message'),
      'fid' => $picture[0],
    );

    // save file as Permanent
    $file = File::load($picture[0]);
    $file->setPermanent();
    $file->save();

    // insert data to database
     \Drupal::database()->insert('mytable')->fields($data)->execute();

     // show message and redirect to list page
    \Drupal::messenger()->addStatus('Succesfully saved');
    $url = new Url('mymodule.display_data');
    $response = new RedirectResponse($url->toString());
    $response->send();
  }


}

our custom form is like this:

How to use database api by creating custom Form with CRUD operations in Drupal 8

 

display all data from database in a custom table

The complete code for display data is shown below. so let's create src/Controller/DisplayTableController.php class.

this class contains : 

index() method:  In this method, we will display the output in the table format. We have used the standard way of displaying the values of the row in table format.

 

<?php

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Link;
use Drupal\Core\Url;

/**
 * Class DisplayTableController
 * @package Drupal\mymodule\Controller
 */
class DisplayTableController extends ControllerBase
{

  public function index()
  {
    //create table header
    $header_table = array(
      'id' => t('ID'),
      'first_name' => t('first name'),
      'last_name' => t('last name'),
      'email' => t('Email'),
      'phone' => t('phone'),
      'view' => t('View'),
      'delete' => t('Delete'),
      'edit' => t('Edit'),
    );


    // get data from database
    $query = \Drupal::database()->select('mytable', 'm');
    $query->fields('m', ['id', 'first_name', 'last_name', 'email', 'phone']);
    $results = $query->execute()->fetchAll();
    $rows = array();
    foreach ($results as $data) {
      $url_delete = Url::fromRoute('mymodule.delete_form', ['id' => $data->id], []);
      $url_edit = Url::fromRoute('mymodule.add_form', ['id' => $data->id], []);
      $url_view = Url::fromRoute('mymodule.show_data', ['id' => $data->id], []);
      $linkDelete = Link::fromTextAndUrl('Delete', $url_delete);
      $linkEdit = Link::fromTextAndUrl('Edit', $url_edit);
      $linkView = Link::fromTextAndUrl('View', $url_view);

      //get data
      $rows[] = array(
        'id' => $data->id,
        'first_name' => $data->first_name,
        'last_name' => $data->last_name,
        'email' => $data->email,
        'phone' => $data->phone,
        'view' => $linkView,
        'delete' => $linkDelete,
        'edit' =>  $linkEdit,
      );

    }
    // render table
    $form['table'] = [
      '#type' => 'table',
      '#header' => $header_table,
      '#rows' => $rows,
      '#empty' => t('No data found'),
    ];
    return $form;

  }

}

 

our table result is like this:

How to use database api by creating custom Form with CRUD operations in Drupal 8

 

Delete data from database

In this file we will perform delete operation. I have followed certain standards to delete operation, we can also user db_delete operation. The complete code for the delete operation is shown below:

 

<?php

namespace Drupal\mymodule\Form;

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


/**
 * Class DeleteForm
 * @package Drupal\mymodule\Form
 */
class DeleteForm extends ConfirmFormBase
{

  public $id;

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

  public function getQuestion()
  {
    return t('Delete data');
  }

  public function getCancelUrl()
  {
    return new Url('mymodule.display_data');
  }

  public function getDescription()
  {
    return t('Do you want to delete data number %id ?', array('%id' => $this->id));
  }

  /**
   * {@inheritdoc}
   */
  public function getConfirmText()
  {
    return t('Delete it!');
  }

  /**
   * {@inheritdoc}
   */
  public function getCancelText()
  {
    return t('Cancel');
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $id = NULL)
  {

    $this->id = $id;
    return parent::buildForm($form, $form_state);
  }

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

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state)
  {
    $query = \Drupal::database();
    $query->delete('mytable')
      ->condition('id', $this->id)
      ->execute();
    \Drupal::messenger()->addStatus('Succesfully deleted.');
    $form_state->setRedirect('mymodule.display_data');
  }
}

 

When you click delete data, an delete confirmation form will be display like this to confirm if you are sure you want data or not.

How to use database api by creating custom Form with CRUD operations in Drupal 8

Update data in database

The complete code for update data is shown below. so let's change our src/Form/MyModuleForm.php class.

I override these methods : 

buildForm(): I changed default values if I have update operation.

submitForm(): I added condition to check if I have add or update operation by passing ?id=VALUE in update operations.

 

<?php

namespace Drupal\mymodule\Form;

use Drupal\Core\Database\Database;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Symfony\Component\HttpFoundation\RedirectResponse;


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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state)
  {
    $conn = Database::getConnection();
    $data = array();
    if (isset($_GET['id'])) {
      $query = $conn->select('mytable', 'm')
        ->condition('id', $_GET['id'])
        ->fields('m');
      $data = $query->execute()->fetchAssoc();
    }

    $form['first_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('first name'),
      '#required' => true,
      '#size' => 60,
      '#default_value' => (isset($data['first_name'])) ? $data['first_name'] : '',
      '#maxlength' => 128,
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['last_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('last name'),
      '#required' => true,
      '#size' => 60,
      '#default_value' => (isset($data['last_name'])) ? $data['last_name'] : '',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['email'] = [
      '#type' => 'email',
      '#title' => $this->t('email'),
      '#required' => true,
      '#default_value' => (isset($data['email'])) ? $data['email'] : '',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['picture'] = array(
      '#title' => t('picture'),
      '#description' => $this->t('Chossir Image gif png jpg jpeg'),
      '#type' => 'managed_file',
      '#required' => true,
      '#default_value' => (isset($data['fid'])) ? [$data['fid']] : [],
      '#upload_location' => 'public://images/',
      '#upload_validators' => array(
        'file_validate_extensions' => array('gif png jpg jpeg')),
    );
    $form['phone'] = [
      '#type' => 'tel',
      '#title' => $this->t('phone'),
      '#required' => true,
      '#default_value' => (isset($data['phone'])) ? $data['phone'] : '',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['select'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Select element'),
      '#options' => [
        '1' => $this
          ->t('One'),
        '2' => [
          '2.1' => $this
            ->t('Two point one'),
          '2.2' => $this
            ->t('Two point two'),
        ],
        '3' => $this
          ->t('Three'),
      ],
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12'],
      '#default_value' => (isset($data['select'])) ? $data['select'] : '',
    ];
    $form['message'] = [
      '#type' => 'textarea',
      '#title' => $this->t('message'),
      '#required' => true,
      '#default_value' => (isset($data['message'])) ? $data['message'] : '',
      '#wrapper_attributes' => ['class' => 'col-md-6 col-xs-12']
    ];
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('save'),
      '#buttom_type' => 'primary'
    ];
    return $form;
  }

  /**
   * @param array $form
   * @param FormStateInterface $form_state
   */
  public function validateForm(array &$form, FormStateInterface $form_state)
  {
    if (is_numeric($form_state->getValue('first_name'))) {
      $form_state->setErrorByName('first_name', $this->t('Error, The First Name Must Be A String'));
    }
  }


  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state)
  {
    $picture = $form_state->getValue('picture');
    $data = array(
      'first_name' => $form_state->getValue('first_name'),
      'last_name' => $form_state->getValue('last_name'),
      'email' => $form_state->getValue('email'),
      'phone' => $form_state->getValue('phone'),
      'select' => $form_state->getValue('select'),
      'message' => $form_state->getValue('message'),
      'fid' => $picture[0],
    );

    // save file as Permanent
    $file = File::load($picture[0]);
    $file->setPermanent();
    $file->save();

    if (isset($_GET['id'])) {
      // update data in database
      \Drupal::database()->update('mytable')->fields($data)->condition('id', $_GET['id'])->execute();
    } else {
      // insert data to database
      \Drupal::database()->insert('mytable')->fields($data)->execute();
    }

    // show message and redirect to list page
    \Drupal::messenger()->addStatus('Succesfully saved');
    $url = new Url('mymodule.display_data');
    $response = new RedirectResponse($url->toString());
    $response->send();
  }


}

The result of updating data is like this:

How to use database api by creating custom Form with CRUD operations in Drupal 8

 

Show data by ID

The complete code for display data by id is shown below. so let's create src/Controller/MydataController .php class.

this class contains : 

show() method:  In this method, we will display the output in the markup format. 

<?php

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Database;
use Drupal\file\Entity\File;

/**
 * Class MydataController
 * @package Drupal\mymodule\Controller
 */
class MydataController extends ControllerBase
{

  /**
   * @return array
   */
  public function show($id)
  {

    $conn = Database::getConnection();

    $query = $conn->select('mytable', 'm')
      ->condition('id', $id)
      ->fields('m');
    $data = $query->execute()->fetchAssoc();
    $full_name = $data['first_name'] . ' ' . $data['last_name'];
    $email = $data['email'];
    $phone = $data['phone'];
    $message = $data['message'];

    $file =File::load($data['fid']);
    $picture = $file->url();

    return [
      '#type' => 'markup',
      '#markup' => "<h1>$full_name</h1><br>
                    <img src='$picture' width='100' height='100' /> <br>
                    <p>$email</p>
                    <p>$phone</p>
                    <p>$message</p>"
    ];
  }

}

The result of single data is like this:

How to use database api by creating custom Form with CRUD operations in Drupal 8

 

Next steps

  • Clear your Drupal 8 caches. To do this I use this Drush command: drush cr if you don’t currently use Drush, I highly recommend using it, or the Drupal Console.
  • I hope you found this article useful. let me know if you have any questions and I’ll be happy to answer them.

 

Riadh Rahmi

Senior Web Developer PHP/Drupal & Laravel

I am a senior web developer, I have experience in planning and developing large scale dynamic web solutions especially in Drupal & Laravel.

Web Posts

Search

Page Facebook