Programmically Creating Roles

I recently wrote a module that required certain roles to be created. My goal was to be able to drop the module in and go, so develop module, install module on live site, and boom goes the dynamite.

The first thing I did was create the function to create the roles:

 

function _create_roles() {
	$existing_roles = user_roles();
	$new_roles = array('VP of Finance & CFO', 'Finance', 'Senior Vice President and Academic Dean', 'Academic Programs', 'President and CEO', 'President\'s Office', 'Human Resources', 'Supervisor');
	$roles = array();
	
	foreach($new_roles as $new_role) {
		if(array_search($new_role, $existing_roles) == FALSE) {
			$roles[] = $new_role;
		}
	}
	
	foreach($roles as $role) {
			db_query('INSERT INTO {role}(name) VALUES(\'%s\')', $role);
	}
}

The only thing I need to do is inject the roles into the database. However, it's best to make sure that I am not adding duplicate roles. On the first line inside the function, I am calling user_roles() which gets an array of all the currently defined roles in the system. I then create an array of roles I wish to add to the system which I iterate through by making sure that each role I want to add does not exist the array of existing roles. Roles that are not in the $existing_roles array gets added to another array which is then iterated through and a query is executed based on each element.

Creating Content Types Programmically

There are two ways to create content types in Drupal. The first is using hook_node_info in your module. When using this method, this only creates a content type with a title and a body (providing you implement the hook_form() function.)

 

function blog_node_info() {
  return array(
    'blog' => array(
      'name' => t('Blog entry'),
      'module' => 'blog',
      'description' => t('A blog entry is a single post to an online journal, or blog.'),
      'has_title' => TRUE,
      'has_body' => TRUE,
    )
  );
}

function blog_form($node, $form_state) {
    return node_content_form($node, $form_state);
}

The other way is to programmically recreate a content type by exporting the content type with the Content Copy module. For example, you're working on module that relies on content type that you created along with a number of CCK fields. The first step in this method is to enable the Content Copy module.  Once the module is enabled head over to admin/content/types/export to select the content type you wish to export. The export will be an array so you can use it in a module.

 

$content['type']  = array (
  'name' => 'Membership',
  'type' => 'product',
  'description' => 'This node displays the representation of a membership for sale on the website. ',
  'title_label' => 'Name',
  'body_label' => 'Description',
  'min_word_count' => '0',
  'help' => '',
  'node_options' => 
  array (
    'status' => true,
    'revision' => true,
    'promote' => false,
    'sticky' => false,
  ),
  'old_type' => 'product',
  'orig_type' => 'product',
  'module' => 'uc_product',
  'custom' => '0',
  'modified' => '1',
  'locked' => '1',
  'reset' => 'Reset to defaults',
  'uc_product_shippable' => 0,
  'uc_image' => '',
  'comment' => '0',
  'comment_default_mode' => '4',
  'comment_default_order' => '1',
  'comment_default_per_page' => '50',
  'comment_controls' => '3',
  'comment_anonymous' => 0,
  'comment_subject_field' => '1',
  'comment_preview' => '1',
  'comment_form_location' => '0',
);
$content['fields']  = array (
  0 => 
  array (
    'label' => 'Image',
    'field_name' => 'field_image',
    'type' => 'filefield',
    'widget_type' => 'imagefield_widget',
    'change' => 'Change basic information',
    'weight' => '31',
    'file_extensions' => 'png gif jpg jpeg',
    'progress_indicator' => 'bar',
    'file_path' => '',
    'max_filesize_per_file' => '',
    'max_filesize_per_node' => '',
    'max_resolution' => 0,
    'min_resolution' => 0,
    'custom_alt' => 0,
    'alt' => '',
    'custom_title' => 0,
    'title_type' => 'textfield',
    'title' => '',
    'use_default_image' => 0,
    'default_image_upload' => '',
    'default_image' => NULL,
    'description' => '',
    'required' => 0,
    'multiple' => '1',
    'list_field' => '0',
    'list_default' => 1,
    'description_field' => '0',
    'op' => 'Save field settings',
    'module' => 'filefield',
    'widget_module' => 'imagefield',
    'columns' => 
    array (
      'fid' => 
      array (
        'type' => 'int',
        'not null' => false,
        'views' => true,
      ),
      'list' => 
      array (
        'type' => 'int',
        'size' => 'tiny',
        'not null' => false,
        'views' => true,
      ),
      'data' => 
      array (
        'type' => 'text',
        'serialize' => true,
        'views' => true,
      ),
    ),
    'display_settings' => 
    array (
      'label' => 
      array (
        'format' => 'above',
        'exclude' => 0,
      ),
      'teaser' => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'full' => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      4 => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'token' => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
    ),
  ),
);
$content['extra']  = array (
  'title' => '-5',
  'body_field' => '-4',
  'revision_information' => '20',
  'author' => '20',
  'options' => '25',
  'comment_settings' => '30',
  'menu' => '0',
  'path' => '30',
  'shipping' => '0',
  'base' => '-1',
  'body' => '1',
);

In a hook_install or hook_enable function, and after making sure the content type doesn't already exist, you would do the following:

 

module_load_include('inc', 'content', 'includes/content.crud');

$content['type']  = array (
  'name' => 'Membership',
  'type' => 'product',
  'description' => 'This node displays the representation of a membership for sale on the website. ',
  'title_label' => 'Name',
  'body_label' => 'Description',
  'min_word_count' => '0',
  'help' => '',
  'node_options' => 
  array (
    'status' => true,
    'revision' => true,
    'promote' => false,
    'sticky' => false,
  ),
  'old_type' => 'product',
  'orig_type' => 'product',
  'module' => 'uc_product',
  'custom' => '0',
  'modified' => '1',
  'locked' => '1',
  'reset' => 'Reset to defaults',
  'uc_product_shippable' => 0,
  'uc_image' => '',
  'comment' => '0',
  'comment_default_mode' => '4',
  'comment_default_order' => '1',
  'comment_default_per_page' => '50',
  'comment_controls' => '3',
  'comment_anonymous' => 0,
  'comment_subject_field' => '1',
  'comment_preview' => '1',
  'comment_form_location' => '0',
);
$content['fields']  = array (
  0 => 
  array (
    'label' => 'Image',
    'field_name' => 'field_image',
    'type' => 'filefield',
    'widget_type' => 'imagefield_widget',
    'change' => 'Change basic information',
    'weight' => '31',
    'file_extensions' => 'png gif jpg jpeg',
    'progress_indicator' => 'bar',
    'file_path' => '',
    'max_filesize_per_file' => '',
    'max_filesize_per_node' => '',
    'max_resolution' => 0,
    'min_resolution' => 0,
    'custom_alt' => 0,
    'alt' => '',
    'custom_title' => 0,
    'title_type' => 'textfield',
    'title' => '',
    'use_default_image' => 0,
    'default_image_upload' => '',
    'default_image' => NULL,
    'description' => '',
    'required' => 0,
    'multiple' => '1',
    'list_field' => '0',
    'list_default' => 1,
    'description_field' => '0',
    'op' => 'Save field settings',
    'module' => 'filefield',
    'widget_module' => 'imagefield',
    'columns' => 
    array (
      'fid' => 
      array (
        'type' => 'int',
        'not null' => false,
        'views' => true,
      ),
      'list' => 
      array (
        'type' => 'int',
        'size' => 'tiny',
        'not null' => false,
        'views' => true,
      ),
      'data' => 
      array (
        'type' => 'text',
        'serialize' => true,
        'views' => true,
      ),
    ),
    'display_settings' => 
    array (
      'label' => 
      array (
        'format' => 'above',
        'exclude' => 0,
      ),
      'teaser' => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'full' => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      4 => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'token' => 
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
    ),
  ),
);
$content['extra']  = array (
  'title' => '-5',
  'body_field' => '-4',
  'revision_information' => '20',
  'author' => '20',
  'options' => '25',
  'comment_settings' => '30',
  'menu' => '0',
  'path' => '30',
  'shipping' => '0',
  'base' => '-1',
  'body' => '1',
);

$form_state = array();
$form = content_copy_import_form($form_state, $content['type']['type']);
$form_state['values']['type_name'] = $type_name ? $type_name : '';
$form_state['values']['macro'] = '$content = '. var_export($content, 1) .';';
$form_state['values']['op'] = t('Import');
content_copy_import_form_submit($form, $form_state);

Disabling XOrg Standby, Suspend, and Sleep Mode

While wanting to watch Hulu on the computer connected to my TV I ran into the issue where every 5 minutes the TV would go into sleep mode. I was not able to find anything in KDE to prevent this from happening.

I did find a command that would allow you to set this option until XOrg was restarted.

 

# xset q

This will get you information about the keyboard, pointer, screen saver, colors, font path, and DPMS (which is what we want)

 


Keyboard Control:
  auto repeat:  on    key click percent:  0    LED mask:  00000002
  XKB indicators:
    00: Caps Lock:   off    01: Num Lock:    on     02: Scroll Lock: off
    03: Compose:     off    04: Kana:        off    05: Sleep:       off
    06: Suspend:     off    07: Mute:        off    08: Misc:        off
    09: Mail:        off    10: Charging:    off    11: Shift Lock:  off
    12: Group 2:     off    13: Mouse Keys:  off
  auto repeat delay:  250    repeat rate:  30
  auto repeating keys:  00ffffffdffffbbf
                        fadfffefffedffff
                        9fffffffffffffff
                        fff7ffffffffffff
  bell percent:  50    bell pitch:  400    bell duration:  100
Pointer Control:
  acceleration:  45/10    threshold:  4
Screen Saver:
  prefer blanking:  yes    allow exposures:  yes
  timeout:  0    cycle:  600
Colors:
  default colormap:  0x20    BlackPixel:  0x0    WhitePixel:  0xffffff
Font Path:
  catalogue:/etc/X11/fontpath.d,built-ins
DPMS (Energy Star):
  Standby: 300    Suspend: 600    Off: 900
  DPMS is Enabled
  Monitor is On

To keep the monitor from turning off or anything run the following command as root:

xset dpms 0 0 0

Screen Captures on Android Phones

I know you can take a screen shot on an iPhone by holding down the only two buttons, which got me thinking "I should be able to do that on Android phones too." So doing some googling for a few minutes, the only thing that I was able to find was connecting phone to a computer and firing up Eclipse and doing it through the SDK/IDE, downloading a special App and again connecting it to your computer, or installing a 3rd party app.
I know it's possible to do this without rooting the phone, or having to do any of the above ways. I was able to do this on two Samsung phones running Android 2.2 and 2.3, but with different key combinations. So far these are the only two phones I was able do a screen capture on:

  • Samsung Droid Charge: Hold the Back button and hit Home
  • Samsung Galaxy S: Hold the Back button and hit the Power button.

When I get some more free time, I'm going to go to a Verizon store and try to figure out how to do this on other phones, providing that it's possible. It doesn't make sense why this feature was would be left out because it's such a small and nice feature to have.

Having Views Initially Display Empty Text and Setting a Default Value

I have found a way to initially show no results when a view loads, but if I want to display a specific value if nothing is found, that's a different story. One instance that you would want to do something like this is when you're making a distributor or representative locator. In this case, if no results are found, then you want to display the corporate office's contact information. 

I am assuming you have selected the fields you want to display, filtered how you wanted, and exposed what filters you want the user to use.

The first set is to add an argument of null. After clicking on the '+' in the arguments section of the display, select Global from the group dropdown.

When configuring the argument select the following options:

  • Under where it says ACTION TO TAKE IF ARGUMENT IS NOT PRESENT
  • Select provide default argument.
  • Provide a default argument by supplying PHP Code
  • In the PHP Argument Code Box paste the following code:
    $is_filtered = FALSE;
    foreach ($view->filter as $filter) {
      if ($filter->options['exposed']) {
        if (!empty($view->display[$view->current_display]->handler->handlers['filter'][$filter->options['id']]->value)) {
          $is_filtered = TRUE;
          break;
        }
      }
    }
    return $is_filtered;
  • The Validator needs to be set as PHP Code
  • Select ACTION TO TAKE IF ARGUMENT DOES NOT VALIDATE
  • Make sure that there actually isn't anything in the settings for 'Empty Text'

Now the view will not display anything until you filter it. However, the next step is to only display something if there aren't any results. Throw the following code into a glue module:

function MODULENAME_views_pre_render(&$view) {
  if ($view->name == 'VIEWNAME' && count($view->result) == 0) {
    if ($view->current_display == 'DISPLAY' && $view->exposed_data['EXPOSEFIELD'] != 'All')
      $view->attachment_after = HTML;
  }
}

Change the following to fit your needs:

  • MODULENAME - The name of your module.
  • VIEWNAME - The name of the view you are working with.
  • DISPALY - This may or may not be needed. If you have more than one display on this view, then you will need to be specific.
  • EXPOSEDFIELD - This will vary depending on what field you have exposed or not.
  • HTML - The message, plain text or HTML to display when no results are found.

 

Setting up a Static IP and route in Linux

The first step is to setup the interface with an IP and a netmask:

 

# ifconfig eht0 192.168.1.25 netmask 255.255.255.0 up

 

Next we need to tell where we want to route the information to:

 

# route add default gw 192.168.1.1 eth0 

 

The above command is saying that we want a default gateway on interface eth0 to be 192.168.1.1 which is a router.

Creating a Database, User, and Granting Privleges

I always for get how to creat a database, user, and granting privileges to the new user for that database:

 > CREATE DATABASE new_db;
 Query OK, 1 row affected (0.02 sec)
 
 > CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'password';
 Query OK, 0 rows affected (0.03 sec)
 
 > CREATE USER 'new_user'@'%' IDENTIFIED BY 'password';
 Query OK, 0 rows affected (0.03 sec)
 
 > GRANT ALL PRIVILEGES ON 'new_db'.* TO 'new_user'@'localhost' IDENTIFIED BY 'password';
 Query OK, 0 rows affected (0.03 sec)
 
 > GRANT ALL PRIVILEGES ON 'new_db'.* TO 'new_user'@'%' IDENTIFIED BY 'password';
 Query OK, 0 rows affected (0.03 sec)
  

Privileges

ALL
ALTER
ALTER_ROUTINE
CREATE
CREATE  ROUTINE
CREATE TEMPORARY TABLES
CREATE USER
CREATE VIEW
DELETE 
DROP
EVENT
EXECUTE
FILE
GRANT OPTION
 INDEX
 INSERT
 LOCK TABLES
 PROCESS
 REFERENCES
 RELOAD
 REPLICATION CLIENT
 REPLICATION SLAVE
 SHOW DATABASES
 SHOW VIEWS
 SHUTDOWN
 SUPER 
 TRIGGER
 UPDATE
 USAGE

 

Using Git

Below are some notes on how to use git from day to day.

Basics

 

Command Description

$ git config --global user.name "<your name>"
$ git config --global user.email "<your email>"

Configures git with your name and your email. If you don't do this at a global level or at a repository level, git will complain about this.
$ git init Run this command inside a directory that alread has source code to set up a repository.
$ git clone <url> <dest_dir> Creates a new repository in the specified directory.
$ git status Checks that status of the files in the repository. There are two states for files, one being Tracked, and the other being Untracked. Tracked includes all file that are unmodified, modified, or stages while Untracked is everything else. For example, if you add a file to the repositiory after cloning, then the added file is considered Untracked.
$ git add <file> Adds a file to be tracked and commited next time the commit comand is issued. If you run this command, and then make changes and then commit. The changes that were made after it was staged will not be commited.
$ git commit
$ git commit -m "message"
$ git commit -a -m "message"
First command will open up the default editor so you can create a commit message.
The second command will take the commit message as a parameter.
The third command will stage all files and then take the commit message as a parameter. This means you do not need to do git add <file>
$ git diff
$ git giff --cached
 First command shows what changes that were made and that are unstaged.
The second command shows what will be commited.
$ git rm <file>
$ git rm --cached <file>
$ git rm mv <file> <file>
First command deletes the file from the repository and the hard drive.
The second command will remove the file from being tracked.
The last command will rename the file.

 

Ignoring Files

 

Pattern Description
 dir/  Ending slash means to exclude directory.
 /README  Ignore the README file in root directory.
 *.log  Ignore all files with the extension of log.
!out.log Do not ignore the out.log file, this would be used in conjunction with the above pattern.

 

Git Logs

 

Comand Description
$ git log lists the commits made in the repository in reverse chronological order.
$ git log stat Shows stats on commits.
$ git log -p -2 Shows the differences in each commit. The -2 shows last two commits.
$ git log --pretty=format:"%h - %n, %ar : %s" For mats the log according to user input.
$ git log --pretty=format:"%H - %ar" --graph Displays the commits in a ASCII graph.

 

Filtering and Output Options

 

Option Description
-p Shwo the patch introduced with each commit.
--stat Show statics for files modified in each commit.
--shortstat Display only the changed/insertions/deletions line from the --stat command.
--name-only Show the list of files modified after the commit information.
--name-status Show the list of files affected with added/modified/deleted information as well.
--abbrev-commit Display the date in relative format instead of using the full date format.
--graph Show an ASCII graph of the brand and merge history beside the log output.
--pretty  show commits in an alternat format. Options include oneline, short, full, fuller, and format -- where you specify your format.
-(n) Show the last n commits.
--since, --after Limit the commits to those made after a specified date.
--until, --before Limit the commits to those made before a specified date.
--author Only show commits in which the author entry matches the specified string.
--commiter Show only mitts in which the commiter entry matches the specified string.

 

Log Formatting Options

 

Option Description
%H Commit Hash
%h Abbreviated commit hash
%T Tree hash
%t Abbreviated tree hash
%P Parent hashes
%p Abbreviated parent hashes
%an Author name
%ae Author email
%ad Author date
%ar Author date, relative
%cn Commiter name
%ce Commiter e-mail
%cd commiter date
%cr commiter date, relative
%s subject

Changing Last Commit

$ git commit -m "message"
$ git add stdio.h
$ git commit --ammend

Misc commands

To unstage a file:

$ git reset HEAD stdio.h

To discard changes to a file

$ git checkout -- stdio.h

Working with Remote Repositories

Command Description
$ git remote -v Shows short name and url for repositories
$ git remote add <name> <url> Adds a remote repository.
$ git fetch <remote-name> Doing this will give you access to all branches of the remote repository. No local files will exist for you to work on.To get files to work on, you must check out the branch.
$ git pull gets a branch and merges it.
$ git push <remote-name> <branch> Pushes a branch to a remote repository. If the remote branch has changed since you started working on it, you must run git fetch <remote-name> to synchornize the work.
$ git remote rename <from> <to> Rename
 $ get remote rm <remote-name> Deletes a remote name.

Defaulting PHP safe_mode to off in Plesk

When creating a domain in Plesk, PHP safe_mode is enabled by default. To change the default behavor do the following as the admin:

  • On the home screen in Plesk go to Event Manager
  • Click on Add New Event Handler
  • Fill in the form with the following values:
    Event: Physical Hosting Created
    Priority: default is fine
    User: root
    Command: /usr/local/psa/bin/domain -u <new_domain_name> -php_safe_mode false

 

Adding Custom Fields to Ubercart Checkout

I had to add the SKU to the checkout of Ubercart, to do that, I had to do the following:

function MODULENAME_form_alter(&$form, &$form_state, $form_id) {
  switch($form_id) {
    ....
    case 'uc_cart_view_form':
      // Reordering existing columns
      $form['items']['#columns']['desc']['weight'] = 3;
      $form['items']['#columns']['qty']['weight'] = 4;     
      
      // Adding SKU column
      $form['items']['#columns']['sku'] = array('cell' => 'SKU', 'weight' => 2);

      // Iterating through the items array element. Since there are more than just 
      // products in this array, we have to make sure we are modifying the correct 
      // arrays. I do this by checking to see if the element has an array element 
      // called 'nid'
      for($i=0; $i < count($form['items']); $i++) {
	if(isset($form['items'][$i]['nid'])) {
          // Loading the node so we can retrieve the information we need.
	  $product = node_load($form['items'][$i]['nid']['#value']);
          
          // Adding the sku/model to the prodct that is in the user's cart.
	  $form['items'][$i]['sku']['#value'] = $product->model;
	  $form['items'][$i]['sku']['#cell_attributes'] = array('class' => 'cart-sku');
	}
      }
      break;
      ......
  }
}
Syndicate content