Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

turning a module to OO design

Status
Not open for further replies.

1DMF

Programmer
Joined
Jan 18, 2005
Messages
8,795
Location
GB
Hi peeps,

I have a module i've written for doing SQL commands, I'm curious to learn a bit of OO design in perl and thought I might convert it to OO as a learning excersise.

But I need help!!!

Also would there be any advantage doing so, here is one of the routines for getting a count from a table....

module subroutine...
Code:
###############################################
############## SUM SQL Routine ################
###############################################

sub sumSQL {

#_0 = Table
#_1 = Column
#_2 = Where

# Define Record Set Array
my @rs;

#Build SQL Statement
my $sel = "SELECT SUM($_[1]) as MYTOT FROM $_[0] WHERE $_[2]";

# Open DB Connection
my $db;

if(!$FILEDSN){
    $db = new Win32::ODBC($DSN) || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}
else{ 
    $db = new Win32::ODBC("FILEDSN=$DSN;") || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(!$db->Sql("$sel")) {

	# Loop SQL Record Set
		while($db->FetchRow()){ 
				# Build Array of Hashes with SQL Data
				my %dt = $db->DataHash();
			    $rs[@rs] = \%dt;	
		}
	# Close DB Connection
	$db->Close();

	# Return Count
	$rs[0]->{'MYTOT'};

} 
else{die "Error in sumSQL ($sel)" . Win32::ODBC::Error();}

}

and in my normal perl script i call it like so...
Code:
my $cnt = &cntSQL("MyTableName","ColumnName = MyValue");

I have similar routines for fetching updating , deleteing etc...

So I could call
Code:
my @records = &getSQL("TableName","Column1,Column2,Column3","ColumnName1 = 'Value' AND ColumnName2 = 'Value'","ColumnName1 DESC");

so you see how I break it down by Table,Columns,Where,Order

Works great, I was thinking I could change it so it was OO designed, so maybe like this...
Code:
my $sql = new SQL;
$sql->Table("TableName");
$sql->Columns("Column1","Column2");
$sql->Where("Column1 = 'value' AND Column2 = 'value'");
$sql->Order("Column1 DESC");
my @records = $sql->Get;

where Get,Sum,Cnt,Del,Ins are all the methods for the various SQL actions, or maybe have a $sql->Type("SQLType"); and then my @records = $sql->Run;

So would some one help me understand how I go about this, but more importantly is it worth it, what benefit would it give me?

I also currently have global vars which store the DSN be it a local system one, or you can use a file DSN, to change the current one used I do
Code:
$sql::DSN = "new dsn details";

and if i wanted to switch to DSN being a fileDSN I use 

$sql::FILEDSN = 1; 

as it is default set to 0

What are peoples opinions on making this change, is it worth it?


"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
Worth it? If the goal is to learn some OO programming then I think it would be worth it. If the goal is something else, I don't know if it would be worth it.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Ditto. I've implemented a couple OO DB access modules myself. It definitely helped my understanding of OO style, and for a while they modules were pretty useful.

However, whatever design that you come up with is not likely to be nearly as effective as many of the preexisting modules out there. The one that I'm currently looking into using more is Rose::DB:


- Miller
 
Basically all you need for OO design, is to have all the object-specific variables be kept under the object's data structure (typically called $self), and to have a blessed instance of the object.

For example:

Code:
package OO::Test;

# variables out here are global to the module,
# so all objects will share these vars, and if
# they change, all objects will see the changes.
# They're class-level variables.

# Variables declared with 'our' are public,
# class-level variables that can be accessed
# from outside the module by referring to them
# as i.e. $OO::Test::VERSION
our $VERSION = '0.01';

# These are private class-level variables that
# aren't available outside the module.
my $now = time();

# The most common constructor is new().
sub new {
   # new() receives its own module name, and any
   # arguments provided by the calling program.
   my $class = shift;

   # create the object data structure
   my $self = {
      # any default object-specific variables go here
      debug => 0,

      # copy the arguments over too, so i.e. the program
      # can pass in "debug => 1" to override the previous
      # declaration of debug => 0
      @_,
   };

   # Bless the data structure, making it a true object
   bless ($self,$class);

   # Return the object to the calling program.
   return $self;
}

sub set {
   # This is some arbitrary method to set a variable
   # within the data structure.
   my $self; # all object methods receive a reference
             # to their own data structures
   my $var;  # this was passed by the caller
   my $value; # ditto

   $self->{$var} = $value; # set it
}

1; # must return true at the end

Then, your test code:

Code:
#!/usr/bin/perl

use OO::Test;

my $obj1 = new OO::Test (
   debug => 1,
   color => 'blue',
);

my $obj2 = new OO::Test (
   color => 'red',
);

my $obj3 = new OO::Test (
   color => 'green',
);

# we changed our mind on the blue
$obj1->set ('color', 'orange');

So then, all three objects will both share the variables $VERSION and $now, but each one has its very own "debug" flag and its very own "color" flag, independent of the others, because those were object variables.

*thinks he should write a FAQ; this was a pretty lengthy post for just replying to a thread*

-------------
Cuvou.com | My personal homepage
Project Fearless | My web blog
 
Thanks for the replies, looks like I got my work cut out if i'm to understand all that :-)

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
ok , i'm having problems understanding how I talk to the variables set within the module and also getting the result, here is what I have.
Code:
##########################
# Set Package Name Space #
##########################
package Sql_mod;

# variables out here are global to the module,
# so all objects will share these vars, and if
# they change, all objects will see the changes.
# They're class-level variables.

# Variables declared with 'our' are public,
# class-level variables that can be accessed
# from outside the module by referring to them
# as i.e. $OO::Test::VERSION
our $VERSION = '0.01';

# These are private class-level variables that
# aren't available outside the module.
my $now = time();

##########################
# Use WIN32::ODBC Module #
##########################
use Win32::ODBC;

# The most common constructor is new().
sub new {
   # new() receives its own module name, and any
   # arguments provided by the calling program.
   my $class = shift;

   # create the object data structure
   my $self = {
      # any default object-specific variables go here
      debug => 0,

      # copy the arguments over too, so i.e. the program
      # can pass in "debug => 1" to override the previous
      # declaration of debug => 0
      @_,
   };

   # Bless the data structure, making it a true object
   bless ($self,$class);

   # Return the object to the calling program.
   return $self;
}

sub set {
   # This is some arbitrary method to set a variable
   # within the data structure.
   my $self; # all object methods receive a reference
             # to their own data structures
   my $var;  # this was passed by the caller
   my $value; # ditto

   $self->{$var} = $value; # set it
}

###############################################
############## Get SQL Routine ################
###############################################

sub get {

# Define Record Set Array & Hash
my @rs;

#Build SQL Statement
my $sel = "SELECT $self->{'Cols'} FROM $self->{'Table'} WHERE $self->{'Where'}";

# Check for ORDER BY
if($self->{'Order'}){$sel .= " ORDER BY $self->{'Order'}";}

# Open DB Connection
my $db;

if(!$self->{'FileDSN'}){
    $db = new Win32::ODBC($self->{'DSN'}) || die "Sql_mod->get Error Connecting: " . Win32::ODBC::Error();
}
else{ 

    $db = new Win32::ODBC("FILEDSN=$self->{'DSN'};") || die "Sql_mod->get Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(!$db->Sql("$sel")) {

	# Loop SQL Record Set
		while($db->FetchRow()){ 
				# Build Array of Hashes with SQL Data
				my %dt = $db->DataHash();
			    $rs[@rs] = \%dt;	
		}
	# Close DB Connection
	$db->Close();

	# Return Record Set Array of Hashes
	$self->{'Records'} = @rs;

} 
else{die "Error in Sql_mod->get ($sel)" . Win32::ODBC::Error();}

}


1; # must return true at the end

I am assuming that i'm referencing the variable wrong with $self->{'varname'}

I have a script which is as follows..
Code:
#!/usr/bin/perl

# Set Error Trapping
use CGI::Carp qw(fatalsToBrowser warningsToBrowser); 
use warnings;
use strict;
#use diagnostics;

# Set path to user modules
use FindBin qw($Bin);
use lib "$Bin";

use Sql_mod;

# Read URL & Form data.
my $sql = new Sql_mod;

$sql->set ('Cols','myCol');
$sql->set ('DSN','DSN=MYDSN;UID=MYID;PWD=MYPWORD;');
$sql->set ('Table','myTable');
$sql->set ('Where','1=1');
$sql->get;
print $sql->{'Records'};
exit();

I get an error
Error Connecting: [911] [] "[Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified

So in the module i stuck a
Code:
 die $self->{'DSN'};
and it shows it as being empty, so i'm obviously doing something wrong, well there's a suprise - NOT!!

can someone help push me in the right direction and I have a feeling
Code:
print $sql->{'Records'};
is not the correct way to get access to the array of hashes, so again all help is appreciated.

Regards,
1DMF

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
? anyone

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
nope I just don't get this code, I've even put die statements after each $var and $value, both show as empty, so this completely does not work for taking the values pased into it from calling the set method.

Code:
sub set {
   # This is some arbitrary method to set a variable
   # within the data structure.
   my $self; # all object methods receive a reference
             # to their own data structures
   my $var;  # this was passed by the caller
   my $value; # ditto

   $self->{$var} = $value; # set it
}

All this does is declare $var and $value, where are they set to the values passed to the method?

surely there should be a 'shift' in there somewhere and what about @_ , all the exmaples i've found don't show any code like this, i'm completely stumped on understanding how your example code works.

I've tried putting
Code:
my $var = shift;
but if i then print $var i get a hash reference.

if I make $value = @_ , $value prints '2' , so that's like getting the number of indexes in an array as I pass in two arguments.

i'm lost if I use this code ..
Code:
[code]sub set {
   # This is some arbitrary method to set a variable
   # within the data structure.
   my $self; # all object methods receive a reference
             # to their own data structures
   my $dummy = shift; # why do i need this???????
   my $var = shift;  # this was passed by the caller
   my $value = shift; # ditto

   $self->{$var} = $value; # set it
}

and print $var and $value they equal what I passed in to them, HOWEVER.

if in my script I use this
Code:
# Read URL & Form data.
my $sql = new Sql_mod;

$sql->set ('Cols','MYID');

print "Content-Type: text/html\n\n";
print "Cols = " . $sql->{'Cols'};

guess what Cols equals, yup NOTHING!!!!

But in the set method, $var & $value = 'Cols' & 'MYID'

I'm at a loss to understand what is going on here and why it doesn't work.


Can anyone help?


"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
ok , ok I got it, Kirsle, what is this
Code:
sub set {
   # This is some arbitrary method to set a variable
   # within the data structure.
   my $self; # all object methods receive a reference
             # to their own data structures
   my $var;  # this was passed by the caller
   my $value; # ditto

   $self->{$var} = $value; # set it
}

That code will never do anything!!!!

It should have been
Code:
sub set {

   my $self[b] = shift;[/b]
   my $var[b] = shift;[/b]
   my $value[b] = shift;[/b]
   $self->{$var} = $value; # set it
}

But i'm stuck on how do you creat an array variable i want
Code:
$self->{records) = @rs;
but that erros saying i'm trying to put an array into a scalar.

so how do I tell $self that 'records' is an array not a scalar?

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
ok i've finished my OO designed module.

Not sure it is any better than the old way of doing things but at least it taught me some OO design :-)

it's here if anyone is interested...




"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top