From 1c39484c4ba694952fae79f214fffabb53b60f37 Mon Sep 17 00:00:00 2001 From: Chris Nighswonger Date: Tue, 1 Sep 2009 11:01:29 -0400 Subject: [PATCH] [2/40] Work on C4::Labels::Template and associated tests This commit also contains some work on C4::Labels::Layout as well --- C4/Labels/Layout.pm | 17 +- C4/Labels/Template.pm | 386 ++++++++++++++++++++++++++++++++++++ t/db_dependent/t_Template.t | 138 +++++++++++++ 3 files changed, 530 insertions(+), 11 deletions(-) create mode 100644 C4/Labels/Template.pm create mode 100644 t/db_dependent/t_Template.t diff --git a/C4/Labels/Layout.pm b/C4/Labels/Layout.pm index f512b55213..8f84cf6c80 100644 --- a/C4/Labels/Layout.pm +++ b/C4/Labels/Layout.pm @@ -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 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 index 0000000000..bf14aa50b6 --- /dev/null +++ b/C4/Labels/Template.pm @@ -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 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 This template is I 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 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 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 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 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 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 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 + +=cut diff --git a/t/db_dependent/t_Template.t b/t/db_dependent/t_Template.t new file mode 100644 index 0000000000..0d945475da --- /dev/null +++ b/t/db_dependent/t_Template.t @@ -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."; -- 2.39.2