How to create a custom filter form and update custom table data in Drupal
Here we are going to create add/edit form and save data in a custom table and then list data with a filter form.
So assuming you have custom module . here I have a custom module with name dn_students.
First we are going to create a table , say students is the table name. It has below fields
We dividing this article in to below steps
- List students in a HTML table
- Filter form for students list
- Add/edit and delete rows
List students in a HTML table
Assuming data base table has some data . here we are going to list students data in a table with edit and delete link, we are creating a URL for listing students and mapping this URL with and a controller and a function in controller which is used to render data in a html form.
First we are going to list all data in students table for this we have to add below code in your .routing.yml file.
dn_students.student: path: '/admin/structure/dn_students/students' defaults: _title: 'Students' _controller: '\Drupal\dn_students\Controller\StudentController::listStudents' requirements: _permission: 'administer Students'
We have provided URL permission as administer students. So users having this permission can only access the path /adminatructure/dn_students/students.
In above we have mentioned controller name so we have to create StudentController. For this create a Src folder inside your custom module and create a Controller folder. Inside Controller folder create a php file and name it as StudentController.php.
We have mentioned function listStudents function router files. So we have to implement listStudent() function in StudentController.
So list function StudentController will be looks like as below code.
<?php namespace Drupal\dn_students\Controller; use Drupal\Core\Form\FormBase; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Url; use Drupal\Core\Routing; use Drupal\Core\Form\FormStateInterface; /** * Class StudentController. * * @package Drupal\dn_students\Controller */ class StudentController extends ControllerBase { public function listStudents() { } }
Before we are creating table we need to query student data from table to populate rows in table.
We are creating a common function in .module file for filter form data and listing all data.
Please see code below.
use Drupal\Core\Url; /** * @file * Contains dn_students.module. */ function get_students($opt,$fname,$marks) { $res = array(); if($opt == "All"){ $results = db_select('students', 'st') ->extend('\Drupal\Core\Database\Query\PagerSelectExtender') ->limit(15); $results->fields('st'); $results->orderBy('st.id','DESC'); $res = $results->execute()->fetchAll(); $ret = []; }else{ $results = db_select('students', 'st') ->extend('\Drupal\Core\Database\Query\PagerSelectExtender') ->limit(15); $results->fields('st'); $results->orderBy('st.id','DESC'); $results->condition('fname', $fname); $results->condition('marks', $marks); $res = $results->execute()->fetchAll(); $ret = []; } foreach ($res as $row) { $delete = Url::fromUserInput('/admin/structure/dn_students/students/delete/' . $row->id, array('attributes' => array('onclick' => "return confirm('Are you Sure')"))); $edit = Url::fromUserInput('/admin/structure/dn_students/students/edit/' . $row->id); $edit_link = \Drupal::l('edit', $edit); $delete_link = \Drupal::l('delete', $delete); $mainLink = t('@linkApprove @linkReject', array('@linkApprove' => $edit_link, '@linkReject' => $delete_link)); $ret[] = [ 'id' => $row->id, 'fname' => $row->fname, 'sname' => $row->sname, 'age' => $row->age, 'marks' => $row->marks, 'opt' => $mainLink, ]; } return $ret; }
As shown above $opt parameter determines whether full data to be shown or based on the parameters $fname and $marks.
Variable $delete and $edit used of generating delete and edit respectively for each row in table. Above function return an array $ret with students details.
Now we are again going to StudentController and create logic to create table form in listStudents function.
Implement listSrudents function as shown in below.
public function listStudents() { //Get parameter value while submitting filter form $fname = \Drupal::request()->query->get('fname'); $marks = \Drupal::request()->query->get('marks'); // Create table header. $header = [ 'id' => $this->t('Id'), 'fname' => $this->t('First Name'), 'sname' => $this->t('Second Name'), 'age'=> $this->t('age'), 'Marks'=> $this->t('Marks'), 'opt' =>$this->t('Operations') ]; if($fname == "" && $marks ==""){ $form['table'] = [ '#type' => 'table', '#header' => $header, '#rows' => get_students("All","",""), '#empty' => $this->t('No users found'), ]; }else{ $form['table'] = [ '#type' => 'table', '#header' => $header, '#rows' => get_students("",$fname,$marks), '#empty' => $this->t('No records found'), ]; } $form['pager'] = [ '#type' => 'pager' ]; return $form; }
Add some dummy data in data base table and view link http://localhost/digitalnadeemDrupal1/admin/structure/dn_students/students
Here digitalnadeemDrupal1 is my project name. So you can see below table in Admin screen.
Filter form for students list
No we are going to create filter form just above list table.
For this we have created a file under Form folder as shown below.
Implementation of form using formbase interface is shown below.
<?php namespace Drupal\dn_students\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Database\Database; use Drupal\Core\Url; use Drupal\Core\Routing; /** * Provides the form for filter Students. */ class StudentfilterForm extends FormBase { /** * {@inheritdoc} */ public function getFormId() { return 'dn_student_filter_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form['filters'] = [ '#type' => 'fieldset', '#title' => $this->t('Filter'), '#open' => true, ]; $form['filters']['fname'] = [ '#title' => 'First Name', '#type' => 'search' ]; $form['filters']['marks'] = [ '#title' => 'Marks', '#type' => 'search' ]; $form['filters']['actions'] = [ '#type' => 'actions' ]; $form['filters']['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Filter') ]; return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { if ( $form_state->getValue('fname') == "") { $form_state->setErrorByName('from', $this->t('You must enter a valid first name.')); }elseif( $form_state->getValue('marks') == ""){ $form_state->setErrorByName('marks', $this->t('You must enter a valid to marks.')); } } /** * {@inheritdoc} */ public function submitForm(array & $form, FormStateInterface $form_state) { $field = $form_state->getValues(); $fname = $field["fname"]; $marks = $field["marks"]; $url = \Drupal\Core\Url::fromRoute('dn_students.student') ->setRouteParameters(array('fname'=>$fname,'marks'=>$marks)); $form_state->setRedirectUrl($url); } }
Now we want to show this form just above list table in admin screen. For this go to your listStudents function in StudentController.php
public function listStudents() { //Get parameter value while submitting filter form $fname = \Drupal::request()->query->get('fname'); $marks = \Drupal::request()->query->get('marks'); //====load filter controller $form['form'] = $this->formBuilder()->getForm('Drupal\dn_students\Form\StudentfilterForm'); // Create table header. $header = [ 'id' => $this->t('Id'), 'fname' => $this->t('First Name'), 'sname' => $this->t('Second Name'), 'age'=> $this->t('age'), 'Marks'=> $this->t('Marks'), 'opt' =>$this->t('Operations') ]; ------- ------ ------
Now you see filter form in students list page.
You can filter values by providing first name and marks.
Add/edit and delete rows
Next we are going to provide functionality for edit and delete button. Also we are using single form for add and edit functionality.
Your edit and delete links have below path
http://localhost/digitalnadeemDrupal1/admin/structure/dn_students/students/edit/2
http://localhost/digitalnadeemDrupal1/admin/structure/dn_students/students/delete/2
Now it will show page not found.
So first we are going to create routers for above links.
dn_students.add_student: path: '/admin/structure/dn_students/students/add' defaults: _title: 'Add Students' _form: '\Drupal\dn_students\Form\StudentForm' requirements: _permission: 'administer Students' dn_students.edit_student: path: '/admin/structure/dn_students/students/edit/{id}' defaults: _title: 'Edit Students' _form: '\Drupal\dn_students\Form\StudentForm' requirements: _permission: 'administer Students' dn_students.delete_student: path: '/admin/structure/dn_students/students/delete/{cid}' defaults: _controller: '\Drupal\dn_students\Controller\StudentController::deleteStudent' _form: '\Drupal\dn_students\Form\StudentDeleteForm' _title: 'Delete Student' requirements: _permission: 'administer Students'
Next we have to create Student Form and StudentDeleteForm in Form folder.
See below code for Student Form.
<?php namespace Drupal\dn_students\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Database\Database; use Drupal\Core\Url; use Drupal\Core\Routing; /** * Provides the form for adding countries. */ class StudentForm extends FormBase { /** * {@inheritdoc} */ public function getFormId() { return 'dn_student_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $conn = Database::getConnection(); $record = []; $get_path = explode("/", \Drupal::service('path.current')->getPath()); if (isset($get_path[6])) { $query = $conn->select('students', 'st'); $query->condition('id', $get_path[6])->fields('st'); $record = $query->execute()->fetchAssoc(); } $fname = $record['fname']; $sname = $record['sname']; $age = $record['age']; $marks = $record['marks']; $language = \Drupal::languageManager()->getLanguages(); $form['fname'] = [ '#type' => 'textfield', '#title' => $this->t('First Name'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => (isset($record['fname']) && $get_path[6]) ? $record['fname'] : '', ]; $form['sname'] = [ '#type' => 'textfield', '#title' => $this->t('Second Name'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => (isset($record['sname']) && $get_path[6]) ? $record['sname'] : '', ]; $form['age'] = [ '#type' => 'textfield', '#title' => $this->t('Age'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => (isset($record['age']) && $get_path[6]) ? $record['age'] : '', ]; $form['marks'] = [ '#type' => 'textfield', '#title' => $this->t('Marks'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => (isset($record['marks']) && $get_path[6]) ? $record['marks'] : '', ]; $form['actions']['#type'] = 'actions'; $form['actions']['submit'] = [ '#type' => 'submit', '#button_type' => 'primary', '#default_value' => (isset($get_path[6])) ? $this->t('Update') : $this->t('Save') , ]; return $form; } /** * {@inheritdoc} */ public function validateForm(array & $form, FormStateInterface $form_state) { //print_r($form_state->getValues());exit; } /** * {@inheritdoc} */ public function submitForm(array & $form, FormStateInterface $form_state) { //echo "reaches";exit; $conn = Database::getConnection(); $account = $this->currentUser(); $get_path_update = explode("/", \Drupal::service('path.current')->getPath()); $uid = $account->id(); $names = []; $language = \Drupal::languageManager()->getLanguages(); $field = $form_state->getValues(); $re_url = Url::fromRoute('dn_students.student'); $fields["fname"] = $field['fname']; $fields["sname"] = $field['sname']; $fields["age"] = $field['age']; $fields["marks"] = $field['marks']; if (isset($get_path_update[6])) { $conn->update('students') ->fields($fields)->condition('id', $get_path_update[6])->execute(); drupal_set_message($this->t('Student data has been succesfully updated')); $form_state->setRedirectUrl($re_url); } else { $conn->insert('students') ->fields($fields)->execute(); drupal_set_message($this->t('The Student data has been succesfully saved')); $form_state->setRedirectUrl($re_url); } } }
Here we are handling both edit and add functionality. if parameter present , treats as an edit form by loading field data from database.
Next StudentDeleteForm.php has been created as below.
<?php namespace Drupal\dn_students\Form; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Url; /** * Class StudentDeleteForm. * * @package Drupal\outlook_calendar\Form */ class StudentDeleteForm extends ConfirmFormBase { /** * {@inheritdoc} */ public function getFormId() { return 'dn_student_delete_form'; } public $cid; /** * {@inheritdoc} */ public function getQuestion() { return t('Do you want to delete %cid?', [ '%cid' => $this->cid, ]); } /** * {@inheritdoc} */ public function getCancelUrl() { return new Url('dn_students.student'); } /** * {@inheritdoc} */ public function getDescription() { return t('This action cannot be undone. Only do this if you are sure'); } /** * {@inheritdoc} */ public function getConfirmText() { return t('Delete it!'); } /** * {@inheritdoc} */ public function getCancelText() { return t('Cancel'); } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, $cid = NULL) { $this->id = $cid; return parent::buildForm($form, $form_state); } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $query = \Drupal::database(); $query->delete('students')->condition('id', $this->id)->execute(); drupal_set_message($this->t('The student details has been succesfully deleted')); $form_state->setRedirect('dn_students.student'); } }
Next we are moving to StudentController.php file and add below function.
public function deleteStudent($cid) { $res = db_query("delete from students where id = :id", array(':id' => $cid)); drupal_set_message('Student details deleted'); return $this->redirect('dn_students.student'); }
Also add below code after header variable so that admin can have links to add form and list student s page.
$form['student'] = [ '#title' => $this->t('Add'), '#type' => 'link', '#url' => Url::fromRoute('dn_students.add_student'), ]; $form['show'] = [ '#title' => $this->t('List'), '#type' => 'link', '#url' => Url::fromRoute('dn_students.student'), ];
So complete code of StudentCotroller.php is shown below.
<?php namespace Drupal\dn_students\Controller; use Drupal\Core\Form\FormBase; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Url; use Drupal\Core\Routing; use Drupal\Core\Form\FormStateInterface; /** * Class StudentController. * * @package Drupal\dn_students\Controller */ class StudentController extends ControllerBase { /** * {@inheritdoc} */ public function listStudents() { //Get parameter value while submitting filter form $fname = \Drupal::request()->query->get('fname'); $marks = \Drupal::request()->query->get('marks'); //====load filter controller $form['form'] = $this->formBuilder()->getForm('Drupal\dn_students\Form\StudentfilterForm'); // Create table header. $header = [ 'id' => $this->t('Id'), 'fname' => $this->t('First Name'), 'sname' => $this->t('Second Name'), 'age'=> $this->t('age'), 'Marks'=> $this->t('Marks'), 'opt' =>$this->t('Operations') ]; $form['student'] = [ '#title' => $this->t('Add'), '#type' => 'link', '#url' => Url::fromRoute('dn_students.add_student'), ]; $form['show'] = [ '#title' => $this->t('List'), '#type' => 'link', '#url' => Url::fromRoute('dn_students.student'), ]; if($fname == "" && $marks ==""){ $form['table'] = [ '#type' => 'table', '#header' => $header, '#rows' => get_students("All","",""), '#empty' => $this->t('No users found'), ]; }else{ $form['table'] = [ '#type' => 'table', '#header' => $header, '#rows' => get_students("",$fname,$marks), '#empty' => $this->t('No records found'), ]; } $form['pager'] = [ '#type' => 'pager' ]; return $form; } /** * {@inheritdoc} * Deletes the given student */ public function deleteStudent($cid) { $res = db_query("delete from students where id = :id", array(':id' => $cid)); drupal_set_message('Student details deleted'); return $this->redirect('dn_students.student'); } }
So now you can edit , delete and add entries.
Drupal 8 – You can download above explained sample code here.
Drupal 9 – You download the above-explained sample code here. some functions. deprecated in Drupal 9