Thứ Tư, 17 tháng 7, 2013

Custom Module in Drupal

**** http://drupalwithpankaj.blogspot.com/ 

http://drupalwithpankaj.blogspot.com/2013/01/custom-module-in-drupal.html

https://drupal.org/node/310075 

https://api.drupal.org/api/drupal/modules%21system%21theme.api.php/group/themeable/7 

 

Name your module

The first step in creating a module is to choose a "short name" for it. This short name will be used in all file and function names in your module, so it must start with a letter, and it must contain only lower-case letters and underscores. 
For this example, we'll choose "current_posts" as the short name. Important note: Be sure you follow these guidelines and do not use upper case letters in your module's short name, since it is used for both the module's file name and as a function prefix. 

When you implement Drupal "hooks" (see later portions of tutorial), Drupal will only recognize your hook implementation functions if they have the same function name prefix as the name of the module file.
It's also important to make sure your module does not have the same short name as any theme you will be using on the site.

 

Create a folder and a module file

Given that our choice of short name is "current_posts" :
  1. Start the module by creating a folder in your 

    Drupal installation at the path:
    • sites/all/modules/current_posts
  2. Create the PHP file for the module :
    • Save it as current_posts.module in the directory sites/all/modules/current_posts
    • As of Drupal 6.x, sites/all/modules is the 
      preferred place for non-core modules 
      (and sites/all/themes for non-core themes), 
      because this places all site-specific files in the 
      sites directory. This allows you to more easily 
      update the core files and modules without 
      erasing your customizations. Alternatively, if 
      you have a multi-site Drupal installation and 
      this module is for only one specific site, you 
      can put it in sites/your-site-folder/modules.
  3. Add an opening PHP tag to the module :
    • <?php
    • Module files begin with the opening PHP tag
      Do not place the CVS ID tag in your module. It
       is no longer needed with drupal.org's 
      conversion to Git. If the coder module gives 
      you error messages about it, then that module 
      has not yet been updated to drupal.org's Git 
      conventions.
The module is not operational yet: it hasn't been activated. We'll activate the module later in the tutorial.


Main topic described: .info files
All modules must have a 'modulename.info' file, which contains meta information about the module.
The general format is:
name = Module Name
description = A description of what your module does.
core = 7.x
For our module, we will replace 'Module Name' in the example above with the name of our module, 'Current Posts'. Without this file, the module will not show up in the module listing. Here is our specific example:
name = Current Posts
description = A block module that lists links to recent posts.
core = 7.x
Add the source above to a file named current_posts.info and save it into the module's directory at sites/all/modules/current_posts.
Note: If you copy and paste this code block, ensure that the description data does not contain a line break (turn off word-wrap on your text-editor to be sure). Otherwise, the .info file will not parse correctly.

.Info File Details

The details of what to put in a .info file can be found on the Writing .info files page.

 

Check

To make your module visible to Drupal create a 'modulename.module' file. For now it can simply be a text file that contains nothing but the opening <?php tag (with no closing tag). For our module this file will be named current_posts.module.
Your module should now appear in the module list in your site. Go to Modules and scroll down to the bottom of the list in the 'Other' category. You should see the module 'Current Posts'.

Comments in Drupal modules
It's always a good idea to document how your module works in comments. Drupal uses Doxygen to draw documentation from source code, so contrib modules on drupal.org follow strict comment guidelines. See Doxygen and comment formatting conventions for more details. Following these guidelines is beneficial to anyone looking at your code even if it's not strictly necessary for your situation.
Your first comment:
<?php/**
* @file
* A block module that displays recent blog and forum posts.
*/
?>
(Remember that the closing tag is included here for formatting reasons only and you should not include it in your real code.)
@file signifies that this comment pertains to the entire file. The doc block begins with a slash and two asterisks (/**) and ends with one asterisk and a slash (*/). Following Drupal guidelines, we will introduce each function in the module with such a comment.

Implementing your first hook

Hooks are fundamental to Drupal modules. They allow you to integrate your module into the actions of Drupal core. If you missed it, go back and read about hooks in Introduction to Drupal modules.
Your first hook is hook_help. This hook is recommended for inclusion in all contrib modules. hook_help provides help and additional information about the module to the user. To implement any hook in Drupal, replace "hook" in the hook name with your module's short name, and create a function in the .module file with that name. So, to implement hook_help() in our example module, we create a function called current_posts_help() in the current_posts.module file:
<?phpfunction current_posts_help($path, $arg) {

}
?>
The $path parameter provides context for the help: where in Drupal or the module the user is when they are accessing help. The recommended way to process this variable is with a switch statement. This code pattern is common in Drupal modules. Here is an abbreviated implementation of this function for your module, along with its doc block comment:


<?php/**
* Implements hook_help.
*
* Displays help and module information.
*
* @param path 
*   Which path of the site we're using to display help
* @param arg 
*   Array that holds the current path as returned from arg() function
*/
function current_posts_help($path, $arg) {
  switch (
$path) {
    case 
"admin/help#current_posts":
      return 
'<p>' . t("Displays links to nodes created on this date") . '</p>';
      break;
  }
}

(Note the closing ?> should not appear in your code.)

The admin/help#modulename case is used by Drupal core to link from the main help page (/admin/help or ?q=admin/help). You will eventually want to add more text to provide a better help message to the user; see Help text standard for the complete 
recommendation. The t()function that wraps the text marks it for translation. This function not only allows for translation, it can give your code an added layer of security. See Localization API for more information.

Check

Look again at the module list by clicking Modules on the Toolbar in your Drupal installation. Enable the module and click 'Save configuration'. Close and reopen the Modules page, find your module in the list, and you should see a link to 'Help' on the right. Click it to see the help text returned by current_posts_help

You can also follow the Help link in the toolbar (http://example.com/admin/help) and find your help link listed with the others on that page.
Disable your module and save ('Save configuration' button). Important: Be sure you follow that last step and disable your module and save, or new partial code in your module could break your site.




Drupal hook described: hook_block_info()


Modules are created to do all sorts of things: create blocks (abbreviated content that often appears on the right or left side of multiple pages), create special content types (for full page content - such as the content you are reading right now), track back-end information, and more. 

You may hear the term 'block modules' used to describe modules that primarily create block content (such as the menu module), or 'node modules' used to describe modules that primarily generate full page content (such as the blog and forum modules). At this stage, this module is a 'block module', because it generates a block.
In Drupal 7, there are at least eight block hooks. For the purposes of this module, we will use two of them. The first is hook_block_info(). As you might suspect, this hook tells Drupal what block(s) your module creates. We will use this hook to define a block that will eventually display the most recent posts. You can use a given hook exactly once in any module, so this hook must declare all blocks the module needs. For this module, a single block is all we need.
To use this hook to define our block, go to your current_posts.module file and create the functioncurrent_posts_block_info() as follows:
<?php/**
* Implements hook_block_info().
*/
function current_posts_block_info() {
  
$blocks['current_posts'] = array(
    
'info' => t('Current posts'), //The name that will appear in the block list.
    
'cache' => DRUPAL_CACHE_PER_ROLE, //Default
  
);
  return 
$blocks;
}
?>
(Remember not to include the closing ?> in your code.)
The doc block simply identifies the hook. For such a straightforward implementation, that is sufficient. Anyone reading the code can easily go to the API and call up the hook for further information.
The return value takes the form of an associative array. Pay special attention to this array structure, as it is Drupal's preferred programming structure. Arrays in PHP are well supported and very fast, and Drupal makes extensive use of them.
The only required value is 'info'. hook_block_info can also specify configuration settings. Here we set the cache to the default. See hook_block_info for a complete list of settings available.
Don't forget the final return statement.

Check

At this point, go to Modules, click the checkbox to enable Current Posts, and save your configuration. Next, navigate to Structure > Blocks. Scroll down to the bottom of the list. Among the disabled blocks, you should find the name, 'Current posts'. Return to Modules, disable your module and save. Important: Be sure you disable your module and save, or new partial code in your module could break your site.

Main topic described: Database API
Main function described: db_select()

Next we will create a custom function to retrieve the most recent posts. When a node is first created, the time of creation is stored in the database. We'll use this database field to find our data. We could include this code in the hook we will implement in the next tutorial page. Putting this section into a separate function keeps the code cleaner, easier to read and to maintain.
We will call the function current_posts_contents. We continue to follow the naming convention by beginning with the module short name. Then we use a descriptive word that is not a Drupal hook. The function begins with getting the time numbers. Here's the first part (without a closing brace because it's not the complete function):
<?php/**
* Custom content function. 
* 
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
* 
* @return 
*   A result set of the targeted posts.
*/
function current_posts_contents(){
  
//Get today's date.
  
$today = getdate();
  
//Calculate the date a week ago.
  
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
  
//Get all posts from one week ago to the present.
  
$end_time = time();?>
This code gets the current time, then calculates the time (in seconds since epoch start, seemktime for more information on time format) for midnight a week ago. These functions are straight PHP; you can look them up on the PHP website (php.net) for more details.
Next we use Drupal's Database API to retrieve our list of current nodes. This is the second part of the custom function:
<?php
  
//Use Database API to retrieve current posts.
  
$query = db_select('node', 'n')
    ->
fields('n', array('nid', 'title', 'created'))
    ->
condition('status', 1) //Published.
    
->condition('created', array($start_time, $end_time), 'BETWEEN')
    ->
orderBy('created', 'DESC') //Most recent first.
    
->execute(); 
  return 
$query 
}
?>


Built into Drupal is a very robust query builder, using a special object-oriented API. INSERT, UPDATE, and DELETE queries need this special care in order to behave consistently across all different databases. Although our SELECT query doesn't require this structure, this is a good opportunity to become familiar with it. You will see this structure used throughout Drupal.
  1. We build the query using the db_select method, 
    which takes a table name ('node') and alias ('n') 
    as arguments.
  2. The fields method uses the table assigned the 
    alias 'n' to select the fields listed in the array in 
    the second argument.
  3. The condition method takes three arguments. The 
    first is the field, the second the value, the third 
    the operator. If no operator is specified, as in 
    'status' above, = is assumed.
  4. The orderBy method sorts according to the field in 
    the first argument, in the order specified by the 
    second argument.
  5. The execute method compiles and runs the query
     and returns a result set/statement object.
Here's the complete function:
<?php/**
* Custom content function. 
* 
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
* 
* @return 
*   A result set of the targeted posts.
*/
function current_posts_contents(){
  
//Get today's date.
  
$today = getdate();
  
//Calculate the date a week ago.
  
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
  
//Get all posts from one week ago to the present.
  
$end_time = time();

  
//Use Database API to retrieve current posts.
  
$query = db_select('node', 'n')
    ->
fields('n', array('nid', 'title', 'created'))
    ->
condition('status', 1) //Published.
    
->condition('created', array($start_time, $end_time), 'BETWEEN')
    ->
orderBy('created', 'DESC') //Most recent first.
    
->execute(); 
  return 
$query 
}
?>
(Remember not to include the closing ?> in your code.)

See also



Drupal hook described: hook_block_view()
 
Main functions described: user_access(), l(), theme()



The next step in this tutorial is to take the data we generated in our custom function and turn it into content for the block. We will do this using hook_block_view

This function returns two values, 'subject', which is the title of the block, and 'content', which is self-documenting. Once again, we will use a switch structure. This structure allows for additional blocks to be added in the future if needed. The $delta parameter tells the function which block is being requested.

Access check

 

Here's the first part of the code:
<?phpfunction current_posts_block_view($delta = '') {
  switch(
$delta){
    case 
'current_posts':
      
$block['subject'] = t('Current posts');
      if(
user_access('access content')){
       
//Retrieve and process data here.
   
} ?>
Best practice dictates that information displayed to the user be assessed against that user's permissions. Here we implement the most basic of checks, 'access content'. You can use any permission here that Drupal supplies, or even create your own. For a list of permission names, go to People > List (tab) (or http://example.com/admin/people). 

In the permission dropdown there, you will find a list of the machine readable names that you can use in your code. This list will include all permissions active on your site, including those created by contrib modules. The names in the Permissions tab (http://example.com/admin/people/permissions) are not the machine readable names.
Another way to find permissions set in core modules is through the API reference. Enter the module name followed by _permission, for example, node_permission. You'll get a list of all the permissions that node defines. Knowing which one to use might be a bit tricky. For example, the access content permission we use here is actually defined in the node module, not the block module.

 

Coding the data as links

 

Here's the next bit of code:
<?php
       
//Use our custom function to retrieve data.
        
$result = current_posts_contents();
        
//Array to contain items for the block to render.
        
$items = array();
        
//Iterate over the resultset and format as links.
        
foreach ($result as $node){
          
$items[] = array(
            
'data' => l($node->title, 'node/' . $node->nid),
          );
  }
?>
First we use our custom function to save the data into the $result variable. The $items variable gives us a place to store the processed data. We then iterate over the resultset, processing each item and formatting it as a link.
Notice the actual link is created by the l() function. (That's a small case 'L'.) The first parameter sets the link text, in this case the node's title. The second parameter is the actual link path. The path to any node is always "node/#", where # is the ID number of the node. l() uses this path to generate appropriate links, adjusting the URL to the installation's URL configuration.

 

Theming the data

 

Drupal's presentation layer is a pluggable system known as the theme layer. Each theme can take control of most of Drupal's output, and has complete control over the CSS. Theming in Drupal is a vast subject with entire books devoted to the subject. Here we will merely touch the surface with a theme function. Later in the tutorial, we will delve into render arrays.
Here's the last section of code for current_posts_block_view:
<?php
     
        
if (empty($items)) { //No content in the last week.
          
$block['content'] = t('No posts available.');  
        } else {
          
//Pass data through theme function.
          
$block['content'] = theme('item_list', array(
            
'items' => $items));
        }
      }
    return 
$block;
  }

}
?>
First, we allow for the possibility of no content that fits our criteria. Your module's block should appear whether or not new content from the last week exists on your site.
If the $items variable contains data, it goes to the theme() function. The first argument of this function is the theme hook. Drupal includes many default theme hooks you can use with this function; see Default theme implementations for the complete list. We have chosen to theme our data as an unordered list, the theme_item_list theme hook. 

The second argument passes the content to be themed.
You may wonder why the code takes this form if the function is theme_item_listtheme() looks for a theme function called theme_hookname, where 'hookname' is the first argument, in this case,item_list. In other words, the second part of the hook name becomes the first argument when the function is called, telling the theme function which of its default versions to use.

 

The whole function

 

<?php/**
* Implements hook_block_view().
* 
* Prepares the contents of the block.
*/
function current_posts_block_view($delta = '') {
  switch(
$delta){
    case 
'current_posts':
      
$block['subject'] = t('Current posts');
      if(
user_access('access content')){
        
//Use our custom function to retrieve data.
        
$result = current_posts_contents();
        
//Array to contain items for the block to render.
        
$items = array();
        
//Iterate over the resultset and format as links.
        
foreach ($result as $node){
          
$items[] = array(
            
'data' => l($node->title, 'node/' . $node->nid),
          ); 
        }
      
        if (empty(
$items)) { //No content in the last week.
          
$block['content'] = t('No posts available.');  
        } 
        else {
          
//Pass data through theme function.
          
$block['content'] = theme('item_list', array(
            
'items' => $items));
        }
      }
    return 
$block;
  }
  
}
?>


(Remember not to include the opening or closing PHP tags when you add this section.)

See also


Enable the module
Go to Modules, or http://example.com/admin/modules, and scroll down to the bottom of the list in the 'Other' category. You should see the module 'Current posts.' Click the checkbox to enableCurrent posts, and save your configuration. Now you should see a link to Help beside the module name. Click it to see the help text you entered in current_posts_help.

Enable the block

 

Next, navigate to Structure > Blocks, or http://example.com/admin/structure/block. Scroll down to the bottom of the list. Among the disabled blocks, you should find the name, 'Current posts'. Set its location for one of the page regions and save. Navigate to another page like your homepage to see your block. Congratulations! You have written a working module.

 

Troubleshooting

If you get a "white screen" or a PHP error when you enable this module, it probably means you have a syntax error in your .module file. Be sure all your punctuation is correct, semi-colons, commas, etc. all in the right places, and that you have all the hook names and module short names spelled correctly. (In the case of a white screen, you may be able to find out what the PHP error was by looking in your Apache error log. Or you can try changing PHP's error reporting level.)
If you cannot find and fix the syntax error, nothing on your site will display, because Drupal will try to load your module on every page request. The easiest way to get your site working again is to delete the module's folder or move it out of the site, in which case Drupal will figure out that it shouldn't load this module after all, and your site should work again.

 

Clear caches

Drupal caches a lot of data, and if you are not seeing changes appear, that could be why. In this phase of the module, the caches shouldn't be an issue, but they will be as we proceed. To get all the troubleshooting instructions in one place, we'll give you the instructions here that you'll need later.
To clear the caches, go to Configuration > Performance or http://example.com/admin/config/development/performance, and click the Clear all cachesbutton.

Không có nhận xét nào:

Đăng nhận xét

Học lập trình web căn bản với PHP

Bài 1: Các kiến thức căn bản Part 1:  https://jimmyvan88.blogspot.com/2012/05/can-ban-lap-trinh-web-voi-php-bai-1-cac.html Part 2:  https://...