[1/40] Work on C4::Labels::Layout module and tests
authorChris Nighswonger <cnighswonger@foundations.edu>
Mon, 29 Jun 2009 15:24:51 +0000 (11:24 -0400)
committerChris Nighswonger <cnighswonger@foundations.edu>
Tue, 1 Sep 2009 19:15:45 +0000 (15:15 -0400)
NOTE: This patch is the first of 40 which almost completely re-factor the
label creator code into a hopefully more scalable form. The new format is
a move in direction of OO handling labels, batches, templates, layouts, and
profiles as objects thus permitting easier implementation of features and
enhancements. It should be possible to export label data in any format one
might choose with the simple addition of a script similar to those included
which produce pdf, csv, and xml format.

One of the larger improvements is a change in workflow that results in template,
layout, and start label selection occurring just before export.

There are also various bugfixes and smaller interface improvements woven into it.

It should be noted that this patch series removes the patron card creator feature
for the present. This feature was only partially completed. A completed variation
will be submitted as a separate patch series to follow in the near future.

The following bugs and enhancements are fixed by this series of patches:

2944 Search to add items to a label batch broken
2061 labels_conf DB values: NULL vs. 0
2511 CSV format string is not cleared when unselected in the label layout editor
2515 Re-factor C4::Labels::DrawSpineText
2823 Label Generator not generating barcodes
3171 Problem due to internationalization in label-create-template.tmpl in de-DE and possibly others
3180 Active settings for label settings should be set at print time only

This work was sponsored by Foundations Bible College & Seminary, Dunn, NC USA

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

diff --git a/C4/Labels/Layout.pm b/C4/Labels/Layout.pm
new file mode 100644 (file)
index 0000000..f512b55
--- /dev/null
@@ -0,0 +1,304 @@
+package C4::Labels::Layout;
+
+# 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 Sys::Syslog qw(syslog);
+
+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();
+}
+
+# FIXME: Consider this style parameter verification instead...
+#  my %param = @_;
+#   for (keys %param)
+#    {   my $lc = lc($_); 
+#        if (exists $default{$lc})
+#        {  $default{$lc} = $param{$_}; 
+#        }
+#        else
+#        {  print STDERR "Unknown parameter $_ , not used \n";
+#        }
+#    }
+
+sub _check_params {
+    my $given_params = {};
+    my $exit_code = 0;
+    my @valtmpl_id_params = (
+        'barcode_type',
+        'start_label',  #remove...pass in as a cgi->param
+        'printing_type',
+        'layout_name',
+        'guidebox',
+        'font_type',
+        'ccode',        #remove...depricated...
+        'callnum_split',
+        'text_justify',
+        'format_string',
+    );
+    if (scalar(@_) >1) {
+        $given_params = {@_};
+        foreach my $key (keys %{$given_params}) {
+            if (!(grep m/$key/, @valtmpl_id_params)) {
+                syslog("LOG_ERR", "C4::Labels::Template : Unrecognized parameter type of \"%s\".", $key);
+                $exit_code = 1;
+            }
+        }
+    }
+    else {
+        if (!(grep m/$_/, @valtmpl_id_params)) {
+            syslog("LOG_ERR", "C4::Labels::Template : Unrecognized parameter type of \"%s\".", $_);
+            $exit_code = 1;
+        }
+    }
+    return $exit_code;
+}
+
+=head1 NAME
+
+C4::Labels::Layout -A class for creating and manipulating layout objects in Koha
+
+=cut
+
+=head1 METHODS
+
+=head2 C4::Labels::Layout->new()
+
+    Invoking the I<new> method constructs a new layout object containing the default values for a layout.
+
+    example:
+        my $layout = Layout->new(); # Creates and returns a new layout object
+
+    B<NOTE:> This layout is I<not> written to the database untill $layout->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 = {
+        barcode_type    =>      '',
+        start_label     =>      1,
+        printing_type   =>      '',
+        layout_name     =>      '',
+        guidebox        =>      0,
+        font_type       =>      '',
+        ccode           =>      '',
+        callnum_split   =>      0,
+        text_justify    =>      '',
+        format_string   =>      '',
+        @_,
+    };
+    bless ($self, $type);
+    return $self;
+}
+
+=head2 Layout->retrieve(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
+
+=cut
+
+sub retrieve {
+    my ($invocant, $layout_id) = @_;
+    my $type = ref($invocant) || $invocant;
+    my $query = "SELECT * FROM labels_layouts WHERE layout_id = ?";  
+    my $sth = C4::Context->dbh->prepare($query);
+    $sth->execute($opts{'layout_id'});
+    if ($sth->err) {
+        syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
+        return 1;
+    }
+    my $self = $sth->fetchrow_hashref;
+    bless ($self, $type);
+    return $self;
+}
+
+=head2 Layout->delete(layout_id => layout_id) |  $layout->delete()
+
+    Invoking the delete method attempts to delete the layout from the database. The method returns 0 upon success
+    and 1 upon failure. Errors are logged to the syslog.
+
+    examples:
+        my $exitstat = $layout->delete(); # to delete the record behind the $layout object
+        my $exitstat = Layout->delete(layout_id => 1); # to delete layout record 1
+
+=cut
+
+sub delete {
+    my $self = {};
+    my %opts = ();
+    my $call_type = '';
+    my $query_param = '';
+    if (ref($_[0])) {
+        $self = shift;  # check to see if this is a method call
+        $call_type = 'C4::Labels::Layout->delete';
+        $query_param = $self->{'layout_id'};
+    }
+    else {
+        %opts = @_;
+        $call_type = 'C4::Labels::Layout::delete';
+        $query_param = $opts{'layout_id'};
+    }
+    warn Dumper(\%opts);
+    if ($query_param eq '') {   # If there is no layout id then we cannot delete it
+        syslog("LOG_ERR", "%s : Cannot delete layout as the layout id is invalid or non-existant.", $call_type);
+        return 1;
+    }
+    my $query = "DELETE FROM labels_layouts WHERE layout_id = ?";  
+    my $sth = C4::Context->dbh->prepare($query);
+    warn "$query : ?= $query_param\n";
+    $sth->execute($query_param);
+    if ($sth->err) {
+        warn "DB error: $sth->errstr\n";
+        syslog("LOG_ERR", "%s : Database returned the following error: %s", $call_type, $sth->errstr);
+        return 1;
+    }
+    return 0;
+}
+
+=head2 $layout->save()
+
+    Invoking the I<save> method attempts to insert the layout into the database if the layout is new and
+    update the existing layout record if the layout exists. The method returns the new record id upon
+    success and -1 upon failure (This avoids conflicting with a record id of 1). Errors are logged to the syslog.
+
+    example:
+        my $exitstat = $layout->save(); # to save the record behind the $layout object
+
+=cut
+
+sub save {
+    my $self = shift;
+    if ($self->{'layout_id'}) {        # if we have an id, the record exists and needs UPDATE
+        my @params;
+        my $query = "UPDATE labels_layouts SET ";
+        foreach my $key (keys %{$self}) {
+            next if $key eq 'id';
+            push (@params, $self->{$key});
+            $query .= "$key=?, ";
+        }
+        $query = substr($query, 0, (length($query)-2));
+        push (@params, $self->{'id'});
+        $query .= " WHERE layout_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;
+        }
+        return $self->{'layout_id'};
+    }
+    else {                      # otherwise create a new record
+        my @params;
+        my $query = "INSERT INTO labels_layouts (";
+        foreach my $key (keys %{$self}) {
+            push (@params, $self->{$key});
+            $query .= "$key, ";
+        }
+        $query = substr($query, 0, (length($query)-2));
+        $query .= ") VALUES (";
+        for (my $i=1; $i<=(scalar keys %$self); $i++) {
+            $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(layout_id) FROM labels_layouts;");
+        $sth1->execute();
+        my $id = $sth1->fetchrow_array;
+        return $id;
+    }
+}
+
+=head2 $layout->get_attr("attr")
+
+    Invoking the I<get_attr> method will return the value of the requested attribute or 1 on errors.
+
+    example:
+        my $value = $layout->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;
+    }
+    return;
+}
+
+=head2 $layout->set_attr(attr => value)
+
+    Invoking the I<set_attr> method will set the value of the supplied attribute to the supplied value.
+
+    example:
+        $layout->set_attr(attr => value);
+
+=cut
+
+sub set_attr {
+    my $self = shift;
+    if (_check_params(@_) eq 1) {
+        return 1;
+    }
+    my ($attr, $value) = @_;
+    $self->{$attr} = $value;
+    return 0;
+}
+1;
+__END__
+
+=head1 AUTHOR
+
+Chris Nighswonger <cnighswonger AT foundations DOT edu>
+
+=cut
diff --git a/t/db_dependent/t_Layout.t b/t/db_dependent/t_Layout.t
new file mode 100644 (file)
index 0000000..365c79a
--- /dev/null
@@ -0,0 +1,99 @@
+#!/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 => 28;
+use C4::Context;
+use Data::Dumper;
+
+BEGIN {
+    use_ok('C4::Labels::Layout');
+}
+
+my $default_layout = {
+        barcode_type    =>      '',
+        start_label     =>      2,
+        printing_type   =>      '',
+        layout_name     =>      'TEST',
+        guidebox        =>      0,
+        font_type       =>      '',
+        ccode           =>      '',
+        callnum_split   =>      0,
+        text_justify    =>      '',
+        format_string   =>      '',
+    };
+
+my $layout;
+
+diag "Testing new layout object creation.";
+ok($layout = C4::Labels::Layout->new(start_label => 2,layout_name => 'TEST'), "Object created");
+is_deeply($layout, $default_layout, "Object verified");
+
+diag "Testing get_attr method.";
+foreach my $key (keys %{$default_layout}) {
+    ok($default_layout->{$key} eq $layout->get_attr($key), "Got $key attribute.");
+}
+
+diag "Testing set_attr method.";
+my $new_attr = {
+        barcode_type    =>      'CODE39',
+        start_label     =>      1,
+        printing_type   =>      'BIBBAR',
+        layout_name     =>      'TEST',
+        guidebox        =>      1,
+        font_type       =>      'TR',
+        ccode           =>      'BOOK',
+        callnum_split   =>      1,
+        text_justify    =>      'L',
+        format_string   =>      'callnumber, title, author, barcode',
+    };
+
+foreach my $key (keys %{$new_attr}) {
+    $layout->set_attr($key, $new_attr->{$key});
+    ok($new_attr->{$key} eq $layout->get_attr($key), "$key attribute is now set to " . $new_attr->{$key});
+}
+
+diag "Testing save method by saving a new record.";
+
+my $sav_results = $layout->save();
+ok($sav_results ne -1, "Record number $sav_results  saved.") || diag "Error encountered during save. See syslog for details.";
+
+my $saved_layout;
+if ($sav_results ne -1) {
+    diag "Testing get method.";
+    $new_attr->{'layout_id'} = $sav_results;
+    diag "\$sav_results = $sav_results";
+    $saved_layout = C4::Labels::Layout->retrieve(layout_id => $sav_results);
+    is_deeply($saved_layout, $new_attr, "Get method verified.");
+}
+
+diag "Testing save method by updating a record.";
+
+$saved_layout->set_attr("start_label",5);
+my $upd_results = $saved_layout->save();
+ok($upd_results ne -1, "Record number $upd_results  updated.") || diag "Error encountered during update. See syslog for details.";
+my $updated_layout = C4::Labels::Layout->retrieve(layout_id => $sav_results);
+is_deeply($updated_layout, $saved_layout, "Update verified.");
+
+diag "Testing delete method.";
+
+my $del_results = $updated_layout->delete();
+ok($del_results eq 0, "Layout deleted.") || diag "Incorrect or non-existent record id. See syslog for details.";