Blue Horn

Symfony Framework

sfDoctrine Behavior: Unique Random Column

September 5, 2009 by Sid in Symfony Framework with 0 Comments

I wanted a Symfony doctrine behavior / template to add a column that contains unique random string. I searched around but found nothing, so I developed these doctrine behavior / template for generating unique random string.

Files:

  • RandomUnique.php (see source code further below)
  • RandomUniqueListener.php (see source code further below)

Save the two files in your project’s lib directory.

Example on how to use them in your doctrine schema:

SomeTable:
  actAs:
    RandomUnique:
  columns:
    id: { type: integer(5), primary: true, autoincrement: true }
    user_id: { type: integer(4) }
    org_name: { type: string(100) }
    title: { type: string(20) }
    first_name: { type: string(50) }
    last_name: { type: string(50) }
    email: { type: string(128), notnull: true }

In the example above, column ‘unique_code’ string (16) will be added to the table. When a new record is inserted, unique random string will be generated in that column.

Source code for UniqueRandom.php:

hasColumn($column_name, 'string', $column_size, array('unique' => true, 'notnull' => true));
    $this->addListener(new RandomUniqueListener(array('column_name' => $column_name, 'column_size' => $column_size)));
  }
  
  public static function generateString($minlength, $maxlength, $useupper, $usespecial, $usenumbers)
  {
    /*
     Author: Peter Mugane Kionga-Kamau
     http://www.pmkmedia.com

     Description: string str_makerand(int $minlength, int $maxlength, bool $useupper, bool $usespecial, bool $usenumbers)
     returns a randomly generated string of length between $minlength and $maxlength inclusively.

     Notes:
     - If $useupper is true uppercase characters will be used; if false they will be excluded.
     - If $usespecial is true special characters will be used; if false they will be excluded.
     - If $usenumbers is true numerical characters will be used; if false they will be excluded.
     - If $minlength is equal to $maxlength a string of length $maxlength will be returned.
     - Not all special characters are included since they could cause parse errors with queries.

     Modify at will.
     */
    $charset = "abcdefghijklmnopqrstuvwxyz";
    if ($useupper) $charset .= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    if ($usenumbers) $charset .= "0123456789";
    if ($usespecial) $charset .= "~@#$%^*()_+-={}|]["; // Note: using all special characters this reads: "~!@#$%^&*()_+`-={}|\\]?[\":;'><,./";
    if ($minlength > $maxlength) $length = mt_rand ($maxlength, $minlength);
    else $length = mt_rand ($minlength, $maxlength);
    $key = '';
    for ($i=0; $i<$length; $i++) 
      $key .= $charset[(mt_rand(0,(strlen($charset)-1)))];
    return $key;
  }
}

And source code for UniqueRandomListener.php:

column_name = $options['column_name'];
    $this->column_size = $options['column_size'];
  }
  
  public function preInsert(Doctrine_Event $event)
  {
    $d = $event->getInvoker(); /* @var $d sfDoctrineRecord */
    $class_name = get_class($d);
    $i = 0;
    $s = null;
    
    $column_name = $this->column_name;
    $column_size = $this->column_size;
    
    while ($i < 100) // maximum 100 attempts
    {
      $s = RandomUnique::generateString($column_size, $column_size, false, false, true);
      
      $q = Doctrine_Query::create()
        ->select('t.id')
        ->from($class_name.' t')
        ->where('t.'.$column_name.'=?', $s);
      
      $result = $q->execute(array(), Doctrine::HYDRATE_ARRAY);
      
      // if we have found a unique code (e.g.: is not used, does not exist in the table)
      if (!$result || count($result) < 0) break;
      
      $i++;
    }
    
    $event->getInvoker()->$column_name = $s;
  }
}

I don't have time to make a plugin out of this, so feel free to turn this into a Symfony plugin, but please link to this website :)

Happy coding!

Tagged ,

Related Posts

Leave a reply

Your email address will not be published. Required fields are marked *

*

four × one =

My Projects
Restaurant Websites
Websites