Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Esteemed Monks,

For all past time we have connected directly to our CRM from the scripts that need to read or write the data. It has been my intention for a very long time to create some standard subroutines in a require file to do all the things we regularly need to do. Thanks to The Monastery, I now know I need to use a module to do this. So I have set about creating a suitable module. I also thought this would be a good opportunity to do it properly and include some POD. This module will never be used outside of our use case but it seems like good practice to include documentation.

Could you please look over the code and documentation and for me before I go too much further and advise if I am making any horrible mistakes, what I can improve and how clear the documentation is...

package Bod::CRM; use DBI; use Bod::Variables; use strict; use warnings; =head1 Name Bod::CRM =head1 Synopsis Bod::CRM provides simple methods to access the Lets Delight CRM. use Bod::CRM; my $crm = Bod::CRM->new(); my $vars = { 'firstname' => 'John', 'lastname' => 'Smith', 'pri_email' => 'john.smith@example.com', }; $crm->add($vars); my $vars = { 'firstname' => 'John', }; my @contacts = $crm->find($vars); print $crm->error; =head2 Error Handling Except where otherwise documented, methods return zero to indicate an +error. The error message can be found by calling the B<error()> method. =head2 Description =cut =head4 new(environment); =over 1 Creates a new connection to the CRM. If I<environment> is 'prod' or ' +test', that environment is used. If I<environment> is omitted, an at +tempt is made to find the environment from the C<$ENV{'HTTP_HOST'}> v +ariable. Returns a B<Bod::CRM> object or I<undef> if unsuccessful. Unsuccessful means either the environment was wrong or the connection +to the database failed for another reason. =back =cut sub new { my ($class, $env) = @_; if (!$env and $ENV{'HTTP_HOST'} =~ /^(.*?)\./) { $env = $1; } $env = 'prod' if $env eq 'www'; my $dbh = DBI->connect("dbi:mysql:$Bod::Variables::db_prefix$env:l +ocalhost:3306", "$Bod::Variables::db_username", "$Bod::Variables::db_ +password"); if (!$dbh) { warn("Unable to connect to $env database - " . $DBI::errstr); return undef; } my @schema_fields; my $query = $dbh->prepare("SELECT COLUMN_NAME FROM information_sch +ema.`COLUMNS` WHERE TABLE_SCHEMA = '$Bod::Variables::db_prefix$env' A +ND TABLE_NAME = '$Bod::Variables::C_Table'"); $query->execute; while (my ($field) = $query->fetchrow_array) { push @schema_fields, $field; } my $self = bless { 'env' => $env, 'dbh' => $dbh, 'error' => '', 'field' => \@schema_fields }, $class; return $self; } =head4 error(); =over 1 Return a string detailing the last error. =back =cut sub error { my ($self) = @_; return $self->{error}; } =head4 find(fields, blanks); =over 1 Finds a list of people in the CRM matching all the I<fields> passed as + a hash reference. Empty strings are not matched unless the optional + I<blanks> parameter is true. Returns an array of people IDs that match all keys as fields to values + as contents. =back =cut sub find { my ($self, $fields, $blanks) = @_; my $where; my @place; my $flag = 0; foreach my $field(keys(%$fields)) { next unless $fields->{$field} or $blanks; $where .= " AND " if $flag; $where .= "$field = ?"; push @place, $fields->{$field}; $flag = 1; } my @ids; my $query = $self->{'dbh'}->prepare("SELECT idContact FROM $Bod::V +ariables::C_Table WHERE $where"); $query->execute(@place); while (my $id = $query->fetchrow_array) { push @ids, $id; } return @ids; } =head4 get(id); =over 1 Get information about the person with given I<id> Returns a hash reference containing keys with the values of the CRM fi +eld names. =back =cut sub get { my ($self, $id) = @_; return $self->{'dbh'}->selectrow_hashref("SELECT * FROM $Bod::Vari +ables::C_Table WHERE id$Bod::Variables::C_Table = ?", undef, $id); } =head4 add(fields); =over 1 Add a person to the CRM or update existing person Given the information in the passed hash reference I<fields> add or up +date a person. If the B<email> or B<Twitter> fields match then updat +e an existing person, otherwise add a new person. If a new person is + being added then the I<fields> source key must be set to the correct + value to correspond with the B<PersonSource> table. If the source key is not set or insufficient information is provided, +returns zero. Otherwise returns the contact ID of the person created + or updated. =back =cut sub add { my ($self, $fields) = @_; my $id; $id = $self->{'dbh'}->selectrow_array("SELECT id$Bod::Variables::C +_Table FROM $Bod::Variables::C_Table WHERE pri_email= ? OR sec_email += ?", undef, $fields->{'email'}, $fields->{'email'}) if $fields->{'em +ail'}; $fields->{'twitter'} =~ s/^\@//; $id = $self->{'dbh'}->selectrow_array("SELECT id$Bod::Variables::C +_Table FROM $Bod::Variables::C_Table WHERE twitter = ?", undef, $fiel +ds->{'twitter'}) if $fields->{'twitter'} and !$id; $fields->{"id$Bod::Variables::C_Table"} = $fields->{'id'} if $fiel +ds->{'id'} and !$fields->{"id$Bod::Variables::C_Table"}; # These fields should not be set manually $fields->{$Bod::Variables::S_Table} = undef; $fields->{'created'} = undef; $fields->{'updated'} = undef; my @place; my $set; my $flag = 0; foreach my $field(@{$self->{'field'}}) { if ($fields->{$field}) { $set .= ', ' if $flag; $set .= "$field = ?"; push @place, $fields->{$field}; $flag = 1; } } if ($id) { my $query = $self->{'dbh'}->prepare("UPDATE $Bod::Variables::C +_Table SET $set, updated = DATE(NOW()) WHERE id$Bod::Variables::C_Tab +le = $id"); $query->execute(@place); } else { if (!$fields->{'source'}) { $self->error = 'No source code provided for contact'; return 0; } if (!$fields->{'firstname'} and !$fields->{'email'} and !$fiel +ds->{'twitter'}) { $self->error = 'Insufficient information provided for cont +act'; return 0; } my $query = $self->{'dbh'}->prepare("INSERT INTO $Bod::Variabl +es::C_Table SET $set, created = DATE(NOW()), $Bod::Variables::S_Table + = ?"); $query->execute(@place, $fields->{'source'}); $id = $self->{'dbh'}->selectrow_array("SELECT LAST_INSERT_ID() +"); } return $id; } =head4 business(contact, business, subscribe) =over 1 Adds the person to the business unit as definded in the B<BusinessUnit +> table. Has no effect if the person is already added to the busines +s unit. However, if the optional I<subscribe> is true, the person wi +ll be resubscribed to the list if they had previously unsubscribed. Returns true if the person is in the busines unit, zero if it has fail +ed and I<undef> if an error has occurred. =back =cut sub business { my ($self, $contact, $business, $subscribe) = @_; unless ($contact > 0 and $business > 0) { $self->error = 'Invalid Contact or Business parameters'; return undef; } my $update; $update = ' ON DUPLICATE KEY UPDATE subscribe = 1' if $subscribe; my $query = $self->{'dbh'}->prepare("INSERT IGNORE INTO $Bod::Vari +ables::B_Table_has_$Bod::Variables::C_Table SET $Bod::Variables::C_Ta +ble_id$Bod::Variables::C_Table = ?, $Bod::Variables::B_Table_id$Bod:: +Variables::B_Table = ?, subscribe = 1$update"); $query->execute($contact, $business); return $self->{'dbh'}->selectrow_array("SELECT COUNT(*) FROM $Bod: +:Variables::B_Table_has_$Bod::Variables::C_Table WHERE $Bod::Variable +s::C_Table_id$Bod::Variables::C_Table = ?, $Bod::Variables::B_Table_i +d$Bod::Variables::B_Table = ?", undef, $contact, $business); } =head4 marketing(contact, business, permission, grant) =over 1 Set the marketing permissions for a person on the specified business u +nit. The I<permission> parameter is defined in the B<MarketingPermis +sionLookUp> table. Normally, this method will grant the permission b +ut can also revoke the permision by passing 'R' as the optional I<gra +nt> parameter =back =cut sub marketing { my ($self, $contact, $business, $permission, $grant) = @_; unless ($contact > 0 and $business > 0 and $permission > 0) { $self->error = 'Invalid Contact, Business or Permission parame +ters'; return undef; } $grant = 'G' unless $grant eq 'R'; my $query = $self->{'dbh'}->prepare("INSERT INTO $Bod::Variables:: +M_Table SET $Bod::Variables::C_Table_id$Bod::Variables::C_Table = ?, +$Bod::Variables::B_Table_id$Bod::Variables::B_Table = ?, date = NOW() +, giveRem = ?, Permission_idPermission = ?"); $query->execute($contact, $business, $grant, $permission); return $self->{'dbh'}->selectrow_array("SELECT COUNT(*) FROM $Bod: +:Variables::M_Table WHERE $Bod::Variables::C_Table_id$Bod::Variables: +:C_Table = ?, $Bod::Variables::B_Table_id$Bod::Variables::B_Table = ? + AND Permission_idPermission = ? AND date > NOW() - INTERVAL 2 SECOND +", undef, $contact, $business, $permission); } 1;

I have pulled out anything that could pose a security threat to Bod::Variables. Not just database username and password but also schema name and table names.

The documentation as generated by pod2html is here.


In reply to [RFC] Review of module code and POD by Bod

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (4)
As of 2024-04-24 01:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found