articles

Home / DeveloperSection / Articles / Creating Custom Module in Drupal

Creating Custom Module in Drupal

Anonymous User 10232 09-Apr-2012

A module is a collection of functions that link into Drupal, providing additional functionality for your Drupal installation or Drupal Website.

Generally module has three types Core, Contributed and Custom. Let’s take a look on these components.

1.       Core: It is a module that ship with Drupal and are approved by core developers and community.

2.       Contributed: It is a module that written by the Drupal community and shared under the same GNU public license as drupal.

3.       Custom:  It is module that written or created by the developer of website.

To create a custom module in Drupal content management system, first of all you’ve to understand about module anatomy.

Anatomy of a Module (Custom module):

There are the two files which play an important role in building custom module; required file and optional file.

Required File:

.info file: This is the information file which describes about the module such module name, module version etc.

.module file: This file contains php coding and defines what functionality will be increase of drupal after installing in drupal site.

 Optional File:

.install file: This file defines the install/uninstall scripts of custom module.

.css file: This is cascading style sheet (CSS) file which manages look and feel of drupal website.

.inc file: This file defines the additional included file which widely used in our product.

Now after the anatomy of a Module; here one question arises, where do module files reside? The answer of this question is; for core module it will be /module/ subdirectory and for contrib and custom module /sites/all/modules.

Here I’m creating a module to count the downloaded software from your website. Let’s have a look a brief idea about it.

.info File Code:

name = Download Count

description = Tracks file downloads for Drupal private core file fields.

core = 7.x

dependencies[] = field

dependencies[] = file

 

; Information added by mindstick.com packaging script on 2012-04-07

version = "7.x-3.x-dev"

core = "7.x"

project = "Mod_Download_Count"

datestamp = "1331640715"


.module File Code:

<?php

 

/**

 * @file

 * Tracks file downloads for files stored in the drupal files table using the private files setting or custom private filefield.

 */

 

// Load all field module hooks.

module_load_include('inc', 'download_count', 'includes/download_count.field');

 

/**

 * Implements hook_help().

 */

function download_count_help($path, $arg) {

  switch ($path) {

    case 'admin/help#download_count':

      return '<p>' . t('Counts file downloads for private core file fields and logs a message to the watchdog table.') . '</p>';

  }

}

 

/**

 * Implements hook_permission().

 */

function download_count_permission() {

  $perms = array(

    'view download counts' => array(

      'title' => t('view download counts'),

    ),

    'skip download counts' => array(

      'title' => t('skip download counts'),

      'description' => t('Don\'t count downloads for users with this role.'),

    ),

    'reset download counts' => array(

      'title' => t('reset download counts'),

    ),

    'export download counts' => array(

      'title' => t('export download counts'),

    ),

  );

  return $perms;

}

 

/**

 * Implements hook_menu().

 */

function download_count_menu() {

  $items = array();

 

  $items['admin/config/media/download-count'] = array(

    'title' => 'Download count',

    'description' => 'Tracks file downloads for files stored in private core file fields.',

    'page callback' => 'drupal_get_form',

    'page arguments' => array('download_count_admin_settings'),

    'access arguments' => array('administer site configuration'),

    'file' => 'includes/download_count.settings.inc',

  );

  $items['admin/config/media/download-count/clear'] = array(

    'title' => 'Clear Cache',

    'page callback' => 'drupal_get_form',

    'page arguments' => array('download_count_clear_confirm'),

    'access arguments' => array('administer site configuration'),

    'type' => MENU_CALLBACK,

    'file' => 'includes/download_count.settings.inc',

  );

  $items['admin/config/media/download-count/settings'] = array(

    'title' => 'Settings',

    'weight' => 1,

    'type' => MENU_DEFAULT_LOCAL_TASK,

  );

  $items['admin/reports/download-count'] = array(

    'title' => 'Download Counts',

    'description' => 'Download history of files attached to private core file fields.',

    'page callback' => 'download_count_view_page',

    'page arguments' => array('download_count'),

    'access arguments' => array('view download counts'),

    'type' => MENU_NORMAL_ITEM,

    'file' => 'includes/download_count.pages.inc',

  );

  $items['admin/reports/download-count/%download_count_entry/details'] = array(

    'title' => 'Download Count Details',

    'page callback' => 'download_count_view_details',

    'page arguments' => array(3),

    'access arguments' => array('view download counts'),

    'type' => MENU_CALLBACK,

    'file' => 'includes/download_count.pages.inc',

  );

  $items['admin/reports/download-count/%download_count_entry/reset'] = array(

    'title' => 'Download Count Reset',

    'page callback' => 'drupal_get_form',

    'page arguments' => array('download_count_reset_form', 3),

    'access arguments' => array('reset download counts'),

    'type' => MENU_CALLBACK,

    'file' => 'includes/download_count.pages.inc',

  );

  $items['admin/reports/download-count/%download_count_entry/export'] = array(

    'title' => 'Download Count Export CSV',

    'page callback' => 'drupal_get_form',

    'page arguments' => array('download_count_export_form', 3),

    'access arguments' => array('export download counts'),

    'type' => MENU_CALLBACK,

    'file' => 'includes/download_count.export.inc',

  );

 

  return $items;

}

 

/**

 * Implements hook_views_api().

 */

function download_count_views_api() {

  return array(

    'api' => 3.0,

    'path' => drupal_get_path('module', 'download_count') . '/includes',

  );

}

 

/**

 * Menu wildcard loader.

 */

function download_count_entry_load($dcid) {

  return $dcid == 'all' ? $dcid : db_query('SELECT dc.dcid, dc.fid, dc.uid, dc.type, dc.id, dc.ip_address, dc.referrer, dc.timestamp, f.filename, f.uri, f.filemime, f.filesize FROM {download_count} dc JOIN {file_managed} f ON dc.fid = f.fid WHERE dcid = :dcid', array(':dcid' => $dcid))->fetchObject();

}

 

/**

 * Implements hook_library().

 */

function download_count_library() {

  if (module_exists('libraries')) {

    $path = libraries_get_path('jquery.sparkline', FALSE) . '/jquery.sparkline.min.js';

  }

  else {

    $path = drupal_get_path('module', 'download_count') . '/jquery.sparkline.min.js';

  }

 

  $libraries['jquery.sparkline'] = array(

    'title' => 'jquery sparkline',

    'website' => 'http://www.omnipotent.net/jquery.sparkline/',

    'version' => '1.6',

    'js' => array(

      $path => array(),

    ),

  );

  return $libraries;

}

 

/**

 * Implements hook_file_download_access_alter().

 */

function download_count_file_download_access_alter(&$grants, $file, $entity_type, $entity) {

  $time =  REQUEST_TIME;

 

  //if role should be skipped, return.

  if (user_access('skip download counts')) {

    return;

  }

 

  //if no access, simply return.

  if (!in_array(TRUE, $grants)) {

    return;

  }

 

  //check flood control

  $flood_limit = variable_get('download_count_flood_limit', 0);

  if ($flood_limit > 0) {

    $flood_window = variable_get('download_count_flood_window', 5);

    if (!flood_is_allowed('download_count-fid_' . $file['fid'], $flood_limit, $flood_window)) {

      return;

    }

  }

 

  //validate file has extension that should be counted, if not return.

  $extensions = explode(' ', drupal_strtolower(trim(variable_get('download_count_excluded_file_extensions', 'jpg jpeg gif png'))));

  if (count($extensions)) {

    $extension = drupal_strtolower(pathinfo($file['filename'], PATHINFO_EXTENSION));

    if (in_array($extension, $extensions)) {

      return;

    }

  }

 

  // Count the download.

  global $user;

  $entity_info = entity_get_info($entity_type);

  $ip = ip_address();

  $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : NULL;

 

  $id = db_insert('download_count')

  ->fields(array(

    'fid' => $file['fid'],

    'uid' => $user->uid,

    'type' => $entity_type,

    'id' => $entity->$entity_info['entity keys']['id'],

    'ip_address' => $ip,

    'referrer' => $referrer,

    'timestamp' => $time,

  ))

  ->execute();

  flood_register_event('download_count-fid_' . $file['fid'], 3600);

  watchdog('download_count', '%file was downloaded by user #%uid from %ip', array('%file' => $file['filename'], '%uid' => $user->uid, '%ip' => $ip), WATCHDOG_NOTICE);

 

  if (module_exists('rules')) {

    rules_invoke_event('download_count_file_download', (object) $file, $user);

  }

}

 

/**

 * Implements hook_cron_queue_info().

 */

function download_count_cron_queue_info() {

  $queues['download_count'] = array(

    'worker callback' => 'download_count_cache_processor',

    'time' => 60,

  );

  return $queues;

}

 

/**

 * Implements hook_cron().

 *

 * Daily file download counts are cached for convenience.

 */

function download_count_cron() {

  $time = REQUEST_TIME;

  $status = 0;

  $count = 0;

  $last_cron = variable_get('download_count_last_cron', 0);

 

  $result = db_query('SELECT fid, type, id, UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(timestamp))) as date, COUNT(dcid) as count FROM {download_count} WHERE timestamp > :last_cron GROUP BY type, id, fid, DATE(FROM_UNIXTIME(timestamp))', array(':last_cron' => $last_cron));

  $queue = DrupalQueue::get('download_count');

  foreach ($result as $record) {

    $queue->createItem($record);

    $count++;

  }

  if ($count > 0) {

    watchdog('download_count', 'Download count queued %count new entries for caching.',  array('%count' => $count), WATCHDOG_NOTICE);

  }

  variable_set('download_count_last_cron', $time);

}

 

/**

 * Adds download count data to the daily cache table.

 *

 * @param $record

 *   An object containing the download to cache.

 */

function download_count_cache_processor($record) {

  db_merge('download_count_cache')

    ->key(array('type' => $record->type, 'id' => $record->id, 'fid' => $record->fid, 'date' => $record->date))

    ->fields(array(

        'count' => $record->count,

      ))

    ->expression('count', 'count + :inc', array(':inc' => $record->count))

    ->execute();

}

 

/**

 * Implements hook_block_info().

 */

function download_count_block_info() {

  $blocks['top_files']['info'] = t('Top Downloaded Files');

  $blocks['recent_files']['info'] = t('Recently Downloaded Files');

  return $blocks;

}

 

/**

 * Implements hook_block_configure().

 */

function download_count_block_configure($delta) {

  $form['download_count_' . $delta . '_block_limit'] = array(

    '#type' => 'textfield',

    '#title' => t('Number of items to display'),

    '#size' => 5,

    '#default_value' => variable_get('download_count_' . $delta . '_block_limit', 10),

  );

  return $form;

}

 

/**

 * Implements hook_block_save().

 */

function download_count_block_save($delta, $edit) {

  variable_set('download_count_' . $delta . '_block_limit', $edit['download_count_' . $delta . '_block_limit']);

}

 

/**

 * Implements hook_block_view().

 */

function download_count_block_view($delta) {

  switch ($delta) {

    case 'top_files':

      $blocks['subject'] = t('Top Downloaded Files');

      $blocks['content'] = _download_count_block_contents('top_files');

      break;

 

    case 'recent_files':

      $blocks['subject'] = t('Recently Downloaded Files');

      $blocks['content'] = _download_count_block_contents('recent_files');

      break;

  }

 

  return $blocks;

}

 

/**

 * Generate block contents based on delta.

 */

function _download_count_block_contents($block) {

  $limit = (int) variable_get('download_count_' . $block . '_block_limit', 10);

  $rows = array();

  if ($block == 'top_files') {

    $sql = 'SELECT dcc.fid, dcc.count, f.filename, f.filesize FROM {download_count_cache} dcc JOIN {file_managed} f ON dcc.fid = f.fid ORDER BY dcc.count DESC';

  }

  else {

    $sql = 'SELECT dc.fid, MAX(dc.timestamp) as date, f.filename, f.filesize FROM {download_count} dc JOIN {file_managed} f ON dc.fid = f.fid GROUP BY dc.fid ORDER BY date DESC';

  }

 

  $header[] = array(

    'data' => t('Name'),

    'class' => 'filename',

  );

  $header[] = array(

    'data' => t('Size'),

    'class' => 'size',

  );

  $header[] = array(

    'data' => $block == 'top_files' ? t('Count') : t('Last Downloaded'),

    'class' => $block == 'top_files' ? 'count' : 'last',

  );

 

  $result = db_query_range($sql, 0, $limit);

  foreach ($result as $file) {

    $row = array();

    $row[] = check_plain($file->filename);

    $row[] = format_size($file->filesize);

    $row[] = $block == 'top_files' ? $file->count : t('%time ago', array('%time' => format_interval(REQUEST_TIME - $file->date)));

    $rows[] = $row;

  }

 

  if (count($rows)) {

    return theme('table', array('header' => $header, 'rows' => $rows, 'sticky' => FALSE));

  }

}

 

/**

 * Implements hook_theme().

 */

function download_count_theme() {

  $theme= array(

    'download_count_file_field_formatter' => array(

    'variables' => array('file' => NULL),

    'file' => 'includes/download_count.field.inc',

    ),

  );

  return $theme;

}

 

.install File Code:

<?php

 

/**

 * @file

 * Installation code for the download_count module.

 */

 

/**

 * Implements hook_schema().

 */

function download_count_schema() {

  $schema['download_count'] = array(

    'fields' => array(

      'dcid' => array(

        'description' => 'Primary Key: Unique download count id.',

        'type' => 'serial',

        'unsigned' => TRUE,

        'not null' => TRUE,

      ),

      'fid' => array(

        'description' => 'The id from the drupal file_managed table of the file downloaded.',

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

      ),

      'uid' => array(

        'description' => 'The uid of the user that downloaded the file.',

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

      ),

      'type' => array(

        'description' => 'The name of the entity type to which the file was attached when downloaded.',

        'type' => 'varchar',

        'length' => 64,

        'not null' => TRUE,

        'default' => '',

      ),

      'id' => array(

        'description' => 'The primary key of the entity to which the file was attached when downloaded.',

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

        'default' => 0,

      ),

      'ip_address' => array(

        'description' => "The ip address of the downloading user.",

        'type' => 'varchar',

        'length' => 128,

        'not null' => TRUE,

        'default' => 0,

      ),

      'referrer' => array(

        'description' => 'Referrer URI.',

        'type' => 'varchar',

        'length' => 255,

        'not null' => TRUE,

        'default' => '',

      ),

      'timestamp' => array(

        'description' => 'The date-time the file was downloaded.',

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

        'default' => 0,

      ),

    ),

    'primary key' => array('dcid'),

    'indexes' => array(

      'dc_fid' => array('fid'),

      'dc_uid' => array('uid'),

      'dc_type' => array('type'),

      'dc_id' => array('id'),

      'dc_ip' => array('ip_address'),

      'dc_timestamp' => array('timestamp'),

      'dc_fid_type_id' => array('fid', 'type', 'id'),

    ),

  );

 

  $schema['download_count_cache'] = array(

    'fields' => array(

      'dcc_id' => array(

        'description' => 'Primary Key: Unique download count cache id.',

        'type' => 'serial',

        'unsigned' => TRUE,

        'not null' => TRUE,

      ),

      'fid' => array(

        'description' => t('The id from the drupal files table of the file downloaded.'),

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

        'default' => 0,

      ),

      'type' => array(

        'description' => 'The name of the entity type to which the file was attached when downloaded.',

        'type' => 'varchar',

        'length' => 64,

        'not null' => TRUE,

        'default' => '',

      ),

      'id' => array(

        'description' => 'The primary key of the entity to which the file was attached when downloaded.',

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

        'default' => 0,

      ),

      'date' => array(

        'description' => t('The date the file was downloaded.'),

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

        'default' => 0,

      ),

      'count' => array(

        'description' => t('Number of times a file was downloaded in one day.'),

        'type' => 'int',

        'unsigned' => TRUE,

        'not null' => TRUE,

        'default' => 0,

      ),

    ),

    'primary key' => array('dcc_id'),

    'indexes' => array(

      'dcc_fid' => array('fid'),

      'dcc_type' => array('type'),

      'dcc_id' => array('id'),

      'dcc_timestamp' => array('date'),

      'dcc_fid_type_id' => array('fid', 'type', 'id', 'date'),

    ),

  );

 

  return $schema;

}

 

/**

 * Implements hook_uninstall().

 */

function download_count_uninstall() {

  variable_del('download_count_excluded_file_extensions');

  variable_del('download_count_view_page_limit');

  variable_del('download_count_view_page_items');

  variable_del('download_count_view_page_title');

  variable_del('download_count_view_page_header');

  variable_del('download_count_view_page_footer');

  variable_del('download_count_export_range');

  variable_del('download_count_sparklines');

  variable_del('download_count_sparkline_min');

  variable_del('download_count_sparkline_height');

  variable_del('download_count_sparkline_width');

  variable_del('download_count_last_cron');

  variable_del('download_count_details_daily_limit');

  variable_del('download_count_details_weekly_limit');

  variable_del('download_count_details_monthly_limit');

  variable_del('download_count_details_yearly_limit');

  variable_del('download_count_flood_limit');

  variable_del('download_count_flood_window');

  drupal_set_message(t('The download_count module has been uninstalled.'));

}


 

.css File Code:

#download-count-table a {

  display: inline-block;

  line-height: .9em;

}

#download-count-table a + a {

  border-left: 1px solid;

  margin-left: 0.5em;

  padding-left: 0.5em;

}

table.download-count-table th {

  font-weight: bold

}

table.download-count-table caption {

  font-weight: bold;

  font-size: 1.3em;

  padding: 2em 0 1em 0;

}

table.download-count-details {

  width: 50%;

}

table.download-count-details th.number {

  width: 10%;

}

table.download-count-details th.range {

  width: 45%;

}

table.download-count-details th.count {

  width: 45%;

}

table.download-count-details td,

table.download-count-details th {

  text-align: center;

}

#download-count-total-bottom {

  padding-top: 2em;

}



Now put all these file in ‘Mod_Download_Count’ directory and create zip folder of this directory.

Creating Custom Module in Drupal

Now login in Drupal Administrator Panel and go to Modules option. 

Creating Custom Module in Drupal

Now click on ‘Install new module’ link and select appropriate module file either from local computer or from web.

Creating Custom Module in Drupal

After selecting appropriate file directory click on ‘install’ button.

Creating Custom Module in Drupal

Now to see your module functionality clicks on ‘Enable newly added module’ link. After selecting this link you will see following window.

Creating Custom Module in Drupal

Now select the Enable checkbox option and click on ‘Save configuration’ option.

This is the complete description about Drupal Custom Module. I hope you will enjoy it.



Updated 07-Sep-2019
I am a content writter !

Leave Comment

Comments

Liked By