Sunday, March 31, 2013

Display current Git branch in bash prompt

View updated version of this blog here.

While working on a project I maintain multiple branches for development. I keep at least two branches, master (the default one) and develop. I work on develop branch and when I complete certain task I merge the work with master branch and push code to the repository. That's how I work :)

At times I forget on which branch I am working, I have to run:

git branch

to know the current branch. I am a bit lazy and I find running the same command again and again annoying. So I thought why not display the current branch in the command prompt. I did google search and found several results. This post is the result of those multiple search results.

Edit .bashrc file. Run the following command to edit .bashrc file

vim ~/.bashrc

You can replace vim with your favourite editor.

At the end of file enter the following piece of code:

# Append current git branch in prompt

parse_git_branch() {

  if ! git rev-parse --git-dir > /dev/null 2>&1; then

    return 0

  fi



  git_branch=$(git branch 2>/dev/null| sed -n '/^\*/s/^\* //p')



  echo "[$git_branch]"

}

PS1="${debian_chroot:+($debian_chroot)}\[\033[01;36m\]\u@\h\[\033[00m\]:\[\033[01;32m\]\w\[\033[00m\]\[\033[01;31m\]\$(parse_git_branch)\[\033[00m\]$ "

My bash prompt
My bash prompt
Cool.. eh? :)

PS1 is used to change the bash command prompt.

Inside the PS1 variable you can see I have given certain codes like 01;32, 01;31, etc. These are color codes for bash prompt. A list of colors are available here.

References:

Friday, March 15, 2013

How to use vim for Drupal development

View updated version of this blog here.

I am a Linux user, and a drupal developer too. Its been months I am using vim for writing custom drupal modules. Before it was eclipse, eclipse was good but I was having issues because of two reasons. First, I was working on a big project with lots of custom modules and huge database. Loading a module in eclipse editor took several minutes and secondly, my computer is a bit old Intel Core 2 Duo processor and 2GB RAM and . I have always heard being vim as one of the most powerful editors, but I realized it that time when I switched to vim for writing or just reading the code of custom modules.

Like everyone I googled for the vim support for drupal. The web pages that helped me most are these:
Non Linux users can also download and use vim, especially Windows users.

One of the recommended way to install required vim plugins for drupal development is to install them using drush. I had also installed vim plugins in this way. After installing drush, check drush version. Command to check drush version:

drush --version

If drush version is 5.8 then it is okay. Otherwise you need to upgrade drush.

After updating drush, install required vim plugins using the following commands:

drush @none dl vimrc
drush help vimrc-install
drush -v vimrc-install <options>

The first command will dowload the vimrc project. The second commad will show you the options for installing vim plugins.

But I installed it without using any options. I just did this:

drush -v vimrc-install

This will install certain vim plugins that will turn your simple vim to cooool vim. Absolutely ready for writing custom module. But you also need to configure certain vim settings so as to make it more developer friendly. I am providing my vim settings. Beginners can copy the settings, advanced users who knows tweaks and tricks of vim settings can make changes as they desire.


These are default vim settings that are loaded when you open vim. Vim global settings can be done from /usr/share/vim/vimrc while vim local settings can be done from ~/.vimrc. Vim global settings means that the vim settings will be available to all users of your system, while vim local settings are available for the particular logged in user. The file path I have given above are for Ubuntu, so Ubuntu users no worries. Sorry, for non Ubuntu Linux users you have to find it yourself.

Also it is recommended that you set color for your terminal. This will make the code more color distinguishable and easy to understand. Just edit ~/.bashrc and add the following line at the end:

export TERM="xterm-256color"

And do not forget to restart terminal after you have done this.

Now I am going to show you some amazing vim commands (available from plugins you installed earlier of course) that will seriously change your experience of custom module work in Drupal.

NERDTree
NERDTree

TagbarOpen
TagbarOpen

NERDCommeter
Command: NUMBER-OF-LINES/ci

NERDCommenter
Command: NUMBER-OF-LINES/ci

Frequently used shotcuts:
daw - Delete word under cursor
caw - Delete word under cursor and go to insert mode
d$ - Delete from under the cursor till end of line
c$ - Delete from under the cursor till end of line and go to insert mode
START-LINE-NUMBER,END-LINE-NUMBER"+y - Copy lines to system clipboard
gg"+yG - Copy all file content to system clipboard
CtrlXO - Autocomplete

Frequently used commands:
%s/TEXT-TO-SEARCH/TEXT-TO-REPLACE/gc - Interactive find and replace

View documentation of a Drupal function:
Bring the cursor at the start or under the function whose documentation you want to see. Then do:
<Leader>da - To view the documenation in drupal.org OR
<Leader>dc - To view the documentattion in drupalcontrib.org
The most wonderful thing I like about this is, it will automatically identify the core version from the module's info file. Suppose you are working on a 6.x core version module then it will show the documenation of the 6.x version. Cooollll, Right?

More information:
Drupal vimrc installs the following plugins:
pathogen - This plugin helps to manage your other vim plugins
nerdcommenter - This plugins helps you to comment out line of codes
nerdtree - This plugin acts like file explorer in eclipse where you can easily navigate through files in current directory
snipmate - This plugin provides code snippets. Drupal vimrc later adds its own module snippets in it
syntastic - This plugin provides syntax checking. Before writing to any file it will check syntax. Do not write and quit at the same time otherwise it will not be able to show errors, if any
tagbar - This plugin displays a list of functions and variables declared in the file
fugitive - Git wrapper

Other than this I installed another plugin:
SearchParty - This plugin provides color highlighting during text search
colorschemes -  A set of vim colorscheme

Update:
See a collection of vim plugins and settings for Drupal development in Use Vim as IDE for Drupal development, also see them in action.

Saturday, March 9, 2013

Dynamic loading of select list using AJAX

View updated version of this blog here.

Dynamic loading of select lists in drupal can be easily done using Drupal form API. I had to implement  dynamic select lists in several of my projects, I googled for some direct answer but did not find any. The answer was rather split among several sites or blogs. Hence, I am writing this blog so that you can find all the required code in one single place.

I will create a form using form API where there will be two select lists. The value of the second(lets say it as child list) will be dependent on the selected value of first list(lets say it as parent list). The changing of the value of child list will be dynamic and done using AJAX.

/**
 * @file
 * dynamic_select_list.module.
 */

/**
 * Implements hook_menu().
 */
function blogs_dynamic_list_menu() {
  $items = array();

  // Put your menu items here.
  $items['blogs/dynamic-list'] = array(
    'title' => 'Dynamic lists',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('blogs_dynamic_list_render_select_list'),
    'access callback' => TRUE,
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

function blogs_dynamic_list_render_select_list($form, &$form_state) {
  $animal_category = array(
    'none' => t('-- None --'),
    'mammal' => t('Mammal'),
    'reptile' => t('Reptile'),
    'aves' => t('Aves'),
    'amphibia' => t('Amphibia'),
  );

  $mammal = array(
    'tiger' => t('Tiger'),
    'cat' => t('Cat'),
    'zebra' => t('Zebra'),
    'panda' => t('Panda'),
    'squirrel' => t('Squirrel'),
  );

  $reptile = array(
    'snake' => t('Snake'),
    'crocodile' => t('Crocodile'),
    'turtle' => t('Turtle'),
    'lizard' => t('Lizard'),
  );

  $aves = array(
    'parrot' => t('Parrot'),
    'eagle' => t('Eagle'),
    'owl' => t('Owl'),
    'peacock' => t('Peacock'),
  );

  $amphibia = array(
    'frog' => t('Frog'),
    'salamander' => t('Salamander'),
  );

  // Check the value of parent select list and populate the value of child
  // select list according to that.
  $default = !empty($form_state['values']['parent_select_list']) ? $form_state['values']['parent_select_list'] : 'none';

  switch ($default) {
    case 'mammal':
      $child_select_options = $mammal;
      break;

    case 'reptile':
      $child_select_options = $reptile;
      break;

    case 'aves':
      $child_select_options = $aves;
      break;

    case 'amphibia':
      $child_select_options = $amphibia;
      break;

    case 'none':
      $child_select_options = array('none' => '-- None --');
      break;
  }

  // Parent select list.
  $form['parent_select_list'] = array(
    '#type' => 'select',
    '#title' => t('Select animal category'),
    '#options' => $animal_category,
    '#default_value' => $animal_category['none'],
    '#description' => t('Select animal class'),
    '#ajax' => array(
      'callback' => 'blog_dynamic_list_select_list_ajax_callback',
      'wrapper' => 'child-select-list-wrapper',
      'event' => 'change',
    ),
  );

  // Child select list.
  $form['child_select_list'] = array(
    '#prefix' => '<div id="child-select-list-wrapper">',
    '#type' => 'select',
    '#title' => t('Select animal'),
    '#options' => $child_select_options,
    '#description' => t('Select animal'),
    '#suffix' => '</div>',
  );

  return $form;
}

/**
 * AJAX callback.
 */
function blog_dynamic_list_select_list_ajax_callback($form, &$form_state) {
  return $form['child_select_list'];
}

The above code will register a menu item where you can view the form. The form has two select lists, the parent list allows to select a class of animals, and the child list will dynamically show the animals that falls under that class.

I am going to give another example, the following example is more manageable than the previous one. Instead of loading the values of select lists from array, we will load the values from taxonomy.

Create a vocabulary called animals and specify the terms like this:



Now we will load the parent taxonomy terms in the parent select list and their respective child terms in the child select list.
/**
 * @file
 * blogs_dynamic_list_terms.module.
 */

/**
 * Implements hook_menu().
 */
function blogs_dynamic_list_terms_menu() {
  $items = array();

  // Put your menu items here.
  $items['blogs/dynamic-list-terms'] = array(
    'title' => 'Dynamic lists terms',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('blogs_dynamic_list_terms_render_select_list'),
    'access callback' => TRUE,
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

function blogs_dynamic_list_terms_render_select_list($form, &$form_state) {
  // Load the vocabulary. Instead of 'taxonomy_animals' you have to give the
  // machine name of your vocabulary.
  $vocabulary = taxonomy_vocabulary_machine_name_load('taxonomy_animals');

  // Load all the parent terms of the vocabulary.
  // The second parameter 0 means that we wish to generate the whole tree.
  // The third parameter 1 means that we wish to see only the parent terms.
  // Default is 0.
  $parent_terms = taxonomy_get_tree($vocabulary->vid, 0, 1);

  $animal_category = array('none' => '-- None --');
  // Build the parent select list values.
  foreach ($parent_terms as $parent) {
    $animal_category[$parent->tid] = $parent->name;
  }

  // Check the value of parent select list and populate the value of child
  // select list according to that.
  $default = !empty($form_state['values']['parent_select_list']) ? $form_state['values']['parent_select_list'] : 'none';

  if ($default != 'none') {
    // Load all the child terms of the selected parent item.
    // The second parameter tells to load the tree based on the parent term ID.
    // We are ignoring the third parameter since we know that the vocabulary has
    // only two levels.
    $child_terms = taxonomy_get_tree($vocabulary->vid, $default);
    // Build the child select list values.
    foreach ($child_terms as $child) {
      $child_select_options[$child->tid] = $child->name;
    }
  }
  else {
    // No value selected in parent selct list.
    $child_select_options = array('none' => '-- None --');
  }

  // Parent select list.
  $form['parent_select_list'] = array(
    '#type' => 'select',
    '#title' => t('Select animal category'),
    '#options' => $animal_category,
    '#default_value' => $animal_category['none'],
    '#description' => t('Select animal class'),
    '#ajax' => array(
      'callback' => 'blogs_dynamic_list_terms_select_list_ajax_callback',
      'wrapper' => 'child-select-list-wrapper',
      'event' => 'change',
    ),
  );

  // Child select list.
  $form['child_select_list'] = array(
    '#prefix' => '<div id="child-select-list-wrapper">',
    '#type' => 'select',
    '#title' => t('Select animal'),
    '#options' => $child_select_options,
    '#description' => t('Select animal'),
    '#suffix' => '</div>',
  );

  return $form;
}

/**
 * AJAX callback.
 */
function blogs_dynamic_list_terms_select_list_ajax_callback($form, &$form_state) {
  return $form['child_select_list'];
}

See how much the code has shortened. And also it is more manageable, you can easily add or remove parent and child terms in future.
Also you may like to see AJAX Forms in Drupal 7 for more information

Monday, March 4, 2013

Drupal Features

View updated version of this blog here.

In Drupal you will sometimes need to export your database settings to another Drupal installation. For example, you have created a content type and you want to create that same content type in another Drupal installation with few clicks. Without going over the process of creating the content type and adding fields again, you can use features module.

How a feature works?
Features lets you to add components in it, a feature component can be anything, it can be a content type, CCK fields, views, etc. After adding components features module will create a custom module on the fly. On enabling that module on another Drupal installation it will create the components that you had added in the feature. In brief, a feature contains the database settings within code i.e. a custom module.

How to manage a feature?
You have created a feature and it has a component say, a view. Now you have made some changes in that view and you want that the changes should also be reflected in the feature. In this case, you have to update that feature. On updating a feature, any later database changes of the component gets into the feature code.

Suppose you have made some wrong changes in the view and messed up everything. Now you want that view's earlier settings, in this case you have to revert the feature component(in this case a view). On reverting a feature you mean that you want that the component should follow the settings as described in the feature code, this overrides any new database settings for the component.

Suppose you are adding a new component to the feature, say another view. In this case reverting or updating a feature will not do, since the component is not yet a part of the feature. You have to re-create the feature and add the new component manually.

Possible status of a feature
A feature status can be seen beside the name of the feature in the feature's admin page. So far I have seen five status that a feature can have:

  • Disabled - the feature is disabled
  • Default - it means that the settings described in the feature code and the feature component's database settings are same
  • Overridden - it means that the settings described in the feature code and the feature component's database settings are not same
  • Needs review - it means that you have added some new components in a feature that are not yet reviewed
  • Conflict - it means that duplicate components are added in more than one feature
Possible scenarios of feature status
You have created a content type and added that content type as a component in feature. You have not enabled that feature. In this case the feature status will be disabled.
Now you have enabled that feature, the feature status will be default.
Suppose you have changed the widget of a field that was in the content type. The feature status will be overridden, because the settings described in code does not match the database settings. In this case you either have to update your feature i.e. bring the database settings in the feature code, or revert your feature i.e. change the field widget as it was before.

You have added a new field to the content type, and have re-created the feature. You have copied the feature module to another Drupal instance which has that feature already enabled(content type created using feature but without that new field), in that Drupal instance the feature status will be needs review. On marking the components as mark as reviewed you mean that you are allowing the new components.

Suppose you have created another feature and has added a component say a field that is already added in some another feature. The status of both feature will be conflict with the feature name with which the feature conflicts. In this case you have to remove the component from either one of the feature.

Some things you cannot do using feature
Remember that you can only export your Drupal database settings using a feature, you cannot export a node or taxonomy terms using feature. There are other modules in Drupal that serves this purpose. Node export can be used for node export/import, taxonomy CSV import/export for taxonomy terms import/export.

You cannot delete a database setting using feature. Suppose you have created a feature with content type as a component, the feature has four fields. You copied the feature module in another Drupal instance and enabled it there. Now you do not want one of the fields and you delete it from the content type. Although the code for creating the field in the feature will be deleted(after updating the feature ofcourse), but since you have already the feature enabled in another Drupal instance, the unwanted field will not be deleted there. You have to manually delete it.

Integration with drush
One of the most exciting that I like about feature is that it is integrated with drush. That means you can easily create or manage a feature from command line. Some drush command that I frequently use for managing features are:

drush fu FEATURE_NAME
update feature

drush fr FEATURE_NAME
revert feature