[31/40] Misc bugfixes and cosmetic cleanup.
[koha.git] / C4 / Labels / Template.pm
1 package C4::Labels::Template;
2
3 # Copyright 2009 Foundations Bible College.
4 #
5 # This file is part of Koha.
6 #       
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20 use strict;
21 use warnings;
22 use Sys::Syslog qw(syslog);
23 use Data::Dumper;
24 use PDF::Reuse;
25 use POSIX qw(ceil);
26
27 use C4::Context;
28 use C4::Debug;
29 use C4::Labels::Profile 1.000000;
30 use C4::Labels::PDF 1.000000;
31 use C4::Labels::Lib 1.000000 qw(get_unit_values);
32
33 BEGIN {
34     use version; our $VERSION = qv('1.0.0_1');
35 }
36
37 sub _check_params {
38     my $given_params = {};
39     my $exit_code = 0;
40     my @valid_template_params = (
41         'profile_id',
42         'template_code',
43         'template_desc',
44         'page_width',
45         'page_height',
46         'label_width',
47         'label_height',
48         'top_text_margin',
49         'left_text_margin',
50         'top_margin',
51         'left_margin',
52         'cols',
53         'rows',
54         'col_gap',
55         'row_gap',
56         'units',
57     );
58     if (scalar(@_) >1) {
59         $given_params = {@_};
60         foreach my $key (keys %{$given_params}) {
61             if (!(grep m/$key/, @valid_template_params)) {
62                 syslog("LOG_ERR", "C4::Labels::Template : Unrecognized parameter type of \"%s\".", $key);
63                 $exit_code = 1;
64             }
65         }
66     }
67     else {
68         if (!(grep m/$_/, @valid_template_params)) {
69             syslog("LOG_ERR", "C4::Labels::Template : Unrecognized parameter type of \"%s\".", $_);
70             $exit_code = 1;
71         }
72     }
73     return $exit_code;
74 }
75
76 sub _conv_points {
77     my $self = shift;
78     my @unit_value = grep {$_->{'type'} eq $self->{'units'}} @{get_unit_values()};
79     $self->{'page_width'}         = $self->{'page_width'} * $unit_value[0]->{'value'};
80     $self->{'page_height'}        = $self->{'page_height'} * $unit_value[0]->{'value'};
81     $self->{'label_width'}        = $self->{'label_width'} * $unit_value[0]->{'value'};
82     $self->{'label_height'}       = $self->{'label_height'} * $unit_value[0]->{'value'};
83     $self->{'top_text_margin'}    = $self->{'top_text_margin'} * $unit_value[0]->{'value'};
84     $self->{'left_text_margin'}   = $self->{'left_text_margin'} * $unit_value[0]->{'value'};
85     $self->{'top_margin'}         = $self->{'top_margin'} * $unit_value[0]->{'value'};
86     $self->{'left_margin'}        = $self->{'left_margin'} * $unit_value[0]->{'value'};
87     $self->{'col_gap'}            = $self->{'col_gap'} * $unit_value[0]->{'value'};
88     $self->{'row_gap'}            = $self->{'row_gap'} * $unit_value[0]->{'value'};
89     return $self;
90 }
91
92 sub _apply_profile {
93     my $self = shift;
94     my $profile = C4::Labels::Profile->retrieve(profile_id => $self->{'profile_id'}, convert => 1);
95     $self->{'top_margin'} = $self->{'top_margin'} + $profile->get_attr('offset_vert');      # controls vertical offset
96     $self->{'left_margin'} = $self->{'left_margin'} + $profile->get_attr('offset_horz');    # controls horizontal offset
97     $self->{'label_height'} = $self->{'label_height'} + $profile->get_attr('creep_vert');   # controls vertical creep
98     $self->{'label_width'} = $self->{'label_width'} + $profile->get_attr('creep_horz');     # controls horizontal creep
99     return $self;
100 }
101
102 =head1 NAME
103
104 C4::Labels::Template - A class for creating and manipulating template objects in Koha
105
106 =cut
107
108 =head1 METHODS
109
110 =head2 C4::Labels::Template->new()
111
112     Invoking the I<new> method constructs a new template object containing the default values for a template.
113
114     example:
115         my $template = Template->new(); # Creates and returns a new template object
116
117     B<NOTE:> This template is I<not> written to the database untill $template->save() is invoked. You have been warned!
118
119 =cut
120
121 sub new {
122     my $invocant = shift;
123     if (_check_params(@_) eq 1) {
124         return -1;
125     }
126     my $type = ref($invocant) || $invocant;
127     my $self = {
128         profile_id      =>      '0',
129         template_code   =>      'DEFAULT TEMPLATE',
130         template_desc   =>      'Default description',
131         page_width      =>      0,
132         page_height     =>      0,
133         label_width     =>      0,
134         label_height    =>      0,
135         top_text_margin =>      0,
136         left_text_margin =>      0,
137         top_margin      =>      0,
138         left_margin     =>      0,
139         cols            =>      0,
140         rows            =>      0,
141         col_gap         =>      0,
142         row_gap         =>      0,
143         units           =>      'POINT',
144         tmpl_stat       =>      0,      # false if any data has changed and the db has not been updated
145         @_,
146     };
147     bless ($self, $type);
148     return $self;
149 }
150
151 =head2 C4::Labels::Template->retrieve(template_id)
152
153     Invoking the I<retrieve> method constructs a new template object containing the current values for template_id. The method returns
154     a new object upon success and 1 upon failure. Errors are logged to the syslog. Two further options may be accessed. See the example
155     below for further description.
156
157     examples:
158
159         my $template = C4::Labels::Template->retrieve(template_id => 1); # Retrieves template record 1 and returns an object containing the record
160
161         my $template = C4::Labels::Template->retrieve(template_id => 1, convert => 1); # Retrieves template record 1, converts the units to points,
162             and returns an object containing the record
163
164         my $template = C4::Labels::Template->retrieve(template_id => 1, profile_id => profile_id); # Retrieves template record 1, converts the units
165             to points, applies the given profile id, and returns an object containing the record
166
167 =cut
168
169 sub retrieve {
170     my $invocant = shift;
171     my %opts = @_;
172     my $type = ref($invocant) || $invocant;
173     my $query = "SELECT * FROM labels_templates WHERE template_id = ?";  
174     my $sth = C4::Context->dbh->prepare($query);
175     $sth->execute($opts{template_id});
176     if ($sth->err) {
177         syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
178         return -1;
179     }
180     my $self = $sth->fetchrow_hashref;
181     $self = _conv_points($self) if (($opts{convert} && $opts{convert} == 1) || $opts{profile_id});
182     $self = _apply_profile($self) if $opts{profile_id};
183     $self->{'tmpl_stat'} = 1;
184     bless ($self, $type);
185     return $self;
186 }
187
188 =head2 C4::Labels::Template::delete(template_id => template_id) |  $template->delete()
189
190     Invoking the delete method attempts to delete the template from the database. The method returns 0 upon success
191     and 1 upon failure. Errors are logged to the syslog.
192
193     examples:
194         my $exitstat = $template->delete(); # to delete the record behind the $template object
195         my $exitstat = C4::Labels::Template::delete(template_id => 1); # to delete template record 1
196
197 =cut
198
199 sub delete {
200     my $self = {};
201     my %opts = ();
202     my $call_type = '';
203     my $query_param = '';
204     if (ref($_[0])) {
205         $self = shift;  # check to see if this is a method call
206         $call_type = 'C4::Labels::Template->delete';
207         $query_param = $self->{'template_id'};
208     }
209     else {
210         %opts = @_;
211         $call_type = 'C4::Labels::Template::delete';
212         $query_param = $opts{'template_id'};
213     }
214     if ($query_param eq '') {   # If there is no template id then we cannot delete it
215         syslog("LOG_ERR", "%s : Cannot delete layout as the template id is invalid or non-existant.", $call_type);
216         return -1;
217     }
218     my $query = "DELETE FROM labels_templates WHERE template_id = ?";  
219     my $sth = C4::Context->dbh->prepare($query);
220     $sth->execute($query_param);
221     $self->{'tmpl_stat'} = 0;
222     return 0;
223 }
224
225 =head2 $template->save()
226
227     Invoking the I<save> method attempts to insert the template into the database if the template is new and
228     update the existing template record if the template exists. The method returns the new record template_id upon
229     success and -1 upon failure (This avotemplate_ids conflicting with a record template_id of 1). Errors are logged to the syslog.
230
231     example:
232         my $exitstat = $template->save(); # to save the record behind the $template object
233
234 =cut
235
236 sub save {
237     my $self = shift;
238     if ($self->{'template_id'}) {        # if we have an template_id, the record exists and needs UPDATE
239         my @params;
240         my $query = "UPDATE labels_templates SET ";
241         foreach my $key (keys %{$self}) {
242             next if ($key eq 'template_id') || ($key eq 'tmpl_stat');
243             push (@params, $self->{$key});
244             $query .= "$key=?, ";
245         }
246         $query = substr($query, 0, (length($query)-2));
247         push (@params, $self->{'template_id'});
248         $query .= " WHERE template_id=?;";
249         my $sth = C4::Context->dbh->prepare($query);
250         $sth->execute(@params);
251         if ($sth->err) {
252             syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
253             return -1;
254         }
255         $self->{'tmpl_stat'} = 1;
256         return $self->{'template_id'};
257     }
258     else {                      # otherwise create a new record
259         my @params;
260         my $query = "INSERT INTO labels_templates (";
261         foreach my $key (keys %{$self}) {
262             next if $key eq 'tmpl_stat';
263             push (@params, $self->{$key});
264             $query .= "$key, ";
265         }
266         $query = substr($query, 0, (length($query)-2));
267         $query .= ") VALUES (";
268         for (my $i=1; $i<=((scalar keys %$self) - 1); $i++) {   # key count less keys not db related...
269             $query .= "?,";
270         }
271         $query = substr($query, 0, (length($query)-1));
272         $query .= ");";
273         my $sth = C4::Context->dbh->prepare($query);
274         $sth->execute(@params);
275         if ($sth->err) {
276             syslog("LOG_ERR", "Database returned the following error: %s", $sth->errstr);
277             return -1;
278         }
279         my $sth1 = C4::Context->dbh->prepare("SELECT MAX(template_id) FROM labels_templates;");
280         $sth1->execute();
281         my $template_id = $sth1->fetchrow_array;
282         $self->{'template_id'} = $template_id;
283         $self->{'tmpl_stat'} = 1;
284         return $template_id;
285     }
286 }
287
288 =head2 $template->get_attr("attr")
289
290     Invoking the I<get_attr> method will return the value of the requested attribute or 1 on errors.
291
292     example:
293         my $value = $template->get_attr("attr");
294
295 =cut
296
297 sub get_attr {
298     my $self = shift;
299     if (_check_params(@_) eq 1) {
300         return -1;
301     }
302     my ($attr) = @_;
303     if (exists($self->{$attr})) {
304         return $self->{$attr};
305     }
306     else {
307         return -1;
308     }
309 }
310
311 =head2 $template->set_attr(attr, value)
312
313     Invoking the I<set_attr> method will set the value of the supplied attribute to the supplied value.
314
315     example:
316         $template->set_attr(attr => value);
317
318 =cut
319
320 sub set_attr {
321     my $self = shift;
322     if (_check_params(@_) eq 1) {
323         return -1;
324     }
325     my %attrs = @_;
326     foreach my $attrib (keys(%attrs)) {
327         $self->{$attrib} = $attrs{$attrib};
328     };
329 }
330
331 =head2 $template->get_label_position($start_label)
332
333     Invoking the I<get_label_position> method will return the row, column coordinates on the starting page
334     and the lower left x,y coordinates on the starting label for the template object.
335
336     examples:
337         my ($row_count, $col_count, $llx, $lly) = $template->get_label_position($start_label);
338
339 =cut
340
341 sub get_label_position {
342     my ($self, $start_label) = @_;
343     my ($row_count, $col_count, $llx, $lly) = 0,0,0,0;
344     if ($start_label eq 1) {
345         $row_count = 1;
346         $col_count = 1;
347         $llx = $self->{'left_margin'};
348         $lly = ($self->{'page_height'} - $self->{'top_margin'} - $self->{'label_height'});
349         return ($row_count, $col_count, $llx, $lly);
350     }
351     else {
352         $row_count = ceil($start_label / $self->{'cols'});
353         $col_count = ($start_label - (($row_count - 1) * $self->{'cols'}));
354         $llx = $self->{'left_margin'} + ($self->{'label_width'} * ($col_count - 1)) + ($self->{'col_gap'} * ($col_count - 1));
355         $lly = $self->{'page_height'} - $self->{'top_margin'} - ($self->{'label_height'} * $row_count) - ($self->{'row_gap'} * ($row_count - 1));
356         return ($row_count, $col_count, $llx, $lly);
357     }
358 }
359
360 1;
361 __END__
362
363 =head1 AUTHOR
364
365 Chris Nighswonger <cnighswonger AT foundations DOT edu>
366
367 =cut