Categories - Create and process categories within MySQL DB
Categories.pm ver.1.0
Categories allows you to create and process categories (for products/directories/shops and etc...)
There is an example that you may use in your own CGI scripts: # --- Script begin here --- use Categories; # NOTE: new() method will create needed DB structure in MySQL (database & tables) if they not exist! # Please create database before execute this script or DB USER must have privilege to create DBs! $obj = Categories->new(database => 'catsdb', user => 'db_user', pass => 'db_pass', host => 'localhost'); # OR # $obj = Categories->new(dbh => $mysql_dbh_handler); if($obj) { my $comp_id = $obj->add(type=>'category',name=>'Computers',category=>0); my $film_id = $obj->add(type=>'category',name=>'Films',category=>0); my $matr_id = $obj->add(type=>'item',name=>'The Matrix',category=>$film_id,value=>''); my $one_id = $obj->add(type=>'item',name=>'The One',category=>$film_id,value=>''); my $cpu_id = $obj->add(type=>'category',name=>'CPU',category=>$comp_id); my $hdd_id = $obj->add(type=>'category',name=>'HDD',category=>$comp_id); my $xp18_id = $obj->add(type=>'item',name=>'Athlon XP 1800+',category=>$cpu_id,value=>''); my $xp20_id = $obj->add(type=>'item',name=>'Athlon XP 2000+',category=>$cpu_id,value=>''); my $xp21_id = $obj->add(type=>'item',name=>'Athlon XP 2100+',category=>$cpu_id,value=>''); my $hdd1_id = $obj->add(type=>'item',name=>'Maxtor 80 GB',category=>$hdd_id,value=>'30 months warranty'); my $hdd2_id = $obj->add(type=>'item',name=>'Maxtor 120 GB',category=>$hdd_id,value=>'36 months warranty'); my @res = $obj->read(path=>'//Computers//HDD//*',sort=>'ID',preload=>YES,reverse=>NO,partial=>'YES'); print "<HR>"; if(scalar(@res)) { foreach $l (@res) { my ($id,$parent_category,$name,$value,$route_path) = @$l; print "ID: $id<BR>\n"; print "PARENT: $parent_category<BR>\n"; print "NAME: $name<BR>\n"; print "VALUE: $value<BR>\n"; $route_path =~ s~//~\\~sgi; $route_path =~ s~\\(.*?)\x0~\\~sgi; print "PATH: $route_path<BR>\n"; print "<HR>"; } } # Find categories and items (filter=>ALL) that has NAME (by=>NAME) 'The Matrix' order by ID (sort=>ID) # and return multiple results (multiple=>'YES') if available, also return rout path to this element # (route=>'YES') using category cache (preload=>'YES') to speed up searching. However 'preload' option may be # worse if categories table is too long, because script load whole table and may crush if not enough memmory! my @res = $obj->find('search'=>'The Matrix','sort'=>'ID','by'=>'NAME','filter'=>'ALL','multiple'=>'YES', 'route'=>'YES','preload'=>'YES','partial'=>'NO','reverse'=>'NO'); if(scalar(@res)) { foreach $l (@res) { my ($type,$id,$parent_category,$name,$value,$route_path) = @$l; print "Type: $type<BR>\n"; print "ID: $id<BR>\n"; print "PARENT: $parent_category<BR>\n"; print "NAME: $name<BR>\n"; print "VALUE: $value<BR>\n"; $route_path =~ s~//~\\~sgi; $route_path =~ s~\\(.*?)\x0~\\~sgi; print "PATH: $route_path<BR>\n"; } } print "<HR>"; # Modify: Change PARENT/CID and/or NAME $obj->modify(id=>$xp21_id,type=>'item',name=>'Duron 1300 MHz',value=>'6 months warranty'); $obj->modify(id=>$comp_id,type=>'category',name=>'PC'); $obj->modify(id=>$cpu_id,type=>'category',newcid=>0); $obj->deep_traverse('preload'=>'YES','id'=>0,'level'=>0,'path'=>'//','eval'=>\&Walk,'sort'=>'NAME'); # Delete ROOT category, so all items/categories are deleted! $obj->del(type=>'category',id=>0); } else { print $Categories::error; } sub Walk { my $self = shift; my %inp = @_; my $id = $inp{'id'}; my $level = $inp{'level'}; my $separator = $inp{'separator'}; my $path = $inp{'path'}; my $name = $inp{'name'}; # ITEM only ($type='I')! my $value = $inp{'value'}; # ITEM only ($type='I')! my $type = $inp{'type'}; $path =~ s~$separator~\\~sgi; $path =~ s~\\(.*?)\x0~\\~sgi; print $path."$name"."[$value]<BR>"; } # --- Script ends here ---
That is simple function reference: # Create object of Categories type $object = Categories->new(database=>'catsdb', user=>'db_user', pass=>'db_pass', host=>'localhost', port=>'3306', create=>'Y', checkdb=>'Y', name=>'catdb', dbh=>$connect_db_handler); Where: database - is your DB where categories (tables) will be placed. If database not exist module will try to create one for you, using supplied user and password. [REQUIRED if $dbh empty] user/pass - is your DB user and password [REQUIRED if $dbh empty] host - MySQL DB host port - your MySQL port create - module will attempt to create DB and/or tables checkdb - module will try to check DB structure name - name of category object dbh - you can supply already connected database handler instead of database/user/pass/host/port! # Test database structure (tables only) $state = $object->is_tables_exists(name=>'name_of_category_object'); # Create database structure (tables only - database must exist!) $state = $object->create_tables(name=>'name_of_category_object'); Create table structure (database should exist!) # Clear categories cache $state = $object->clear_cache(); # Reload/create categories cache and return array of all categories. @cats is array of references to hashes; @cats = $object->preload_categories(name=>'name_of_category_object', sort=>'NAME', reverse=>'N'); Where: sort - is name of column (order by), reverse - reverse results (DESC) HINT: $ref = $cats[0]; %hash = %$ref; $name = $hash{'NAME'}; $id = $hash{'ID'}; $parent = $hash{'PARENT'}; # Find category/item by 'by' column, searching by 'search' keyword (may be on part of word 'partial'=>'Y'); # also it may return full path to located item/category (route=>'Y') using categories cache (preload=>'Y') @res = $object->find(caseinsensitive=>'Y', filter=>'ITEMS', multiple=>'Y', by=>'ID', sort=>'NAME', reverse=>'N', partial=>'N', search=>'keyword', check=>'N', route=>'N', separator=>'//', preload=>'Y'); Where: caseinsensitive - search is caseinsensitive, filter - define where sub must search (ITEMS,CATEGORIES,ALL), multiple - allows muliple results, by - search BY column, sort - 'order by' all results, reverse - reverse all results, partial - allows partial search ( LIKE %something%), search - search keyword, check - test tables structure, route - find path to root, separator - use follow separator to separate categories in route path, preload - allows categories cache. Method returns array of references to arrays results in follow syntax: @res = ($ref_1[,$ref_2,...]), where $ref_n is reference to array with follow structure: @$ref_n = ([0],[1],[2],[3],[4],[5]); where: [0] - 'I' or 'C' (Item or Category), [1] - ID of Item/Category, [2] - PARENT (category ID), [3] - NAME of Item/Category, [4] - VALUE of Item (ONLY) or empty string if Category, [5] - If route=>'Y' this will has follow syntax: $separator.$ID."\x0".$CATEGORY_NAME[$separator...] # Add ITEM/CATEGORY to categories tree. If proceed ITEM you can set 'value' to it. $id = $object->add(type=>'ITEM', category=>'0', name=>'Name_Of_Element', check=>'N', value=>'Items only'); Where: type - is type of element ('ITEM' and 'CATEGORY'), category - is ID of parent (0 is root), name - name of new item/category, value - value of item (only) check - test tables structure. $id is ID of created element. # Delete ITEM/CATEGORY (recursive) by it's own ID $cnt = $object->del(type=>'ITEM', id=>'0', check=>'N', preload=>'Y'); Where: type - is type of element ('ITEM' and 'CATEGORY'), id - is ID of Item/Category (0 is root), check - test tables structure, preload - allows categories cache. $cnt is number of affected(deleted) rows. # Modify(update/rename/move) given ITEM/CATEGORY. If some parameter missed method will not change # current ITEM value (name,parent,value) $cnt = $object->modify(type=>'ITEM', id=>'id_of_element', newcid=>'id_of_new_parent', check=>'N', name=>'new_name_of_element', value=>'Items only', preload=>'Y'); Where: type - is type of element ('ITEM' and 'CATEGORY'), id - is ID of Item/Category, check - test tables structure, name - new name of item/category (if you dismiss filed, NAME will not be affected!), value - new value of item (if you dismiss filed, VALUE will not be affected!), newcid - new Parent category ID (if you dismiss filed, PARENT will not be affected!), preload - allows categories cache. $cnt is number of affected(deleted) rows. # Traverse category tree (in width) and calling 'eval' callback sub for any found category! $cnt = $object->traverse(cid=>'id_of_category', eval=>\&callback_sub', check=>'N', sort=>'NAME', reverse=>'N', preload=>'Y'); This sub traverse in width. Where: cid - ID of category that should be traversed, eval - reference to sub that will be called for every category, it will be called as: &$eval($self,'id'=>$current,'parent'=>$cid); # Traverse category tree (in deep) and calling 'eval' callback sub for any found CATEGORY/ITEM! $object->deep_traverse(id=>'id_of_category', level=>'0', separator=>'//', path=>'//', eval=>\&callback_sub', sort=>'NAME', reverse=>'N', check=>'N', preload=>'Y'); deep_traverse is recursive sub and it traverse in deep. At fist step level should be '0' and path '//' (like separator); eval is also reference to callback sub and it will be called as: &$evala($self,'id'=>$id,'level'=>$level,'type'=>$whereis,'path'=>$path, 'name'=>$item_name,'value'=>$item_value,'separator'=>$separator); where 'name'/'value' will be available only for Items (type=>'I'), but not for categories (type=>'C') # Load found categories/items for 'cid' category only! (no recurse) @res = $object->load_category(cid=>'id_of_category', sort=>'NAME', reverse=>'N', preload=>'Y'); This method will load only Items/Categories of 'cid' category (without recurse)! # Read category/item[s] properties(data) searching by registry-like path (only by 'NAME')! @res = $object->read(path=>'//path//to//category//item', sort=>'ID', reverse=>'N', preload=>'Y', partial=>'N', caseinsensitive=>'Y', separator=>'//', preload=>'Y', check=>'N'); This method try to locate category or item[s] only by 'NAME' starting by 'root' category(PARENT=0), Where: path - is 'registry'-like path to category/item[s]. If path ends with '//' (separator) then searching is proceed for category, other else for item. If name of item is '*' then all items of this 'path' will be fetched! partial - This allows searhing for partial items (not for path or categories)! Moreover to use '*' feature you must set partial=>'YES' Method returns array of references to arrays results in follow syntax: @res = ($ref_1[,$ref_2,...]), where $ref_n is reference to array with follow structure: @$ref_n = ($ID,$PARENT_ID,$NAME,$VALUE,$PATH); $PATH has follow syntax: $separator.$ID."\x0".$CATEGORY_NAME[$separator...]
Julian Lishev - Bulgaria, Sofia, e-mail: julian@proscriptum.com, www.proscriptum.com
To install ShopCard, copy and paste the appropriate command in to your terminal.
cpanm
cpanm ShopCard
CPAN shell
perl -MCPAN -e shell install ShopCard
For more information on module installation, please visit the detailed CPAN module installation guide.