[35/40] Work on C4::Labels tests and various bugfixs resulting
[koha.git] / C4 / Labels / Layout.pm
1 package C4::Labels::Layout;
2
3 use strict;
4 use warnings;
5
6 use Sys::Syslog qw(syslog);
7 use DBI qw(neat);
8
9 use C4::Context;
10 use C4::Debug;
11 use C4::Labels::PDF;
12
13 BEGIN {
14     use version; our $VERSION = qv('1.0.0_1');
15 }
16
17 # FIXME: Consider this style parameter verification instead...
18 #  my %param = @_;
19 #   for (keys %param)
20 #    {   my $lc = lc($_); 
21 #        if (exists $default{$lc})
22 #        {  $default{$lc} = $param{$_}; 
23 #        }
24 #        else
25 #        {  print STDERR "Unknown parameter $_ , not used \n";
26 #        }
27 #    }
28
29 sub _check_params {
30     my $exit_code = 0;
31     my @valtmpl_id_params = (
32         'barcode_type',
33         'printing_type',
34         'layout_name',
35         'guidebox',
36         'font',
37         'font_size',
38         'callnum_split',
39         'text_justify',
40         'format_string',
41     );
42     if (scalar(@_) >1) {
43         my %given_params = @_;
44         foreach my $key (keys %given_params) {
45             if (!(grep m/$key/, @valtmpl_id_params)) {
46                 syslog("LOG_ERR", "C4::Labels::Layout : (Multiple parameters) Unrecognized parameter type of \"%s\".", $key);
47                 $exit_code = 1;
48             }
49         }
50     }
51     else {
52         if (!(grep m/$_/, @valtmpl_id_params)) {
53             syslog("LOG_ERR", "C4::Labels::Layout : (Single parameter) Unrecognized parameter type of \"%s\".", $_);
54             $exit_code = 1;
55         }
56     }
57     return $exit_code;
58 }
59
60 sub new {
61     my $invocant = shift;
62     if (_check_params(@_) eq 1) {
63         return -1;
64     }
65     my $type = ref($invocant) || $invocant;
66     my $self = {
67         barcode_type    =>      'CODE39',
68         printing_type   =>      'BAR',
69         layout_name     =>      'DEFAULT',
70         guidebox        =>      0,
71         font            =>      'TR',
72         font_size       =>      3,
73         callnum_split   =>      0,
74         text_justify    =>      'L',
75         format_string   =>      'title, author, isbn, issn, itemtype, barcode, callnumber',
76         @_,
77     };
78     bless ($self, $type);
79     return $self;
80 }
81
82 sub retrieve {
83     my $invocant = shift;
84     my %opts = @_;
85     my $type = ref($invocant) || $invocant;
86     my $query = "SELECT * FROM labels_layouts WHERE layout_id = ?";  
87     my $sth = C4::Context->dbh->prepare($query);
88     $sth->execute($opts{'layout_id'});
89     if ($sth->err) {
90         syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
91         return -1;
92     }
93     my $self = $sth->fetchrow_hashref;
94     bless ($self, $type);
95     return $self;
96 }
97
98 sub delete {
99     my $self = {};
100     my %opts = ();
101     my $call_type = '';
102     my $query_param = '';
103     if (ref($_[0])) {
104         $self = shift;  # check to see if this is a method call
105         $call_type = 'C4::Labels::Layout->delete';
106         $query_param = $self->{'layout_id'};
107     }
108     else {
109         %opts = @_;
110         $call_type = 'C4::Labels::Layout::delete';
111         $query_param = $opts{'layout_id'};
112     }
113     if ($query_param eq '') {   # If there is no layout id then we cannot delete it
114         syslog("LOG_ERR", "%s : Cannot delete layout as the layout id is invalid or non-existant.", $call_type);
115         return -1;
116     }
117     my $query = "DELETE FROM labels_layouts WHERE layout_id = ?";  
118     my $sth = C4::Context->dbh->prepare($query);
119     $sth->execute($query_param);
120     if ($sth->err) {
121         syslog("LOG_ERR", "%s : Database returned the following error: %s", $call_type, $sth->errstr);
122         return -1;
123     }
124     return 0;
125 }
126
127 sub save {
128     my $self = shift;
129     if ($self->{'layout_id'}) {        # if we have an id, the record exists and needs UPDATE
130         my @params;
131         my $query = "UPDATE labels_layouts SET ";
132         foreach my $key (keys %{$self}) {
133             next if $key eq 'layout_id';
134             push (@params, $self->{$key});
135             $query .= "$key=?, ";
136         }
137         $query = substr($query, 0, (length($query)-2));
138         $query .= " WHERE layout_id=?;";
139         push (@params, $self->{'layout_id'});
140         my $sth = C4::Context->dbh->prepare($query);
141         #local $sth->{TraceLevel} = "3";        # enable DBI trace and set level; outputs to STDERR
142         $sth->execute(@params);
143         if ($sth->err) {
144             syslog("LOG_ERR", "C4::Labels::Layout : Database returned the following error: %s", $sth->errstr);
145             return -1;
146         }
147         return $self->{'layout_id'};
148     }
149     else {                      # otherwise create a new record
150         my @params;
151         my $query = "INSERT INTO labels_layouts (";
152         foreach my $key (keys %{$self}) {
153             push (@params, $self->{$key});
154             $query .= "$key, ";
155         }
156         $query = substr($query, 0, (length($query)-2));
157         $query .= ") VALUES (";
158         for (my $i=1; $i<=(scalar keys %$self); $i++) {
159             $query .= "?,";
160         }
161         $query = substr($query, 0, (length($query)-1));
162         $query .= ");";
163         my $sth = C4::Context->dbh->prepare($query);
164         $sth->execute(@params);
165         if ($sth->err) {
166             syslog("LOG_ERR", "C4::Labels::Layout : Database returned the following error: %s", $sth->errstr);
167             return -1;
168         }
169         my $sth1 = C4::Context->dbh->prepare("SELECT MAX(layout_id) FROM labels_layouts;");
170         $sth1->execute();
171         my $id = $sth1->fetchrow_array;
172         return $id;
173     }
174 }
175
176 sub get_attr {
177     my $self = shift;
178     if (_check_params(@_) eq 1) {
179         return -1;
180     }
181     my ($attr) = @_;
182     if (exists($self->{$attr})) {
183         return $self->{$attr};
184     }
185     else {
186         return -1;
187     }
188     return;
189 }
190
191 sub set_attr {
192     my $self = shift;
193     if (_check_params(@_) eq 1) {
194         return -1;
195     }
196     my %attrs = @_;
197     foreach my $attrib (keys(%attrs)) {
198         $self->{$attrib} = $attrs{$attrib};
199     };
200     return 0;
201 }
202
203 sub get_text_wrap_cols {
204     my $self = shift;
205     my %params = @_;
206     my $string = '';
207     my $strwidth = 0;
208     my $col_count = 0;
209     my $textlimit = $params{'label_width'} - ( 3 * $params{'left_text_margin'});
210
211     while ($strwidth < $textlimit) {
212         $string .= '0';
213         $col_count++;
214         $strwidth = C4::Labels::PDF->StrWidth( $string, $self->{'font'}, $self->{'font_size'} );
215     }
216     return $col_count;
217 }
218
219 1;
220 __END__
221
222 =head1 NAME
223
224 C4::Labels::Layout -A class for creating and manipulating layout objects in Koha
225
226 =head1 ABSTRACT
227
228 This module provides methods for creating, retrieving, and otherwise manipulating label layout objects used by Koha to create and export labels.
229
230 =head1 METHODS
231
232 =head2 new()
233
234     Invoking the I<new> method constructs a new layout object containing the default values for a layout.
235     The following parameters are optionally accepted as key => value pairs:
236
237         C<barcode_type>         Defines the barcode type to be used on labels. NOTE: At present only the following barcode types are supported in the label creator code:
238
239 =over 9
240
241 =item .
242             CODE39          = Code 3 of 9
243
244 =item .
245             CODE39MOD       = Code 3 of 9 with modulo 43 checksum
246
247 =item .
248             CODE39MOD10     = Code 3 of 9 with modulo 10 checksum
249
250 =item .
251             COOP2OF5        = A varient of 2 of 5 barcode based on NEC's "Process 8000" code
252
253 =item .
254             INDUSTRIAL2OF5  = The standard 2 of 5 barcode (a binary level bar code developed by Identicon Corp. and Computer Identics Corp. in 1970)
255
256 =back
257
258         C<printing_type>        Defines the general layout to be used on labels. NOTE: At present there are only five printing types supported in the label creator code:
259
260 =over 9
261
262 =item .
263 BIB     = Only the bibliographic data is printed
264
265 =item .
266 BARBIB  = Barcode proceeds bibliographic data
267
268 =item .
269 BIBBAR  = Bibliographic data proceeds barcode
270
271 =item .
272 ALT     = Barcode and bibliographic data are printed on alternating labels
273
274 =item .
275 BAR     = Only the barcode is printed
276
277 =back
278
279         C<layout_name>          The descriptive name for this layout.
280         C<guidebox>             Setting this to '1' will result in a guide box being drawn around the labels marking the edge of each label
281         C<font>                 Defines the type of font to be used on labels. NOTE: The following fonts are available by default on most systems:
282
283 =over 9
284
285 =item .
286 TR      = Times-Roman
287
288 =item .
289 TB      = Times Bold
290
291 =item .
292 TI      = Times Italic
293
294 =item .
295 TBI     = Times Bold Italic
296
297 =item .
298 C       = Courier
299
300 =item .
301 CB      = Courier Bold
302
303 =item .
304 CO      = Courier Oblique (Italic)
305
306 =item .
307 CBO     = Courier Bold Oblique
308
309 =item .
310 H       = Helvetica
311
312 =item .
313 HB      = Helvetica Bold
314
315 =item .
316 HBO     = Helvetical Bold Oblique
317
318 =back
319
320         C<font_size>            Defines the size of the font in postscript points to be used on labels
321         C<callnum_split>        Setting this to '1' will enable call number splitting on labels
322         C<text_justify>         Defines the text justification to be used on labels. NOTE: The following justification styles are currently supported by label creator code:
323
324 =over 9
325
326 =item .
327 L       = Left
328
329 =item .
330 C       = Center
331
332 =item .
333 R       = Right
334
335 =back
336
337         C<format_string>        Defines what fields will be printed and in what order they will be printed on labels. These include any of the data fields that may be mapped
338                                 to your MARC frameworks. Specify MARC subfields as a 4-character tag-subfield string: ie. 254a Enclose a whitespace-separated list of fields
339                                 to concatenate on one line in double quotes. ie. "099a 099b" or "itemcallnumber barcode" Static text strings may be entered in single-quotes:
340                                 ie. 'Some static text here.'
341
342     example:
343         C<my $layout = Layout->new(); # Creates and returns a new layout object>
344
345         C<my $layout = C4::Labels::Layout->new(barcode_type => 'CODE39', printing_type => 'BIBBAR', font => 'C', font_size => 6); # Creates and returns a new layout object using
346             the supplied values to override the defaults>
347
348     B<NOTE:> This layout is I<not> written to the database until save() is invoked. You have been warned!
349
350 =head2 retrieve(layout_id => layout_id)
351
352     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.
353     Errors are logged to the syslog.
354
355     example:
356         C<my $layout = Layout->retrieve(layout_id => 1); # Retrieves layout record 1 and returns an object containing the record>
357
358 =head2 delete()
359
360     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.
361     NOTE: This method may also be called as a function and passed a key/value pair simply deleteing that template from the database. See the example below.
362
363     examples:
364         C<my $exitstat = $layout->delete(); # to delete the record behind the $layout object>
365         C<my $exitstat = Layout->delete(layout_id => 1); # to delete layout record 1>
366
367 =head2 save()
368
369     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.
370     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.
371
372     example:
373         C<my $exitstat = $layout->save(); # to save the record behind the $layout object>
374
375 =head2 get_attr($attribute)
376
377     Invoking the I<get_attr> method will return the value of the requested attribute or -1 on errors.
378
379     example:
380         C<my $value = $layout->get_attr($attribute);>
381
382 =head2 set_attr(attribute => value, attribute_2 => value)
383
384     Invoking the I<set_attr> method will set the value of the supplied attributes to the supplied values. The method accepts key/value pairs separated by
385     commas.
386
387     example:
388         C<$layout->set_attr(attribute => value);>
389
390 =head2 get_text_wrap_cols()
391
392     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.
393
394     examples:
395         C<my $text_wrap_cols = $layout->get_text_wrap_cols();>
396
397 =head1 AUTHOR
398
399 Chris Nighswonger <cnighswonger AT foundations DOT edu>
400
401 =head1 COPYRIGHT
402
403 Copyright 2009 Foundations Bible College.
404
405 =head1 LICENSE
406
407 This file is part of Koha.
408
409 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
410 Foundation; either version 2 of the License, or (at your option) any later version.
411
412 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,
413 Suite 330, Boston, MA  02111-1307 USA
414
415 =head1 DISCLAIMER OF WARRANTY
416
417 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
418 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
419
420 =cut