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