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.