Posts Tagged Drupal

Create an action confirm form using “confirm_form()” function in Drupal

Doctor's List with delete option

Doctor's List with delete option


Action confirm form in Drupal

Action confirm form in Drupal

We can easily create an action confirm form using confirm_form() function in Drupal. Normally we need this form when user want to delete something and we want user to confirm his/her action. I am showing here an example in which we are listing all the Doctors information with Edit and Delete option. When user click the delete link we will show him the action confirm form with “Delete” and “Cancel” options. If user click the “Delete” button we will delete that Doctor record from database and if user click on “Cancel” we simply show the doctors list again.

Here is the code. I am using the module name “doctor” in this example.

Step 1. First implement hook_menu() to register new path in Drupal.

function doctor_menu() {
  $items = array();
 
  $items['doctors'] = array(
    'title' => t('Doctors'),
    'page callback' => 'doctors_list',
    'access arguments' => array('access doctor'),
    'type' => MENU_CALLBACK,
  );
 
  $items['doctors/delete/%doctor_user'] = array(
    'title' => t('Delete doctor'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('doctor_delete_confirm', 2),
    'access arguments' => array('access doctor'),
    'type' => MENU_CALLBACK,
  );
 
  return $items;
}

Step 2. Implementing the doctors_list() function to display the list of doctors.

function doctors_list() {
	$header = array(t('Doctor Name'), t('Gender'), t('Phone No.'), t('Status'), t('Action'));
 
	$query = "SELECT * FROM {doctor}";
	$rs = db_query($query);
 
	$row = array();
 
	if ($rs) {
		while ($data = db_fetch_object($rs)) {
			$gender = $data->gender == 'M' ? t('Male') : t('Female');
			$status = $doctor->status ? t('active') : t('inactive');
			$row[] = array(stripslashes($data->firstname) . ' ' . stripslashes($data->lastname), $gender, stripslashes($data->phoneno), $status, 
			"<a href='/doctors/edit/{$data->doctorid}'>" . t('Edit') . "</a> | <a href='/doctors/delete/{$data->doctorid}'>" . t('Delete') . "</a>");
		}
	}
 
	$str .= theme_table($header, $row);
 
	return $str;
}

Step 3. Create a wildcard loader function doctor_user_load() which we used in “doctors/delete/%doctor_user” path. This function checks the given “ID” in path is valid or not. If the given doctor id is not exists in database then “Page not found.” message will display.

function doctor_user_load($doctorid) {
	$query = "SELECT * FROM {doctor} WHERE doctorid = %d";
	$rs = db_query($query, $doctorid);
 
	if ($rs) {
		while ($data = db_fetch_object($rs)) {
			return $data;
		}
	}
 
	return FALSE;
}

Step 4. Create the doctor_delete_confirm() function. We are using the “confirm_form()” function in this function to show action confirm form.

function doctor_delete_confirm(&$form_state, $doctor) {
	$form['_doctor'] = array(
		'#type' => 'value',
		'#value' => $doctor,
	);
 
	return confirm_form($form,
    	t('Are you sure you want to delete this doctor?'),
    	isset($_GET['destination']) ? $_GET['destination'] : "doctors",
    	t('This action cannot be undone.'),
    	t('Delete'),
    	t('Cancel'));
}

Step 5. Create the Form API submit function for doctor_delete_confirm form.

function doctor_delete_confirm_submit($form, &$form_state) {
	$form_values = $form_state['values'];
 
	if ($form_state['values']['confirm']) {
		$doctor = $form_state['values']['_doctor'];
 
		doctor_delete($form_state['values'], $doctor->doctorid);			
 
		drupal_set_message(t('Doctor has been deleted successfully.'));
  	}
 
	drupal_goto("doctors");
}

, ,

15 Comments


Theme Drupal Form

In this example, we are theming Drupal form different from its default layout. Suppose we have a search form with two fields search textbox and category selectbox. We are assuming that our module name is “search“.

Default Layout Search Form

Default Layout Search Form



Themed Layout Search Form

Themed Layout Search Form


Step 1. Create search form using Drupal Form API.

function search_form() {
	$form['str'] = array(
	'#type' => 'textfield',
	'#size' => '32',
	);
 
	$form['category'] = array(
	'#name' => t('category'),
	'#type' => 'select',
	'#options' => array('0' => t('All'), '1' => t('Bars'), '2' => t('Restaurants')),
	);
 
	$form['submit'] = array(
	'#type' => 'submit',
	'#value' => t('Search'),
	);
 
	return $form;
}

Step 2. Register our theme in Drupal theme registry using hook_theme().

function search_theme() {
  global $theme;
 
  return array(
    'search_form' => array(
      'arguments' => array('form' => NULL, 'theme' => $theme),
      'template' => 'search-form',
    ),
  );
}

Step 3. Create search-form.tpl.php file to theme this search form.

<table cellspacing="0">
	<tr>
    	<td class="container-inline"><strong><?php print t('Search');?></strong> <?php print drupal_render($form['str']); ?></td>
        <td class="container-inline"><strong><?php print t('Category');?></strong> <?php print drupal_render($form['category']); ?></td>
        <td><?php print drupal_render($form['submit']); ?></td>
    </tr>
</table>
<?php
print drupal_render($form);
?>

,

3 Comments


Hide Input Format Options from Drupal Node Create Form

Normally you don’t want to show “Input Format” options available in node create form to your website users. You can easily hide them using CSS. We are hiding these options only from normal users and not from admin user.

Input Format

Input Format



1. Create a hook_form_FormID_alter callback function to add the ID to DIV that containing the Input Format options. Suppose our module name is “story” and we want to hide Input Format options from “Create Story” form. So, our callback function name should be story_form_story_node_form_alter(). Where “story_node_form” is Form ID of create story form.

function story_form_story_node_form_alter(&$form, &$form_state) {
	global $user;
 
	if ($user->uid != 1) {
		$form['format']['#attributes'] = array('id' => 'fieldset-input-format');
	}
}

2. We added the ID “fieldset-input-format” to DIV containing Input Format options. Now, we need to hide it using CSS.

#fieldset-input-format {
	display:none;
}

,

3 Comments


Create image upload field using Drupal Form API

Product Form with Image Field

Product Form with Image Field


We can create a image/file upload field using Drupal Form API. Here I am considering an example of product form so we can easily understand its use and its implementation. Our product form have two fields product name and product image. I am considering only three fields productid, product name and product image in our product table. The productid is primary key and set to auto increment. Our module name is ‘product.module’.

STEP 1.

function new_product_form() {
	$form['product_name'] = array(
	'#title' => t('Product Name'),
	'#type' => 'textfield',
	'#required' => TRUE,
	'#description' => t('Please enter product name.'),
	);
 
	// Product picture
	$form['picture'] = array('#type' => 'fieldset', '#title' => t('Product image'));
    	$form['picture']['picture_upload'] = array('#type' => 'file', '#title' => t('Upload product image'), '#size' => 48, 
		'#description' => t('Maximum dimensions are %dimensions and the maximum size is %size kB.', array('%dimensions' => 	'250x250', '%size' => '30')));
 
    	$form['#validate'][] = 'product_validate_picture';
 
	$form['submit'] = array(
	'#type' => 'submit',
	'#value' => t('Submit'),
	);
 
	$form['#redirect'] = 'product_list';	
	$form['#attributes']['enctype'] = 'multipart/form-data';
 
	return $form;
}

We have set the enctype of form as multipart/form-data because we are uploading the file. We also set a validation function product_validate_picture() for validating our uploaded image.


STEP 2.
Now we are creating product_validate_picture() function.

function product_validate_picture(&$form, &$form_state) {
	$validators = array(
    		'file_validate_is_image' => array(),
	    	'file_validate_image_resolution' => array('250x250')),
    		'file_validate_size' => array(30 * 1024),
  	);
  	if ($file = file_save_upload('picture_upload', $validators)) {
    		// Remove the old picture.
    		if (isset($form_state['values']['_product']->image_path) && file_exists($form_state['values']['_product']->image_path)){
      			file_delete($form_state['values']['_product']->image_path);
    		}
 
		$productid = 0;
		if (!isset($form_state['values']['productid'])) { // Execute in case of new product
			$query = "SHOW TABLE STATUS LIKE 'product'";
			$rs = db_query($query);
			$row = db_fetch_object($rs);
 
			$productid = isset($row->Auto_increment) ? $row->Auto_increment : 0;
		}
		else {
			$productid = $form_state['values']['productid'];
		}
 
		$info = image_get_info($file->filepath);
    		$destination = variable_get('product_picture_path', 'product_pictures') .'/picture-'. $productid .'.'. $info['extension'];
    		if (file_copy($file, $destination, FILE_EXISTS_REPLACE)) {
      			$form_state['values']['picture'] = $file->filepath;
    		}
    		else {
      			form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", 
                        array('%directory' => variable_get('product_picture_path', 'product_pictures'))));
    		}
  	}
}

Drupal provide a function file_save_upload() for saving the uploaded file to a new location. Its also take associative array of callback functions used to validate the file as optional argument. Here we passing three callback functions file_validate_is_image, file_validate_image_resolution, and file_validate_size for validating file type as image, image resolution and file size respectively. This function return an object containing the file information or 0 in case of error.

We are using this product_validate_picture() function in both new product and edit product form. So, if ‘_product’ is not set in form values then its fetch the id of next auto_increment value set in product table. In case of edit product form it replace the old product image with new image if user uploaded a new image.

We assign the uploaded image path in our form values so we can store that path in out product table.

$form_state['values']['picture'] = $file->filepath;

STEP 3.

function new_product_form_submit($form_id, $form) {
	$form_values = $form['values'];
 
	$product_name = trim($form_values['product_name']);
	$image_path = $form_values['picture'];
 
	$query = "INSERT INTO product(product_name, image_path) VALUES('%s', '%s')";
	db_query($query, $product_name, $image_path);
 
	drupal_set_message(t('Product has been added successfully.'));
}

Then we will save the product imformation in out product table.

STEP 4.
In case of edit product form we are passing productid as arg(2). We fetch the product imformation using this productid and set the default values in form. We also save the product information and productid in form values.

function edit_product_form() {
	$productid = arg(2);
 
	$query = "SELECT * FROM {product} WHERE productid = '%d'";
	$rs = db_query($query, $productid);
	$product_data = db_fetch_object($rs);
 
	$form['_product'] = array('#type' => 'value', '#value' => $product_data);
	$form['productid'] = array('#type' => 'value', '#value' => $product_data->productid);
 
	$form['product_name'] = array(
	'#title' => t('Product Name'),
	'#type' => 'textfield',
	'#default_value' => stripslashes($product_data->product_name),
	'#required' => TRUE,
	'#description' => t('Please enter product name.'),
	);
 
	// Product picture
	$form['picture'] = array('#type' => 'fieldset', '#title' => t('Product image'));
    	$picture = theme('product_picture', (object)$product_data);
    	if ($product_data->image_path) {
      		$form['picture']['current_picture'] = array('#value' => $picture);
      		$form['picture']['picture_delete'] = array('#type' => 'checkbox', '#title' => t('Delete picture'), 
	  		'#description' => t('Check this box to delete your current picture.'));
    	}
    	else {
     		$form['picture']['picture_delete'] = array('#type' => 'hidden');
    	}
    	$form['picture']['picture_upload'] = array('#type' => 'file', '#title' => t('Upload product image'), '#size' => 48, 
		'#description' => t('Maximum dimensions are %dimensions and the maximum size is %size kB.', 
		array('%dimensions' => '250x250', '%size' => '30')));
 
    	$form['#validate'][] = 'product_validate_picture';
 
	$form['#redirect'] = 'product_list';
 
	$form['#attributes']['enctype'] = 'multipart/form-data';
 
	return $form;
}

STEP 5.
Then we will update the product detail. If user want to delete product image then we will delete the current image of product.

function edit_product_form_submit($form_id, $form) {
	$form_values = $form['values'];
 
	$product_name = trim($form_values['product_name']);
	$image_path = $form_values['_product']->image_path;
 
	 // Delete picture if requested, and if no replacement picture was given.
  	if (!empty($form_values['picture_delete']) && $form_values['picture'] == '') {
    	if ($form_values['_product']->image_path && file_exists($form_values['_product']->image_path)) {
	      	file_delete($form_values['_product']->image_path);
    	}
    	$image_path = '';
  	}
 
	if (isset($form_values['picture']) && $form_values['picture'] != '') {
		$image_path = $form_values['picture'];
	}
 
	$query = "UPDATE {product} SET product_name = '%s', image_path = '%s' WHERE productid = '%d'";
	db_query($query, $product_name, $image_path, $productid);
 
	drupal_set_message(t('Product has been updated successfully.'));
}

STEP 6.
We are also theming our product image. For this, we are using a product-picture.tpl.php file. First we register our theme in theme registry using hook_theme() callback function.

function product_theme() {
  	return array(
    	'product_picture' => array(
      	'arguments' => array('product' => NULL),
      	'template' => 'product-picture',
    	),
  	);
}
 
function template_preprocess_product_picture(&$variables) {
    $variables['picture'] = '';
 
    $product = $variables['product'];
    if (!empty($product->image_path) && file_exists($product->image_path)) {
      $picture = file_create_url($product->image_path);
    }
    else if (variable_get('product_picture_default', '')) {
      $picture = variable_get('product_picture_default', '');
    }
 
    if (isset($picture)) {
      $alt = t("@product's picture", array('@product' => $product->product_name ));
      $variables['picture'] = theme('image', $picture, $alt, $alt, '', FALSE);
    }
}
<?php 
//product-picture.tpl.php file 
?>
<div class="picture">
  <?php print $picture; ?>
</div>

, ,

2 Comments


Create Drupal Form elements like ‘DATE’ element

Drupal Form Elements

Drupal Form Elements

Sometime we require from elements for filling “Height” or “Credit card expiry date” or “Phone number(in any specific format)”. We can easily create these type of form elements in Drupal. I am showing here how we can create such type of form elements.

Here I am taking the example of “Height” element. For height element we require two select boxes. One for showing feet and other for inches.

Step 1: First create “hook_elements()” in your module. This hook allows modules to declare their own Forms API element types and specify their default values.

function module_name_elements() {
	return array(
	'height' => array(
     	'#input' => TRUE,
     	'#process' => array('expand_height'),
     	'#element_validate' => array('height_validate'),
  	),
}

Step 2: Define the “#process” callback function “expand_height()”. This will take $element as argument and process it.

function expand_height($element) {
	// Assigning default values to element. You can override these values by passing your own values using "#default_value".
	if (empty($element['#value'])) {
    	$element['#value'] = array(
      		'feet' => '-',
      		'inch' => '-',
    	);
  	}
 
	$element['#tree'] = TRUE;
 
	$parents = $element['#parents'];
	$parents[] = 'feet';
    	$element['feet'] = array(
      	'#type' => 'select',
		'#default_value' => $element['#value']['feet'],
		'#options' => array('-' => '-', '2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8',),
		'#suffix' => t('ft.'),
    	);
 
	$parents = $element['#parents'];
    	$parents[] = 'inch';
    	$element['inch'] = array(
		'#type' => 'select',
		'#default_value' => $element['#value']['inch'],
		'#options' => array('-' => '-', '0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', 
			'7' => '7', '8' => '8', '9' => '9', '10' => '10', '11' => '11'),
		'#suffix' => t('in.'),
    	);
 
	return $element;
}

Step 3: Theme your custom element by defining “theme_hook()” for your element.

function theme_height($element) {
  	return theme('form_element', $element, '<div class="container-inline">'. $element['#children'] .'</div>');
}

step 4: We need to register our above theme function “theme_height()” in theme registry. We can do that using “hook_theme()” hook. To see effect of your code, clear your cache because all theme hook is cached by Drupal.

function module_name_theme() {
	return array(
		'height' => array(
      		'arguments' => array('element' => NULL))
  	);
}

Step 5: Define “hook_validate()” for your element. This function is automatically called by FORM API and it validate the given value of element. We verify the values of element and if value is not valid we will set error message using form_error() function. This function take $element as argument.

function height_validate($element) {
  	if (trim($element['#value']['feet']) == '-' || trim($element['#value']['inch']) == '-') {
    		form_error($element, t('The specified height is invalid.'));
  	}
}

How you use it:

$user->height = array('feet' => '5', 'inch' => '8');
// Create element of 'type' height
$form['height'] = array('#type' => 'height',
		'#title' => t('Height'),
		'#required' => TRUE,
		'#default_value' => isset($user->height) ? $user->height : array('feet' => '-', 'inch' => '-'),
	);
 
//Access it in form_submit() like this
$height = $edit['height']['feet']. '-' . $edit['height']['inch'];

Code for Phone Number Element

<php
function mymodule_theme() {
  	return array(
    	'phone' => array(
      	'arguments' => array('element' => NULL))
  	);
}
 
function mymodule_elements() {
	return array(
		'phone' => array(
     	'#input' => TRUE,
     	'#process' => array('expand_phone'),
     	'#element_validate' => array('phone_validate'),
  		),
  	);
}
 
function expand_phone($element) {
	if (empty($element['#value'])) {
    	$element['#value'] = array(
      		'part1' => '',
      		'part2' => '',
      		'part3' => '',
    	);
  	}
 
	$element['#tree'] = TRUE;
 
	$parents = $element['#parents'];
        $parents[] = 'part1';
        $element['part1'] = array(
      	'#type' => 'textfield',
		'#size' => 4,
		'#maxlength' => 3,
		'#default_value' => $element['#value']['part1'],
		'#prefix' => '(',
		'#suffix' => ')',
    );
 
	$parents = $element['#parents'];
        $parents[] = 'part2';
        $element['part2'] = array(
      	'#type' => 'textfield',
		'#size' => 4,
		'#maxlength' => 3,
		'#default_value' => $element['#value']['part2'],
		'#suffix' => '-',
    );
 
	$parents = $element['#parents'];
        $parents[] = 'part3';
        $element['part3'] = array(
      	'#type' => 'textfield',
		'#size' => 6,
		'#maxlength' => 4,
		'#default_value' => $element['#value']['part3'],
    );
 
	return $element;
}
 
function theme_phone($element) {
  	return theme('form_element', $element, '<div class="container-inline">'. $element['#children'] .'</div>');
}
 
function phone_validate($element) {
  	if (trim($element['#value']['part1']) == '' || trim($element['#value']['part2']) == '' || trim($element['#value']['part3']) == '' ||
  		!is_numeric($element['#value']['part1']) || !is_numeric($element['#value']['part2']) || !is_numeric($element['#value']['part3'])) {
    	form_error($element, t('The specified phone number is invalid.'));
  	}
}
?>

Code for Credit card expiry date Element

<?php
function mymodule_theme() {
  	return array(
    	'cardexpdate' => array(
       	'arguments' => array('element' => NULL))
	);
}
 
function mymodule_elements() {
	return array(
		'cardexpdate' => array(
     	        '#input' => TRUE,
     	        '#process' => array('expand_cardexpdate'),
     	        '#element_validate' => array('cardexpdate_validate'),
  		),
  	);
}
 
function expand_cardexpdate($element) {
	$next_month_date = strtotime("+1 month");
	$month = date('n', $next_month_date);
	$year = date('Y', $next_month_date);
 
	if (empty($element['#value'])) {
		$element['#value'] = array(
      		'month' => $month,
      		'year' => $year,
    	);
  	}
 
	$element['#tree'] = TRUE;
 
	$parents = $element['#parents'];
        $parents[] = 'month';
        $element['month'] = array(
      	'#type' => 'select',
		'#default_value' => $element['#value']['month'],
		'#options' => drupal_map_assoc(range(1, 12), 'cardexpdate_map_month'),
    );
 
	$parents = $element['#parents'];
        $parents[] = 'year';
        $element['year'] = array(
		'#type' => 'select',
		'#default_value' => $element['#value']['year'],
		'#options' => drupal_map_assoc(range($year, 2020)),
    );
 
	return $element;
}
 
function theme_cardexpdate($element) {
	return theme('form_element', $element, '<div class="container-inline">'. $element['#children'] .'</div>');
}
 
function cardexpdate_validate($element) {
	$month = $element['#value']['month'];
	$year = $element['#value']['year'];
 
	$exp_date = mktime(0, 0, 0, $month, date('j'), $year);
 
	if ($exp_date < time()) {
    	form_error($element, t('The specified expiry date is invalid.'));
  	}
}
 
function cardexpdate_map_month($month) {
	return format_date(gmmktime(0, 0, 0, $month, 2, 1970), 'custom', 'm', 0);
}
?>

,

5 Comments