Wednesday, December 28, 2011

Using drush to get a list of enable modules

If you just wanted to make a list of all the modules which are installed in your instance. Don't waste time, be smart write a command using drush.

  1. List all modules and themes : drush pm-list
  2. List only modules : drush pm-list --type=Module
  3. List all modules except core modules : drush pm-list --type=Module --no core
  4. List all enabled modules except those from the core : drush pm-list --type=Module --no core -- status=enabled
  5. List all enabled modules except those from the core which belong to the CCK package : drush pm-list --type=Module --no core --package=CCK status=enabled
If you want more info about the pm-list
  1. drush help pm-list


Tuesday, October 4, 2011

Some frequently used commands in Ubuntu Linux for SQL and DRupal

MYSQL : 
To create a database, to create a user and then to give all the permissions on that database to the user.



create database my_database_name_to_be_created; 
create USER 'username_to_be_created'@'localhost' IDENTIFIED BY 'password';
GRANT ALL ON  my_database_name_to_be_created.* TO 'username_to_be_created'@'localhost' ;
FLUSH ALL PRIVILEGES;



Linux/ Mysql : 
To take a dump of the data base.

mysqldump -u root -p databased_to_be_dumped> dump_file_name.sql;


To create a new database
mysql -u root -p name_of_the_database_to_which_dump_is_loaded < dump_file_name.sql

Linux : 

find . -maxdepth 1 -exec mv {} .. \;

Monday, July 4, 2011

How to remove few formatting options from CK editor.

  • Download and install CK editor.
  • Make sure that you have given the permissions.
  • Associate the roles with the CK editor profiles.
  • Now edit the appropriate profile. For example if you want to edit the CK editor for the authenticated user then you will have to edit the Advanced profile editor.


  • Click open the "Advanced Options" fieldset.





And copy paste the following code so that it looks like the image on the right.
format_tags = 'p;pre;h4;h5;h6'
removeFormatTags = 'b;big;code;del;dfn;em;font;i;ins;kbd;q;samp;small;span;strike;strong;sub;sup;tt;u;var;h1;h2;h3' 




How to make titles optional and generate title from body text

Head to automatic nodetitles , download and install the module.

Goto /admin/content/node-type/entry under the "Automatic title generation" field set select the second or third option and paste the code below.

//the least number of words in a scentence when trying to extract a complete scentence
$w_sentence= 1;
//if the scentence obtained contains more words than this it will be truncated to this many words and "..."
$w_wordnum = 10;
//if the number of characters after all truncation is above this number it will be truncated to this many characters and "...",  This is to protect agains extremely long words
$w_maxchar = 50;

// this is the name of the cck node token you want to use for example"
$bodyfield = '[field_sms_text-formatted]';


function summarize($paragraph, $limit)
    // cuts the 
       {
           $tok = strtok($paragraph, " ");
           while($tok)
           {
               $text .= " $tok";
               $words++;
               if(($words >= $limit) && ((substr($tok, -1) == "!")||(substr($tok, -1) == ".")))
                   break;
               $tok = strtok(" ");
           }
           
           return ltrim($text);
       }

function shorten_string($string, $wordsreturned)
     /*  Returns the first $wordsreturned out of $string.  If string
    contains more words than $wordsreturned, the entire string
    is returned.
    */
    {
    $retval = $string;    //    Just in case of a problem
    $array = explode(" ", $string);
    if (count($array)<=$wordsreturned)
    /*  Already short enough, return the whole thing
        */
        {
        $retval = $string;
        }
    else
    /*  Need to chop of some words
        */
        {
        array_splice($array, $wordsreturned);
        $retval = implode(" ", $array)."...";
        }
    return $retval;
    }     

// if somone managed to put in html we have to clean it out
$bodyfield = strip_tags($bodyfield);    

// multiple spaces in my editor were correctly converted to hardspaces but it confuses drupal so we need to remove them
$bodyfield = str_replace(' ', " ", $bodyfield);
$bodyfield = trim($bodyfield);


$bodyfield = summarize($bodyfield, $w_sentence);
$bodyfield = shorten_string($bodyfield, $w_wordnum);

// to protect agains extremely long words we also have a character based rule
if(strlen($bodyfield) > $w_maxchar )
    {
    $bodyfield = substr($bodyfield,0,$w_maxchar)."...";
    }
    
print check_plain($bodyfield);
    

Monday, June 20, 2011

Drupal Taleo Integration with SOAPClient

Taleo is a Talent Management System. Many companies use Taleo for the recruitment services. Taleo has an API which can be used to make API calls to fetch data from the Taleo servers. Though there is documentation about the Taleo integration, it is confusing at places and misleading at some.

The following code helps us to fetch job titles and location from the Taleo server. The explanation of each block of code follows next.

try {
  $client = new SoapClient("http://tbe.taleo.net/wsdl/DispatcherAPI.wsdl", array('trace' => true)); 
  $url = $client->__call('getURL', $company_name);
  $clientTaleo = new SoapClient("http://tbe.taleo.net/wsdl/WebAPI.wsdl", array('trace' => true));
  $clientTaleo->__setLocation($url);
  $params = array(
             'in0' => $comp_name,
             'in1' => $user_name,
             'in2' => $password,
  );
  $session =  $clientTaleo->__call('login', $params);
  $params = array(
           'in0' => $session,
           'in1' => array('status' => 'Filled', 'city' => 'Bothell',)
          );
  $jobIds =  $clientTaleo->__call('searchRequisition', $params);
            foreach($jobIds->array->item as $jobid){
              $params = array(
                'in0' => $session,
                'in1' => $jobid->id,
                );

                $job = $clientTaleo->__call('getRequisitionById', $params);
                print $job->title . '  ' . $job->location;
            }  
  
            
} catch (SoapFault $fault) {
            $error = 1;
            print("
            
'Sorry, blah returned the following ERROR: ".$fault->faultcode."-".$fault->faultstring
            );
} 


You need to follow a three step procedure to get any meaningful data from taleo.

1) Access a fixed url to get a local-url for your company : Based on your location you get different urls. This is done for load balancing.
$client = new SoapClient("http://tbe.taleo.net/wsdl/DispatcherAPI.wsdl", array('trace' => true)); 
 $url = $client->__call('getURL', $company_name);

Gives you a url like : https://tbe.taleo.net/NA7/ats/services/rpcrouter
2) Authenticate via the url retrieved from first step to get a session token : This session token changes on every request you make.
$clientTaleo = new SoapClient("http://tbe.taleo.net/wsdl/WebAPI.wsdl", array('trace' => true));
  $clientTaleo->__setLocation($url);
  $params = array(
             'in0' => $comp_name,
             'in1' => $user_name,
             'in2' => $password,
  );
  $session =  $clientTaleo->__call('login', $params);  

3) Use the session token from the second step to invoke the various Taleo API methods.
$params = array(
            'in0' => $session,
            'in1' => $jobid_id,
          );

$job = $clientTaleo->__call('getRequisitionById', $params);
print $job->title . '  ' . $job->location;

Saturday, June 18, 2011

Update query with joins

I had comfortable assumed that we cannot use joins in MySQL along with the update query. But recently I realized that we can use joins with UPDATE query.  Not only does it make your query simple and meaningful but it also saves you the pain of understanding what the ERROR 1093 (HY000): You can't specify target table 'files' for update in FROM clause means.

You would get the above error if you tried to run the query

UPDATE files f set f.filename = REPLACE(filename,'jpg','jpeg') 
WHERE f.fid IN 
 (SELECT f.fid from files f 
    JOIN content_type_test ctt 
      ON ctt.field_test_fid = f.fid 
    JOIN node n 
      ON (ctt.nid = n.nid and n.type ='content_type_test')
  );


Instead reframe the query as
UPDATE files f 
JOIN content_type_test ctt 
  ON ctt.field_test_fid = f.fid 
JOIN node n 
  ON (ctt.nid = n.nid AND and n.type = 'content_type_test')
SET filename = REPLACE(filename,'jpg','jpeg');

Friday, June 17, 2011

Adding a new display option in the view


To create a formatter option like the ones provided by CCK editor you need to follow the following steps. For those of you who don't know what a formatter is take a look at the following images. If you go to display option in any content type "admin/content/node-type/test-content-type/display" you can find these options. These are the same options that appear when selecting a formatter in the views when you are displaying field from content(CCK) group.

For this example I have taken link module. Link module has the following seven options by default. I will be adding a new option "File with Icon", which will make the file appear link a download link along with the icon. To begin with we will have these.










The first thing that we have got to do is implement hook_field_formatter_info. The values passed are what should the label for this formatter be, this format will apply to which field types and how do we handle the multiple values. The key in the array that we are passing is "file". This is important as the other functions we will write are dependent on this.

function mymodule_field_formatter_info() {
  return array(
    'file' => array(
      'label' => t('File with icon'),
      'field types' => array('link'),
      'multiple values' => CONTENT_HANDLE_CORE,
      ),
  );
}

Now since the key is "link", CCK will look out for a function that begins with theme_[modulename] and ends with formatter_file. So first let us write an entry for that in our implementation of hook_theme.

function mymodule_theme() {
  return array(
    'mymodule_formatter_file' => array(
      'arguments' => array('element' => NULL),
     ),
  );
}

The theme function that returns the formatted field.

function theme_mymodule_formatter_file($element = NULL) {
  global $base_path,$base_url;
  $icon_path =  drupal_get_path('module', 'filefield') . '/icons/' . get_file_type($element['#item']['url']);
  $output = theme_image($icon_path);
  $output .= l($element['#item']['title'],$element['#item']['url'],array('attributes' => array('target' => '_blank')));
  return $output;
}

Now that we have done all the necessary changes, the much awaited output will look like this


Force download on clicking a link in Drupal

Forcing a file download when the user clicks on a link is pretty simple in Drupal.Few things you must already know
  • The files are generally stored in site/default/files folder. 
  • The data regarding the uploaded files are stored in files table in DB.
  • Every file has a unique fid.

All our downloads will happen through a single link. Our link will look like this
Download Image

Let us create a menu entry for our path "download/image". Lets pass the second argument to our function download_image() . This argument will be the unique fid.

$items['download/image/%'] = array(
    'title' => t('Download Images'),
    'page callback' => 'download_image',
    'page arguments' => array(2),
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK, 
    );

Our funciton download_image() that will actually force the file to be downloaded, rather than opening in a the brower. We accept fid as the argument to the function. We query the DB table for the filepath of the image based on the fid and we also make sure that it is an image as we don't want users to download other content types. Then we set the headers and make content dispostion as attachement(this is what forced the file to be downloaded) and then read the file from the path.

function download_image($fid) {
  global $user, $base_path, $base_url;
  if ($fid) {
    $query = db_query("SELECT filepath, filename FROM {files} WHERE fid = %d and filemime like '%image%' ", $fid);
    while ($files_data = db_fetch_array($query)) {
      $filepath = $base_url . "/" . $files_data['filepath'];
      $filename = $files_data['filename'];
        header("Content-Disposition: attachment; filename = $filename");
        readfile($filepath);
        exit();
    }
    drupal_set_message(t('You are not authorised to download this file'));
    drupal_goto();
  }  
}

Get the node ids in the current view as a CSV

function get_current_view_results_as_csv($position_only = false, $nid = 0) {
  $view = views_get_current_view();
  $result_nids = array();
  foreach($view->result as $row_id => $row){
    $result_nids[] = $row->nid;
  }
  if($position_only){
    return array_search($nid, $result_nids);
  }else{
    return implode(',', $result_nids);
  }
}


The above function will give you the result node ids in the current view as a CSV list. If $position_only = TRUE then you need to pass the nid and the functiton will return the position of the given nodeid in the current view results.

Printing a date range

Recently I had this scenario where the client wanted the whole date range to be displayed instead of just the first and last date. So instead of June 6 - June 10 then wanted it to be displayed as June 6, 7, 8, 9, 10. Seems to be simple at first right? What if the range is July 30 - August 1? Then it has to be July 30, 31, August 1. What if it is December 31 to January 2. Then it has to be December 31, 2012 January 1, 2,

So I wrote this nifty function which does the job.

function get_date_range($date1, $date2){
  $start = date( 'Y-m-d', strtotime($date1) );
  $end = date( 'Y-m-d', strtotime($date2) );
  $current = $start;
  $range_string = '';
  while( (strtotime($end)-strtotime($current)) >= 0 ){
    $current_month = date( 'F', strtotime($current));
    $current_year = date( 'Y', strtotime($current));
    if($range_string && $current_year != $previous_year){
      $range_string .= $current_year . ' ';
    }
    if($current_month != $previous_month){
      $range_string .= $current_month . ' ';
    }
    $range_string .= date( 'd', strtotime($current));
    if($current != $end){
      $range_string .=  ', ';      
    }
    $previous_month = $current_month;
    $previous_year = $current_year;
    $current = date( 'Y-m-d', strtotime($current) + 86400);
  }
  
  return $range_string;
}



So if the inputs are
$date1 = 2011-07-28T04:00:00
$date2 = 2011-08-02T04:00:00

$output = "July 28, 29, 30, 31 August 01, 02"

Tuesday, May 31, 2011

Embedding a View using code

$view = views_get_view('my_view_name','display_delta');
$view = views_get_view('my_view_name','display_delta');
$view->render();
if ($view->result)
  {
    $view_contents = views_embed_view('my_view_name','display_delta');
    $title = $view->display['display_delta']->display_options['title'];
    $output.= "

$title

"; $output.= $view_contents; $output.= "
"; }

Do remember
  1. views_get_view gives you the view object.
  2. view->render();
    is a function to render the view so that you get the result of the view and other values.
  3. Once view->render() is executed, you can get the result from view->result;
  4. views_embed_view embeds the html output of the view.
  5. views_embed_view doesn't give you the title of the view.
  6. To get the title of a view for a particular display use
    $view->display['display_delta']->display_options['title'];