[2/40] Work on C4::Labels::Template and associated tests
authorChris Nighswonger <cnighswonger@foundations.edu>
Tue, 1 Sep 2009 15:01:29 +0000 (11:01 -0400)
committerChris Nighswonger <cnighswonger@foundations.edu>
Tue, 1 Sep 2009 19:47:32 +0000 (15:47 -0400)
This commit also contains some work on C4::Labels::Layout as well

C4/Labels/Layout.pm
C4/Labels/Template.pm [new file with mode: 0644]
t/db_dependent/t_Template.t [new file with mode: 0644]

index f512b55..8f84cf6 100644 (file)
@@ -1,6 +1,6 @@
 package C4::Labels::Layout;
 
-# Copyright 2007 Foundations Bible College.
+# Copyright 2009 Foundations Bible College.
 #
 # This file is part of Koha.
 #       
@@ -26,14 +26,8 @@ use C4::Context;
 use C4::Debug;
 use Data::Dumper;
 
-#use vars qw($VERSION @ISA @EXPORT);
-use vars qw($VERSION);
-
 BEGIN {
-    $VERSION = 1.00;
-#    require Exporter;
-#    @ISA    = qw(Exporter);
-#    @EXPORT = qw();
+    use version; our $VERSION = qv('1.0.0_1');
 }
 
 # FIXME: Consider this style parameter verification instead...
@@ -123,18 +117,19 @@ sub new {
     return $self;
 }
 
-=head2 Layout->retrieve(layout_id)
+=head2 Layout->retrieve(layout_id => layout_id)
 
     Invoking the I<retrieve> method constructs a new layout object containing the current values for layout_id. The method returns
     a new object upon success and 1 upon failure. Errors are logged to the syslog.
 
     example:
-        my $layout = Layout->retrieve(1); # Retrieves layout record 1 and returns an object containing the record
+        my $layout = Layout->retrieve(layout_id => 1); # Retrieves layout record 1 and returns an object containing the record
 
 =cut
 
 sub retrieve {
-    my ($invocant, $layout_id) = @_;
+    my $invocant = shift;
+    my %opts = @_;
     my $type = ref($invocant) || $invocant;
     my $query = "SELECT * FROM labels_layouts WHERE layout_id = ?";  
     my $sth = C4::Context->dbh->prepare($query);
diff --git a/C4/Labels/Template.pm b/C4/Labels/Template.pm
new file mode 100644 (file)
index 0000000..bf14aa5
--- /dev/null
@@ -0,0 +1,386 @@
+package C4::Labels::Template;
+
+# Copyright 2009 Foundations Bible College.
+#
+# This file is part of Koha.
+#       
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA  02111-1307 USA
+
+use strict;
+use warnings;
+use Sys::Syslog qw(syslog);
+use Data::Dumper;
+use PDF::Reuse;
+
+use C4::Context;
+use C4::Debug;
+use C4::Labels::Profile 1.000000;
+use C4::Labels::PDF 1.000000;
+
+BEGIN {
+    use version; our $VERSION = qv('1.0.0_1');
+}
+
+my $unit_values = { 
+    POINT       => 1,
+    INCH        => 72,
+    MM          => 2.83464567,
+    CM          => 28.3464567,
+};
+
+sub _check_params {
+    my $given_params = {};
+    my $exit_code = 0;
+    my @valid_template_params = (
+        'tmpl_code',
+        'tmpl_desc',
+        'page_width',
+        'page_height',
+        'label_width',
+        'label_height',
+        'top_text_margin',
+        'left_text_margin',
+        'top_margin',
+        'left_margin',
+        'cols',
+        'rows',
+        'col_gap',
+        'row_gap',
+        'units',
+        'font_size',
+        'font',
+    );
+    if (scalar(@_) >1) {
+        $given_params = {@_};
+        foreach my $key (keys %{$given_params}) {
+            if (!(grep m/$key/, @valid_template_params)) {
+                syslog("LOG_ERR", "C4::Labels::Template : Unrecognized parameter type of \"%s\".", $key);
+                $exit_code = 1;
+            }
+        }
+    }
+    else {
+        if (!(grep m/$_/, @valid_template_params)) {
+            syslog("LOG_ERR", "C4::Labels::Template : Unrecognized parameter type of \"%s\".", $_);
+            $exit_code = 1;
+        }
+    }
+    return $exit_code;
+}
+
+sub _conv_points {
+    my $self = shift;
+    $self->{page_width}         = $self->{page_width} * $unit_values->{$self->{units}};
+    $self->{page_height}        = $self->{page_height} * $unit_values->{$self->{units}};
+    $self->{label_width}        = $self->{label_width} * $unit_values->{$self->{units}};
+    $self->{label_height}       = $self->{label_height} * $unit_values->{$self->{units}};
+    $self->{top_text_margin}    = $self->{top_text_margin} * $unit_values->{$self->{units}};
+    $self->{left_text_margin}   = $self->{left_text_margin} * $unit_values->{$self->{units}};
+    $self->{top_margin}         = $self->{top_margin} * $unit_values->{$self->{units}};
+    $self->{left_margin}        = $self->{left_margin} * $unit_values->{$self->{units}};
+    $self->{col_gap}            = $self->{col_gap} * $unit_values->{$self->{units}};
+    $self->{row_gap}            = $self->{row_gap} * $unit_values->{$self->{units}};
+    return $self;
+}
+
+sub _apply_profile {
+    my $self = shift;
+    my $profile_id = shift;
+    my $profile = C4::Labels::Profile->retrieve(profile_id => $profile_id, convert => 1);
+    $self->{top_margin} = $self->{top_margin} + $profile->get_attr('offset_vert');      # controls vertical offset
+    $self->{left_margin} = $self->{left_margin} + $profile->get_attr('offset_horz');    # controls horizontal offset
+    $self->{label_height} = $self->{label_height} + $profile->get_attr('creep_vert');   # controls vertical creep
+    $self->{label_width} = $self->{label_width} + $profile->get_attr('creep_horz');     # controls horizontal creep
+    return $self;
+}
+
+=head1 NAME
+
+C4::Labels::Template - A class for creating and manipulating template objects in Koha
+
+=cut
+
+=head1 METHODS
+
+=head2 C4::Labels::Template->new()
+
+    Invoking the I<new> method constructs a new template object containing the default values for a template.
+
+    example:
+        my $template = Template->new(); # Creates and returns a new template object
+
+    B<NOTE:> This template is I<not> written to the database untill $template->save() is invoked. You have been warned!
+
+=cut
+
+sub new {
+    my $invocant = shift;
+    if (_check_params(@_) eq 1) {
+        return 1;
+    }
+    my $type = ref($invocant) || $invocant;
+    my $self = {
+        tmpl_code       =>      '',
+        tmpl_desc       =>      '',
+        page_width      =>      0,
+        page_height     =>      0,
+        label_width     =>      0,
+        label_height    =>      0,
+        top_text_margin =>      0,
+        left_text_margin =>      0,
+        top_margin      =>      0,
+        left_margin     =>      0,
+        cols            =>      0,
+        rows            =>      0,
+        col_gap         =>      0,
+        row_gap         =>      0,
+        units           =>      'POINT',
+        font_size       =>      3,
+        font            =>      'TR',
+        tmpl_stat       =>      0,      # false if any data has changed and the db has not been updated
+        @_,
+    };
+    bless ($self, $type);
+    return $self;
+}
+
+=head2 C4::Labels::Template->retrieve(template_id)
+
+    Invoking the I<retrieve> method constructs a new template object containing the current values for template_id. The method returns
+    a new object upon success and 1 upon failure. Errors are logged to the syslog. Two further options may be accessed. See the example
+    below for further description.
+
+    examples:
+
+        my $template = C4::Labels::Template->retrieve(template_id => 1); # Retrieves template record 1 and returns an object containing the record
+
+        my $template = C4::Labels::Template->retrieve(template_id => 1, convert => 1); # Retrieves template record 1, converts the units to points,
+            and returns an object containing the record
+
+        my $template = C4::Labels::Template->retrieve(template_id => 1, profile_id => profile_id); # Retrieves template record 1, converts the units
+            to points, applies the given profile id, and returns an object containing the record
+
+=cut
+
+sub retrieve {
+    my $invocant = shift;
+    my %opts = @_;
+    my $type = ref($invocant) || $invocant;
+    my $query = "SELECT * FROM labels_templates WHERE tmpl_id = ?";  
+    my $sth = C4::Context->dbh->prepare($query);
+    $sth->execute($opts{template_id});
+    if ($sth->err) {
+        syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
+        return 1;
+    }
+    my $self = $sth->fetchrow_hashref;
+    $self = _conv_points($self) if (($opts{convert} && $opts{convert} == 1) || $opts{profile_id});
+    $self = _apply_profile($self, $opts{profile_id}) if $opts{profile_id};
+    $self->{tmpl_stat} = 1;
+    bless ($self, $type);
+    return $self;
+}
+
+=head2 C4::Labels::Template->delete(tmpl_id => template_id) |  $template->delete()
+
+    Invoking the delete method attempts to delete the template from the database. The method returns 0 upon success
+    and 1 upon failure. Errors are logged to the syslog.
+
+    examples:
+        my $exitstat = $template->delete(); # to delete the record behind the $template object
+        my $exitstat = C4::Labels::Template->delete(tmpl_id => 1); # to delete template record 1
+
+=cut
+
+sub delete {
+    my $self = shift;
+    if (!$self->{tmpl_id}) {   # If there is no template tmpl_id then we cannot delete it
+        syslog("LOG_ERR", "Cannot delete template as it has not been saved.");
+        return 1;
+    }
+    my $query = "DELETE FROM labels_templates WHERE tmpl_id = ?";  
+    my $sth = C4::Context->dbh->prepare($query);
+    $sth->execute($self->{tmpl_id});
+    $self->{tmpl_stat} = 0;
+    return 0;
+}
+
+=head2 $template->save()
+
+    Invoking the I<save> method attempts to insert the template into the database if the template is new and
+    update the existing template record if the template exists. The method returns the new record tmpl_id upon
+    success and -1 upon failure (This avotmpl_ids conflicting with a record tmpl_id of 1). Errors are logged to the syslog.
+
+    example:
+        my $exitstat = $template->save(); # to save the record behind the $template object
+
+=cut
+
+sub save {
+    my $self = shift;
+    if ($self->{'tmpl_id'}) {        # if we have an tmpl_id, the record exists and needs UPDATE
+        my @params;
+        my $query = "UPDATE labels_templates SET ";
+        foreach my $key (keys %{$self}) {
+            next if ($key eq 'tmpl_id') || ($key eq 'tmpl_stat');
+            push (@params, $self->{$key});
+            $query .= "$key=?, ";
+        }
+        $query = substr($query, 0, (length($query)-2));
+        push (@params, $self->{'tmpl_id'});
+        $query .= " WHERE tmpl_id=?;";
+        warn "DEBUG: Updating: $query\n" if $debug;
+        my $sth = C4::Context->dbh->prepare($query);
+        $sth->execute(@params);
+        if ($sth->err) {
+            syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
+            return -1;
+        }
+        $self->{tmpl_stat} = 1;
+        return $self->{'tmpl_id'};
+    }
+    else {                      # otherwise create a new record
+        my @params;
+        my $query = "INSERT INTO labels_templates (";
+        foreach my $key (keys %{$self}) {
+            next if $key eq 'tmpl_stat';
+            push (@params, $self->{$key});
+            $query .= "$key, ";
+        }
+        $query = substr($query, 0, (length($query)-2));
+        $query .= ") VALUES (";
+        for (my $i=1; $i<=((scalar keys %$self) - 1); $i++) {   # key count less keys not db related...
+            $query .= "?,";
+        }
+        $query = substr($query, 0, (length($query)-1));
+        $query .= ");";
+        warn "DEBUG: Saving: $query\n" if $debug;
+        my $sth = C4::Context->dbh->prepare($query);
+        $sth->execute(@params);
+        if ($sth->err) {
+            syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
+            return -1;
+        }
+        my $sth1 = C4::Context->dbh->prepare("SELECT MAX(tmpl_id) FROM labels_templates;");
+        $sth1->execute();
+        my $tmpl_id = $sth1->fetchrow_array;
+        $self->{tmpl_id} = $tmpl_id;
+        $self->{tmpl_stat} = 1;
+        return $tmpl_id;
+    }
+}
+
+=head2 $template->get_attr("attr")
+
+    Invoking the I<get_attr> method will return the value of the requested attribute or 1 on errors.
+
+    example:
+        my $value = $template->get_attr("attr");
+
+=cut
+
+sub get_attr {
+    my $self = shift;
+    if (_check_params(@_) eq 1) {
+        return 1;
+    }
+    my ($attr) = @_;
+    if (exists($self->{$attr})) {
+        return $self->{$attr};
+    }
+    else {
+        return 1;
+    }
+}
+
+=head2 $template->set_attr(attr, value)
+
+    Invoking the I<set_attr> method will set the value of the supplied attribute to the supplied value.
+
+    example:
+        $template->set_attr(attr => value);
+
+=cut
+
+sub set_attr {
+    my $self = shift;
+    if (_check_params(@_) eq 1) {
+        return 1;
+    }
+    my ($attr, $value) = @_;
+    $self->{$attr} = $value;
+}
+
+=head2 $template->get_text_wrap_cols()
+
+    Invoking the I<get_text_wrap_cols> method will return the number of columns that can be printed on the
+    label before wrapping to the next line.
+
+    examples:
+        my $text_wrap_cols = $template->get_text_wrap_cols();
+
+=cut
+
+sub get_text_wrap_cols {
+    my $self = shift;
+    my $string = '';
+    my $strwidth = 0;
+    my $col_count = 0;
+    my $textlimit = $self->{label_width} - ( 3 * $self->{left_text_margin});
+
+    while ($strwidth < $textlimit) {
+        $string .= '0';
+        $col_count++;
+        $strwidth = C4::Labels::PDF->StrWidth( $string, $self->{font}, $self->{font_size} );
+    }
+    return $col_count;
+}
+
+=head2 $template->get_label_position($start_label)
+
+    Invoking the I<get_label_position> method will return the row, column coordinates on the starting page
+    and the lower left x,y coordinates on the starting label for the template object.
+
+    examples:
+        my ($row_count, $col_count, $llx, $lly) = $template->get_label_position($start_label);
+
+=cut
+
+sub get_label_position {
+    my ($self, $start_label) = @_;
+    my ($row_count, $col_count, $llx, $lly) = 0,0,0,0;
+    if ($start_label eq 1) {
+        $row_count = 1;
+        $col_count = 1;
+        $llx = $self->{left_margin};
+        $lly = ($self->{page_height} - $self->{top_margin} - $self->{label_height});
+        return ($row_count, $col_count, $llx, $lly);
+    }
+    else {
+        $row_count = ceil($start_label / $self->{cols});
+        $col_count = ($start_label - (($row_count - 1) * $self->{cols}));
+        $llx = $self->{left_margin} + ($self->{label_width} * ($col_count - 1)) + ($self->{col_gap} * ($col_count - 1));
+        $lly = $self->{page_height} - $self->{top_margin} - ($self->{label_height} * $row_count) - ($self->{row_gap} * ($row_count - 1));
+        return ($row_count, $col_count, $llx, $lly);
+    }
+}
+
+1;
+__END__
+
+=head1 AUTHOR
+
+Chris Nighswonger <cnighswonger AT foundations DOT edu>
+
+=cut
diff --git a/t/db_dependent/t_Template.t b/t/db_dependent/t_Template.t
new file mode 100644 (file)
index 0000000..0d94547
--- /dev/null
@@ -0,0 +1,138 @@
+#!/usr/bin/perl
+#
+# Copyright 2007 Foundations Bible College.
+#
+# This file is part of Koha.
+#       
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA  02111-1307 USA
+
+use strict;
+use warnings;
+
+use Test::More tests => 54;
+use C4::Context;
+use Data::Dumper;
+
+BEGIN {
+    use_ok('C4::Labels::Template');
+}
+
+my $expect_template = {
+    tmpl_code           => '',
+    tmpl_desc           => '',
+    page_width          => 8.5,
+    page_height         => 0,
+    label_width         => 0,
+    label_height        => 0,
+    top_text_margin     => 0,
+    left_text_margin    => 0,
+    top_margin          => 0,
+    left_margin         => 0,
+    cols                => 3,
+    rows                => 0,
+    col_gap             => 0,
+    row_gap             => 0,
+    units               => 'POINT',
+    font_size           => 3,
+    font                => 'TR',
+    tmpl_stat           => 0,
+};
+
+my $template;
+
+diag "Testing new template object creation.";
+ok($template = C4::Labels::Template->new(page_width => 8.5,cols => 3), "Object created");
+is_deeply($template, $expect_template, "Object verified");
+
+diag "Testing get_attr method.";
+foreach my $key (keys %{$expect_template}) {
+    ok($expect_template->{$key} eq $template->get_attr($key), "Got $key attribute.");
+}
+
+diag "Testing set_attr method.";
+my $new_attr = {
+    tmpl_code           => 'Avery 5160 | 1 x 2-5/8',
+    tmpl_desc           => '3 columns, 10 rows of labels',
+    page_width          => 8.5,
+    page_height         => 11,
+    label_width         => 2.63,
+    label_height        => 1,
+    top_text_margin     => 0.139,
+    left_text_margin    => 0.0417,
+    top_margin          => 0.35,
+    left_margin         => 0.23,
+    cols                => 3,
+    rows                => 10,
+    col_gap             => 0.13,
+    row_gap             => 0,
+    units               => 'INCH',
+    font_size           => 7,
+    font                => 'C',
+    tmpl_stat           => 1,
+};
+
+foreach my $key (keys %{$new_attr}) {
+    next if ($key eq 'tmpl_stat');
+    $template->set_attr($key, $new_attr->{$key});
+    ok($new_attr->{$key} eq $template->get_attr($key), "$key attribute is now set to " . $new_attr->{$key});
+}
+
+diag "Testing save method by saving a new record.";
+
+my $sav_results = $template->save();
+ok($sav_results ne -1, "Record number $sav_results  saved.") || diag "Error encountered during save. See syslog for details.";
+
+my $saved_template;
+if ($sav_results ne -1) {
+    diag "Testing retrieve method.";
+    $new_attr->{'tmpl_id'} = $sav_results;
+    $saved_template = C4::Labels::Template->retrieve(template_id => $sav_results);
+    is_deeply($saved_template, $new_attr, "Retrieve method verified.");
+}
+
+diag "Testing save method by updating a record.";
+
+$saved_template->set_attr(start_label => 5);
+my $upd_results = $saved_template->save();
+ok($upd_results ne -1, "Record number $upd_results  updated.") || diag "Error encountered during update. See syslog for details.";
+my $updated_template = C4::Labels::Template->retrieve(template_id => $sav_results);
+is_deeply($updated_template, $saved_template, "Update verified.");
+
+diag "Testing conv_points method.";
+
+my $conv_template = C4::Labels::Template->retrieve(template_id => $sav_results, convert => 1);
+my $expect_conv = {
+    page_width          => 612,
+    page_height         => 792,
+    label_width         => 189.36,
+    label_height        => 72,
+    top_text_margin     => 10.008,
+    left_text_margin    => 3.0024,
+    top_margin          => 25.2,
+    left_margin         => 16.56,
+    col_gap             => 9.36,
+    row_gap             => 0,
+};
+
+foreach my $key (keys %{$expect_conv}) {
+    ok($expect_conv->{$key} eq $conv_template->get_attr($key), "$key converted correctly.") || diag "Expected " . $expect_conv->{$key} . " but got " . $conv_template->get_attr($key) . ".";
+}
+
+diag "Testing get_text_wrap_cols method.";
+ok ($conv_template->get_text_wrap_cols eq 43, "Get_text_wrap_cols verified.");
+
+diag "Testing delete method.";
+
+my $del_results = $updated_template->delete();
+ok($del_results eq 0, "Template deleted.") || diag "Incorrect or non-existent record id. See syslog for details.";