Thursday, March 31, 2016

Drupal 8 custom module

Using below easy steps you can able to create custom module in Drupal 8.

// Steps.
1. Go to your root directory
2. Navigate to modules folder
3. Under modules folder, create two directories (Contrib, Custom)
4. Under custom folder, create your first module folder (first_module)

// Create first_module.info.yml in the root of the first_module directory.
     
name: First Module
description: An experimental module to build our first Drupal 8 module
package: Custom
type: module
version: 1.0
core: 8.x
// .module file not mandatory in Drupal 8 for custom module.
#. Create src & Controller folder under first_module.
#. Within the Controller folder, create a file called FirstController.php.
// Write below codes under FirstController.php
     
namespace Drupal\first_module\Controller; 
use Drupal\Core\Controller\ControllerBase; 
class FirstController extends ControllerBase {
  public function content() {
  return array(
      '#type' => 'markup',
      '#markup' => t('Hello world'),
    );
  }
}
// Add a route file.
#. Create a file called first_module.routing.yml
#. Add the following code to first_module.routing.yml
     
first_module.content:
  path: '/first'
  defaults:
    _controller: 'Drupal\first_module\Controller\FirstController::content'
    _title: 'Hello world'
  requirements:
    _permission: 'access content'

// View the content.
If you now go to /first, you will see the Hello World message that is being returned from the controller.

// Create menu link.
#. In your module root, create first_module.links.menu.yml
# . Add the following:
     
first_module.admin:
  title: 'First module settings'
  description: 'A basic module to return hello world'
  parent: system.admin_config_development
  route_name: first_module.content
  weight: 100

#. Clear the cache and then you should see the menu item under configuration -> development.
#. Click on the menu item and it will take you to /first.

A custom block.


// First, we need to create a new plugin for the module.
// [Plugins] are new in Drupal 8 and provide swappable pieces of functionality.

#. To get started, create a new directory in the module’s src folder called Plugin.
This is where you can store all of your plugins for this module.

#. Then create a folder called Block. A block is a plugin type.
#. And inside the Block folder, create a file called HelloBlock.php.

#. Another new concept to Drupal that we need to use for the block is Annotations.
 In order for Drupal to find your block code, you need to implement a code comment in a specific way, called an Annotation.

// The full code for HelloBlock.php
     
 $this->t('Hello, World!'),
    );
  }
 
}

See this link for how to enable & display the module.

Reference link:
-- Create your first Drupal 8 module

Refer below image for folder structure. 


You can download full code of this module from here : https://github.com/kali-dasan/D8-custom_module


Wednesday, March 2, 2016

Drupal batch process to download or create CSV/XLS

Using below code you can able to download or create CSV/XLS file with huge data (I have used it for around 90,000 records) using batch process.

// Menu callback.
     
$items['url_to_my_batch'] = array(
  'title' => "Batch process to download some huge contents",
  'page callback' => 'my_batch_callback',
  'access arguments' => 'administer users',
  'type' => MENU_CALLBACK,
);
Batch menu call back definition.
     
 function my_batch_callback() {
  // File create.
  $download_folder = 'public://my_folder';
  $file_name = 'my-file-' . date('m-d-Y') . '.csv';
  $header = array('Name', 'age', .....);
  // Append header values.
  if (!file_exists($download_folder)) {
    mkdir($download_folder, 0777, TRUE);
  }
  $fp = fopen($download_folder . '/' . $file_name, 'w');
  fprintf($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
  fwrite($fp, implode(",", $header) . "\n");
  fclose($fp);
  // Batch process starts.
  $total = count_for_batch(); // Get total count. It was 90,000 records in my case.
  $batch = array(
    'title' => t('Batch process to download huge data'),
    'finished' => 'process_finished_batch',
  );
  $i = 0;
  $total = $total +1000;
  while($i <= $total) {
    $batch['operations'][] = array('process_my_batch', array($i, $total));
    $i += 1000 ;
  }
  batch_set($batch);
  batch_process('success/page');
}
I have split 90,000 records into 1000 records each to single batch process.
// Collect table row values
     
function process_my_batch($from, $total, &$context) {
  $download_folder = 'public://my_folder';
  $file_name = 'my-file-' . date('m-d-Y') . '.csv';
  $results = function_to_collect_rows($from, 1000);
  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['max'] = count($results[0]);
  }
  $fwp = fopen($download_folder . '/' . $file_name, 'a');
  if (!empty($results[0])) {
    foreach ($results[0] as $key => $value) {
      if (!empty($value)) {
        fwrite($fwp, implode(",", $value) . "\n");
      }
      //increment our progress
      $context['sandbox']['progress']++;
    }
  }
  fclose($fwp);
  //check if batch is finished and update progress
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
}
// Batch finish.
     
function process_finished_batch($success, $results, $operations) {
  if($success) {
    $message = t('The batch was successful');
    drupal_set_message($message);
  }
  else {
    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
  }
}

Some useful references:
-- Drupal 7 Batch Process Example

Friday, January 22, 2016

Drupal7 table with sortable headers and pagination

Using below code you can able to display table with sortable headers & pagination.

// Define table headers
     
$header = array(
  array('data' => 'ID', 'field' => 'id', 'sort' => 'ASC'),
  array('data' => 'Name', 'field' => 'name'),
  array('data' => 'Date of birth', 'field' => 'dob'),
  array('data' => 'Email', 'field' => 'email'),
);
Here 'field' values are database field values. (Ex: 'field' => 'name')
If you want to assign sort option to table field like ID, use 'sort' attribute (ex: 'sort' => 'ASC').

// DB query
     
   $select = db_select('my_table', 't')
      // This line is to enable pagination
      ->extend('PagerDefault')
      // This is for table sort
      ->extend('TableSort');
      // Example for LIKE condition
      if (condition) {
        $select->condition('email', '%' . db_like($qry['email']) . '%', 'LIKE');
      }
   $select->fields('t', array('id', 'name', 'dob', 'email'))
      // Pagination limit
      ->limit(10)
      // Sort table header
      ->orderByHeader($header)
      // Example for group by
      ->groupBy('t.email')
      // example for order by
      ->orderBy('updated_time', 'DESC')
      // Example for COUNT().
      ->addExpression('COUNT(*)', 'total');
    $results = $select->execute();

// Collect table row values
     
foreach ($results as $row) {
   $rows[] = array(
        // ID with hyperlink.
        l($row->id, 'url', array('query' => array('qry' => $row->email), 'attributes' => array('target' => '_blank'))),
        $row->name,
        $row->dob,
        $row->email, // $row->total can also be used here.
      );
    }
// Putting all together to form a table.
     
    $output .= theme('table', array('header' => $header, 'rows' => $rows, "empty" => t("Table has no row!"), "sticky" => true));
    $output .= theme('pager');
    return $output;

Some useful references:
-- A Drupal 7 table with sortable headers and pager
-- DRUPAL 7 - CREATING DRUPAL STYLE TABLES WITH PAGING, SORTING AND FILTER.

Wednesday, November 25, 2015

Drupal preview image with remove option after upload file using form API

Preview image with remove option after upload file using form API.

// Create form with '#type' => 'managed_file'.
     
function kali_custom_form($form, &$form_state) {
 $form['upload'] = array(
  '#type' => 'managed_file',
  '#title' => t('Image Preview'),
  '#upload_location' => 'public://',
  '#theme' => 'kali_preview_theme', // define theme for preview
  '#progress_indicator' => 'throbber',
  '#upload_validators' => array(
  'file_validate_is_image' => array(),
 'file_validate_extensions' => array('jpg jpeg gif png'),
 ),
);
}
// Write hook_theme() as mentioned below.
     
function hook_theme() {
  return array(
   'kali_preview_theme' => array(
   'render element' => 'element',
   'file' => 'kali.inc', // you can write code in separate file.
  )
 );
}

// Include below function as mentioned in kali.inc file or remove file include in hook_theme
and write below function in module file.
     
function theme_kali_preview_theme($variables) {
 $element = $variables['element'];
 $output = '';
 if($element['fid']['#value'] != 0 ) {
  $output .= '
'; $output .= theme('image_style', array('style_name' => 'thumbnail', 'path' => file_load($element['fid']['#value'])->uri, 'getsize' => FALSE)); $output .= drupal_render_children($element); $output .= '
'; } return $output; }

Some useful references:
-- Preview image after upload usinf FAPI.
-- Display uploaded image after upload.

Enable PHP OPcache in XAMPP windows

PHP 5.5.0 & later OPcache will be available by default.
Please add below code in php.ini to enable it.
 zend_extension = "C:\xampp\php\ext\php_opcache.dll"
 // Restart apache after enabled it.

opcache in xampp windows


Wednesday, November 4, 2015

Add group of fields using jquery or javascript

I had one requirement that adding some group of fields into some form.

Have used below set of HTML & jQuery codes.

Original posts: http://stackoverflow.com/questions/7232083/add-and-remove-group-of-textelements-dynamically-from-a-web-form-using-javascr

// HTML
Name Year Description
// jQuery
function checkRemove() {
    if ($('div.container').length == 1) {
        $('#remove').hide();
    } else {
        $('#remove').show();
    }
};
$(document).ready(function() {
    checkRemove()
    $('#add').click(function() {
        $('div.container:last').after($('div.container:first').clone());
        checkRemove();
    });
    $('#remove').click(function() {
        $('div.container:last').remove();
        checkRemove();
    });
});

Below code to attach remove button against each group.
$(document).ready(function() {
    var removeButton = "";
    $('#add').click(function() {
        $('div.container:last').after($('div.container:first').clone());
        $('div.container:last').append(removeButton);

    });
    $('#remove').live('click', function() {
        $(this).closest('div.container').remove();
    });
});

Tuesday, November 3, 2015

Drupal Queues

Using Drupal Queues, you can do so many bulk operation or batch process easily.

Shared some interesting links for further reading.

Original posts: http://rbayliss.net/drupal-queue-api

https://www.computerminds.co.uk/drupal-code/drupal-queues