Bug 11747 - DBrev 3.23.00.002
[koha.git] / C4 / Creators / Template.pm
blobccf3d571794763cb30c610e6dde17915830990c3
1 package C4::Creators::Template;
3 use strict;
4 use warnings;
5 use POSIX qw(ceil);
6 use autouse 'Data::Dumper' => qw(Dumper);
8 use C4::Context;
9 use C4::Debug;
10 use C4::Creators::Profile;
11 use C4::Creators::Lib qw(get_unit_values);
13 BEGIN {
14 use version; our $VERSION = qv('3.07.00.049');
17 sub _check_params {
18 shift if $_[0] =~ m/::/; # this seems a bit hackish
19 my $given_params = {};
20 my $exit_code = 0;
21 my @valid_template_params = (
22 'profile_id',
23 'template_code',
24 'template_desc',
25 'page_width',
26 'page_height',
27 'label_width',
28 'label_height',
29 'card_width',
30 'card_height',
31 'top_text_margin',
32 'left_text_margin',
33 'top_margin',
34 'left_margin',
35 'cols',
36 'rows',
37 'col_gap',
38 'row_gap',
39 'units',
40 'creator',
41 'current_label',
43 if (scalar(@_) >1) {
44 $given_params = {@_};
45 foreach my $key (keys %{$given_params}) {
46 if (!(grep m/$key/, @valid_template_params)) {
47 warn sprintf('Unrecognized parameter type of "%s".', $key);
48 $exit_code = 1;
52 else {
53 if (!(grep m/$_/, @valid_template_params)) {
54 warn sprintf('Unrecognized parameter type of "%s".', $_);
55 $exit_code = 1;
58 return $exit_code;
61 sub _conv_points {
62 my $self = shift;
63 my @unit_value = grep {$_->{'type'} eq $self->{'units'}} @{get_unit_values()};
64 $self->{'page_width'} = $self->{'page_width'} * $unit_value[0]->{'value'};
65 $self->{'page_height'} = $self->{'page_height'} * $unit_value[0]->{'value'};
66 $self->{'label_width'} = $self->{'label_width'} * $unit_value[0]->{'value'};
67 $self->{'label_height'} = $self->{'label_height'} * $unit_value[0]->{'value'};
68 $self->{'top_text_margin'} = $self->{'top_text_margin'} * $unit_value[0]->{'value'};
69 $self->{'left_text_margin'} = $self->{'left_text_margin'} * $unit_value[0]->{'value'};
70 $self->{'top_margin'} = $self->{'top_margin'} * $unit_value[0]->{'value'};
71 $self->{'left_margin'} = $self->{'left_margin'} * $unit_value[0]->{'value'};
72 $self->{'col_gap'} = $self->{'col_gap'} * $unit_value[0]->{'value'};
73 $self->{'row_gap'} = $self->{'row_gap'} * $unit_value[0]->{'value'};
74 return $self;
77 sub _apply_profile {
78 my $self = shift;
79 my $creator = shift;
80 my $profile = C4::Creators::Profile->retrieve(profile_id => $self->{'profile_id'}, creator => $creator, convert => 1);
81 $self->{'top_margin'} = $self->{'top_margin'} + $profile->get_attr('offset_vert'); # controls vertical offset
82 $self->{'left_margin'} = $self->{'left_margin'} + $profile->get_attr('offset_horz'); # controls horizontal offset
83 $self->{'label_height'} = $self->{'label_height'} + $profile->get_attr('creep_vert'); # controls vertical creep
84 $self->{'label_width'} = $self->{'label_width'} + $profile->get_attr('creep_horz'); # controls horizontal creep
85 return $self;
88 sub new {
89 my $invocant = shift;
90 my $type = ref($invocant) || $invocant;
91 if (_check_params(@_) eq 1) {
92 return -1;
94 my $self = {
95 profile_id => 0,
96 template_code => 'DEFAULT TEMPLATE',
97 template_desc => 'Default description',
98 page_width => 0,
99 page_height => 0,
100 label_width => 0,
101 label_height => 0,
102 top_text_margin => 0,
103 left_text_margin => 0,
104 top_margin => 0,
105 left_margin => 0,
106 cols => 0,
107 rows => 0,
108 col_gap => 0,
109 row_gap => 0,
110 units => 'POINT',
111 template_stat => 0, # false if any data has changed and the db has not been updated
114 bless ($self, $type);
115 return $self;
118 sub retrieve {
119 my $invocant = shift;
120 my %opts = @_;
121 my $type = ref($invocant) || $invocant;
122 my $query = "SELECT * FROM " . $opts{'table_name'} . " WHERE template_id = ? AND creator = ?";
123 my $sth = C4::Context->dbh->prepare($query);
124 $sth->execute($opts{'template_id'}, $opts{'creator'});
125 if ($sth->err) {
126 warn sprintf('Database returned the following error: %s', $sth->errstr);
127 return -1;
129 my $self = $sth->fetchrow_hashref;
130 $self = _conv_points($self) if (($opts{convert} && $opts{convert} == 1) || $opts{profile_id});
131 $self = _apply_profile($self, $opts{'creator'}) if $opts{profile_id} && $self->{'profile_id'}; # don't bother if there is no profile_id
132 $self->{'template_stat'} = 1;
133 bless ($self, $type);
134 return $self;
137 sub delete {
138 my $self = {};
139 my %opts = ();
140 my $call_type = '';
141 my @query_params = ();
142 if (ref($_[0])) {
143 $self = shift; # check to see if this is a method call
144 $call_type = 'C4::Labels::Template->delete';
145 push @query_params, $self->{'template_id'}, $self->{'creator'};
147 else {
148 %opts = @_;
149 $call_type = 'C4::Labels::Template::delete';
150 push @query_params, $opts{'template_id'}, $opts{'creator'};
152 if (scalar(@query_params) < 2) { # If there is no template id or creator type then we cannot delete it
153 warn sprintf('%s : Cannot delete template as the template id is invalid or non-existent.', $call_type) if !$query_params[0];
154 warn sprintf('%s : Cannot delete template as the creator type is invalid or non-existent.', $call_type) if !$query_params[1];
155 return -1;
157 my $query = "DELETE FROM creator_templates WHERE template_id = ? AND creator = ?";
158 my $sth = C4::Context->dbh->prepare($query);
159 $sth->execute(@query_params);
160 $self->{'template_stat'} = 0;
163 sub save {
164 my $self = shift;
165 my %opts = @_;
166 if ($self->{'template_id'}) { # if we have an template_id, the record exists and needs UPDATE
167 my @params;
168 my $query = "UPDATE " . $opts{'table_name'} . " SET ";
169 foreach my $key (keys %{$self}) {
170 next if ($key eq 'template_id') || ($key eq 'template_stat') || ($key eq 'creator');
171 push (@params, $self->{$key});
172 $query .= "$key=?, ";
174 $query = substr($query, 0, (length($query)-2));
175 push (@params, $self->{'template_id'}, $self->{'creator'});
176 $query .= " WHERE template_id=? AND creator=?;";
177 my $sth = C4::Context->dbh->prepare($query);
178 $sth->execute(@params);
179 if ($sth->err) {
180 warn sprintf('Database returned the following error: %s', $sth->errstr);
181 return -1;
183 $self->{'template_stat'} = 1;
184 return $self->{'template_id'};
186 else { # otherwise create a new record
187 my @params;
188 my $query = "INSERT INTO " . $opts{'table_name'} ." (";
189 foreach my $key (keys %{$self}) {
190 next if $key eq 'template_stat';
191 push (@params, $self->{$key});
192 $query .= "$key, ";
194 $query = substr($query, 0, (length($query)-2));
195 $query .= ") VALUES (";
196 for (my $i=1; $i<=((scalar keys %$self) - 1); $i++) { # key count less keys not db related...
197 $query .= "?,";
199 $query = substr($query, 0, (length($query)-1));
200 $query .= ");";
201 my $sth = C4::Context->dbh->prepare($query);
202 $sth->execute(@params);
203 if ($sth->err) {
204 warn sprintf('Database returned the following error: %s', $sth->errstr);
205 return -1;
207 my $sth1 = C4::Context->dbh->prepare("SELECT MAX(template_id) FROM " . $opts{'table_name'} . ";");
208 $sth1->execute();
209 my $template_id = $sth1->fetchrow_array;
210 $self->{'template_id'} = $template_id;
211 $self->{'template_stat'} = 1;
212 return $template_id;
216 sub get_attr {
217 my $self = shift;
218 if (_check_params(@_) eq 1) {
219 return -1;
221 my ($attr) = @_;
222 if (exists($self->{$attr})) {
223 return $self->{$attr};
225 else {
226 return -1;
230 sub set_attr {
231 my $self = shift;
232 if (_check_params(@_) eq 1) {
233 return -1;
235 my %attrs = @_;
236 foreach my $attrib (keys(%attrs)) {
237 $self->{$attrib} = $attrs{$attrib};
241 sub get_label_position {
242 my ($self, $start_label) = @_;
243 my $current_label = $self->{'current_label'};
244 if ($start_label eq 1) {
245 $current_label->{'row_count'} = 1;
246 $current_label->{'col_count'} = 1;
247 $current_label->{'llx'} = $self->{'left_margin'};
248 $current_label->{'lly'} = ($self->{'page_height'} - $self->{'top_margin'} - $self->{'label_height'});
249 $self->{'current_label'} = $current_label;
250 return ($current_label->{'row_count'}, $current_label->{'col_count'}, $current_label->{'llx'}, $current_label->{'lly'});
252 else {
253 $current_label->{'row_count'} = ceil($start_label / $self->{'cols'});
254 $current_label->{'col_count'} = ($start_label - (($current_label->{'row_count'} - 1) * $self->{'cols'}));
255 $current_label->{'llx'} = $self->{'left_margin'} + ($self->{'label_width'} * ($current_label->{'col_count'} - 1)) + ($self->{'col_gap'} * ($current_label->{'col_count'} - 1));
256 $current_label->{'lly'} = $self->{'page_height'} - $self->{'top_margin'} - ($self->{'label_height'} * $current_label->{'row_count'}) - ($self->{'row_gap'} * ($current_label->{'row_count'} - 1));
257 $self->{'current_label'} = $current_label;
258 return ($current_label->{'row_count'}, $current_label->{'col_count'}, $current_label->{'llx'}, $current_label->{'lly'});
262 sub get_next_label_pos {
263 my $self = shift;
264 my $current_label = $self->{'current_label'};
265 my $new_page = 0;
266 if ($current_label->{'col_count'} lt $self->get_attr('cols')) {
267 $current_label->{'llx'} = ($current_label->{'llx'} + $self->get_attr('label_width') + $self->get_attr('col_gap'));
268 $current_label->{'col_count'}++;
270 else {
271 $current_label->{'llx'} = $self->get_attr('left_margin');
272 if ($current_label->{'row_count'} eq $self->get_attr('rows')) {
273 $new_page = 1;
274 $current_label->{'lly'} = ($self->get_attr('page_height') - $self->get_attr('top_margin') - $self->get_attr('label_height'));
275 $current_label->{'row_count'} = 1;
277 else {
278 $current_label->{'lly'} = ($current_label->{'lly'} - $self->get_attr('row_gap') - $self->get_attr('label_height'));
279 $current_label->{'row_count'}++;
281 $current_label->{'col_count'} = 1;
283 return ($current_label->{'llx'}, $current_label->{'lly'}, $new_page);
287 __END__
289 =head1 NAME
291 C4::Creators::Template - A class for creating and manipulating template objects in Koha
293 =head1 ABSTRACT
295 This module provides methods for creating, retrieving, and otherwise manipulating label template objects used by Koha.
297 =head1 METHODS
299 =head2 new()
301 Invoking the I<new> method constructs a new template object containing the default values for a template.
302 The following parameters are optionally accepted as key => value pairs:
304 C<profile_id> A valid profile id to be assciated with this template. NOTE: The profile must exist in the database and B<not> be assigned to another template.
305 C<template_code> A template code. ie. 'Avery 5160 | 1 x 2-5/8'
306 C<template_desc> A readable description of the template. ie. '3 columns, 10 rows of labels'
307 C<page_width> The width of the page measured in the units supplied by the units parameter in this template.
308 C<page_height> The height of the page measured in the same units.
309 C<label_width> The width of a single label on the page this template applies to.
310 C<label_height> The height of a single label on the page.
311 C<top_text_margin> The measure of the top margin on a single label on the page.
312 C<left_text_margin> The measure of the left margin on a single label on the page.
313 C<top_margin> The measure of the top margin of the page.
314 C<left_margin> The measure of the left margin of the page.
315 C<cols> The number of columns of labels on the page.
316 C<rows> The number of rows of labels on the page.
317 C<col_gap> The measure of the gap between the columns of labels on the page.
318 C<row_gap> The measure of the gap between the rows of labels on the page.
319 C<units> The units of measure used for this template. These B<must> match the measures you supply above or
320 bad things will happen to your document. NOTE: The only supported units at present are:
322 =over 9
324 =item .
325 POINT = Postscript Points (This is the base unit in the Koha label creator.)
327 =item .
328 AGATE = Adobe Agates (5.1428571 points per)
330 =item .
331 INCH = US Inches (72 points per)
333 =item .
334 MM = SI Millimeters (2.83464567 points per)
336 =item .
337 CM = SI Centimeters (28.3464567 points per)
339 =back
341 example:
342 my $template = Template->new(); # Creates and returns a new template object with the defaults
344 my $template = C4::Labels::Template->new(profile_id => 1, page_width => 8.5, page_height => 11.0, units => 'INCH'); # Creates and returns a new template object using
345 the supplied values to override the defaults
347 B<NOTE:> This template is I<not> written to the database until save() is invoked. You have been warned!
349 =head2 retrieve(template_id => $template_id)
351 Invoking the I<retrieve> method constructs a new template object containing the current values for template_id. The method returns
352 a new object upon success and -1 upon failure. Errors are logged to the Apache log. Two further options may be accessed. See the example
353 below for further description.
355 examples:
357 C<my $template = C4::Labels::Template->retrieve(template_id => 1); # Retrieves template record 1 and returns an object containing the record>
359 C<my $template = C4::Labels::Template->retrieve(template_id => 1, convert => 1); # Retrieves template record 1, converts the units to points,
360 and returns an object containing the record>
362 C<my $template = C4::Labels::Template->retrieve(template_id => 1, profile_id => 1); # Retrieves template record 1, converts the units
363 to points, applies the currently associated profile id, and returns an object containing the record.>
365 =head2 delete()
367 Invoking the delete method attempts to delete the template from the database. The method returns -1 upon failure. Errors are logged to the Apache log.
368 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.
370 examples:
371 C<my $exitstat = $template->delete(); # to delete the record behind the $template object>
372 C<my $exitstat = C4::Labels::Template::delete(template_id => 1); # to delete template record 1>
374 =head2 save()
376 Invoking the I<save> method attempts to insert the template into the database if the template is new and update the existing template record if
377 the template exists. The method returns the new record template_id upon success and -1 upon failure (This avoids template_ids conflicting with a
378 record template_id of 1). Errors are logged to the Apache log.
380 example:
381 C<my $template_id = $template->save(); # to save the record behind the $template object>
383 =head2 get_attr($attribute)
385 Invoking the I<get_attr> method will return the value of the requested attribute or -1 on errors.
387 example:
388 C<my $value = $template->get_attr($attribute);>
390 =head2 set_attr(attribute => value, attribute_2 => value)
392 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
393 commas.
395 example:
396 C<$template->set_attr(attribute => value);>
398 =head2 get_label_position($start_label)
400 Invoking the I<get_label_position> method will return the row, column coordinates on the starting page and the lower left x,y coordinates on the starting
401 label for the template object.
403 examples:
404 C<my ($row_count, $col_count, $llx, $lly) = $template->get_label_position($start_label);>
406 =head1 AUTHOR
408 Chris Nighswonger <cnighswonger AT foundations DOT edu>
410 =head1 COPYRIGHT
412 Copyright 2009 Foundations Bible College.
414 =head1 LICENSE
416 This file is part of Koha.
418 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
419 Foundation; either version 2 of the License, or (at your option) any later version.
421 You should have received a copy of the GNU General Public License along with Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
422 Fifth Floor, Boston, MA 02110-1301 USA.
424 =head1 DISCLAIMER OF WARRANTY
426 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
427 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
429 =cut