sfDoctrine Behavior: Unique Random Column
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:
<?php class RandomUnique extends Doctrine_Template { public function setTableDefinition() { $column_name = 'unique_code'; $column_size = 16; $this->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:
<?php class RandomUniqueListener extends Doctrine_Record_Listener { protected $column_name; protected $column_size; public function __construct($options) { $this->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!
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.