Erste Version Template Toolkit Druck
[kivitendo-erp.git] / SL / Template / Simple.pm
1 #====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #====================================================================
8
9 package SL::Template::Simple;
10
11 use strict;
12
13 use Scalar::Util qw(blessed);
14
15 # Parameters:
16 #   1. The template's file name
17 #   2. A reference to the Form object
18 #   3. A reference to the myconfig hash
19 #
20 # Returns:
21 #   A new template object
22 sub new {
23   my $type = shift;
24   my $self = {};
25
26   bless($self, $type);
27   $self->_init(@_);
28
29   return $self;
30 }
31
32 sub _init {
33   my $self = shift;
34
35   $self->{source}    = shift;
36   $self->{form}      = shift;
37   $self->{myconfig}  = shift;
38   $self->{userspath} = shift;
39
40   $self->{error}     = undef;
41   $self->{quot_re}   = '"';
42
43   $self->set_tag_style('<%', '%>');
44 }
45
46 sub set_tag_style {
47   my $self                    = shift;
48   my $tag_start               = shift;
49   my $tag_end                 = shift;
50
51   $self->{tag_start}          = $tag_start;
52   $self->{tag_end}            = $tag_end;
53   $self->{tag_start_qm}       = quotemeta $tag_start;
54   $self->{tag_end_qm}         = quotemeta $tag_end;
55
56   $self->{substitute_vars_re} = "$self->{tag_start_qm}(.+?)$self->{tag_end_qm}";
57 }
58
59 sub set_use_template_toolkit {
60   my $self                    = shift;
61   my $value                   = shift;
62
63   $self->{use_template_toolkit} = $value;
64 }
65
66 sub cleanup {
67   my ($self) = @_;
68 }
69
70 # Parameters:
71 #   1. A typeglob for the file handle. The output will be written
72 #      to this file handle.
73 #
74 # Returns:
75 #   1 on success and undef or 0 if there was an error. In the latter case
76 #   the calling function can retrieve the error message via $obj->get_error()
77 sub parse {
78   my $self = $_[0];
79   local *OUT = $_[1];
80
81   print(OUT "Hallo!\n");
82 }
83
84 sub get_error {
85   my $self = shift;
86
87   return $self->{"error"};
88 }
89
90 sub uses_temp_file {
91   return 0;
92 }
93
94 sub _get_loop_variable {
95   my ($self, $var, $get_array, @indices) = @_;
96   my $form      = $self->{form};
97   my ($value, @methods);
98
99   if ($var =~ m/\./) {
100     ($var, @methods) = split m/\./, $var;
101   }
102
103   if (($get_array || @indices) && (ref $form->{TEMPLATE_ARRAYS} eq 'HASH') && (ref $form->{TEMPLATE_ARRAYS}->{$var} eq 'ARRAY')) {
104     $value = $form->{TEMPLATE_ARRAYS}->{$var};
105   } else {
106     $value = $form->{$var};
107   }
108
109   for (my $i = 0; $i < scalar(@indices); $i++) {
110     last unless (ref($value) eq "ARRAY");
111     $value = $value->[$indices[$i]];
112   }
113
114   for my $part (@methods) {
115     if (ref($value) =~ m/^(?:Form|HASH)$/) {
116       $value = $value->{$part};
117     } elsif (blessed($value) && $value->can($part)) {
118       $value = $value->$part;
119     } else {
120       $value = '';
121       last;
122     }
123   }
124
125   return $value;
126 }
127
128 sub substitute_vars {
129   my ($self, $text, @indices) = @_;
130
131   my $form = $self->{"form"};
132
133   while ($text =~ /$self->{substitute_vars_re}/) {
134     my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]);
135     my ($var, @option_list) = split(/\s+/, $1);
136     my %options             = map { ($_ => 1) } @option_list;
137
138     my $value               = $self->_get_loop_variable($var, 0, @indices);
139     $value                  = $form->parse_amount({ numberformat => $::myconfig{output_numberformat} || $::myconfig{numberformat} }, $value) if     $options{NOFORMAT};
140     $value                  = $self->format_string($value)                                                                                   unless $options{NOESCAPE};
141
142     substr($text, $tag_pos, $tag_len, $value);
143   }
144
145   return $text;
146 }
147
148 sub _parse_block_if {
149   $main::lxdebug->enter_sub();
150
151   my $self         = shift;
152   my $contents     = shift;
153   my $new_contents = shift;
154   my $pos_if       = shift;
155   my @indices      = @_;
156
157   $$new_contents .= $self->substitute_vars(substr($$contents, 0, $pos_if), @indices);
158   substr($$contents, 0, $pos_if) = "";
159
160   if ($$contents !~ m/^$self->{tag_start_qm}if
161                      \s*
162                      (not\b|\!)?           # $1 -- Eventuelle Negierung
163                      \s+
164                      (\b.+?\b)             # $2 -- Name der zu überprüfenden Variablen
165                      (                     # $3 -- Beginn des optionalen Vergleiches
166                        \s*
167                        ([!=])              # $4 -- Negierung des Vergleiches speichern
168                        ([=~])              # $5 -- Art des Vergleiches speichern
169                        \s*
170                        (                   # $6 -- Gequoteter String oder Bareword
171                          $self->{quot_re}
172                          (.*?)(?<!\\)      # $7 -- Gequoteter String -- direkter Vergleich mit eq bzw. ne oder Patternmatching; Escapete Anführungs als Teil des Strings belassen
173                          $self->{quot_re}
174                        |
175                          (\b.+?\b)         # $8 -- Bareword -- als Index für $form benutzen
176                        )
177                      )?
178                      \s*
179                      $self->{tag_end_qm}
180                     /x) {
181     $self->{"error"} = "Malformed $self->{tag_start}if$self->{tag_end}.";
182     $main::lxdebug->leave_sub();
183     return undef;
184   }
185
186   my $not           = $1;
187   my $var           = $2;
188   my $comparison    = $3; # Optionaler Match um $4..$8
189   my $operator_neg  = $4; # '=' oder '!' oder undef, wenn kein Vergleich erkannt
190   my $operator_type = $5; # '=' oder '~' für Stringvergleich oder Regex
191   my $quoted_word   = $7; # nur gültig, wenn quoted string angegeben (siehe unten); dann "value" aus <%if var == "value" %>
192   my $bareword      = $8; # undef, falls quoted string angegeben wurde; andernfalls "othervar" aus <%if var == othervar %>
193
194   $not = !$not if ($operator_neg && $operator_neg eq '!');
195
196   substr($$contents, 0, length($&)) = "";
197
198   my $block;
199   ($block, $$contents) = $self->find_end($$contents, 0, "$var $comparison", $not);
200   if (!$block) {
201     $self->{"error"} = "Unclosed $self->{tag_start}if$self->{tag_end}." unless ($self->{"error"});
202     $main::lxdebug->leave_sub();
203     return undef;
204   }
205
206   my $value = $self->_get_loop_variable($var, 0, @indices);
207   $value    = scalar(@{ $value }) if (ref($value) || '') eq 'ARRAY';
208   my $hit   = 0;
209
210   if ($operator_type) {
211     my $compare_to = $bareword ? $self->_get_loop_variable($bareword, 0, @indices) : $quoted_word;
212     if ($operator_type eq '=') {
213       $hit         = ($not && !($value eq $compare_to))     || (!$not && ($value eq $compare_to));
214     } else {
215       $hit         = ($not && !($value =~ m/$compare_to/i)) || (!$not && ($value =~ m/$compare_to/i));
216     }
217
218   } else {
219     $hit           = ($not && ! $value)                     || (!$not &&  $value);
220   }
221
222   if ($hit) {
223     my $new_text = $self->parse_block($block, @indices);
224     if (!defined($new_text)) {
225       $main::lxdebug->leave_sub();
226       return undef;
227     }
228     $$new_contents .= $new_text;
229   }
230
231   $main::lxdebug->leave_sub();
232
233   return 1;
234 }
235
236 1;