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