Bug 19223: Add methods to correctly handle plugin-generated output
[koha.git] / Koha / Plugins / Base.pm
1 package Koha::Plugins::Base;
2
3 # Copyright 2012 Kyle Hall
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use Module::Pluggable require => 1;
23 use Cwd qw(abs_path);
24
25 use base qw{Module::Bundled::Files};
26
27 use C4::Context;
28 use C4::Output qw(output_with_http_headers output_html_with_http_headers);
29
30 =head1 NAME
31
32 Koha::Plugins::Base - Base Module for plugins
33
34 =cut
35
36 sub new {
37     my ( $class, $args ) = @_;
38
39     return unless ( C4::Context->config("enable_plugins") || $args->{'enable_plugins'} );
40
41     $args->{'class'} = $class;
42     $args->{'template'} = Template->new( { ABSOLUTE => 1, ENCODING => 'UTF-8' } );
43
44     my $self = bless( $args, $class );
45
46     ## Run the installation method if it exists and hasn't been run before
47     if ( $self->can('install') && !$self->retrieve_data('__INSTALLED__') ) {
48         if ( $self->install() ) {
49             $self->store_data( { '__INSTALLED__' => 1 } );
50         } else {
51             warn "Plugin $class failed during installation!";
52         }
53     }
54
55     return $self;
56 }
57
58 =head2 store_data
59
60 store_data allows a plugin to store key value pairs in the database for future use.
61
62 usage: $self->store_data({ param1 => 'param1val', param2 => 'param2value' })
63
64 =cut
65
66 sub store_data {
67     my ( $self, $data ) = @_;
68
69     my $dbh = C4::Context->dbh;
70     my $sql = "REPLACE INTO plugin_data SET plugin_class = ?, plugin_key = ?, plugin_value = ?";
71     my $sth = $dbh->prepare($sql);
72
73     foreach my $key ( keys %$data ) {
74         $sth->execute( $self->{'class'}, $key, $data->{$key} );
75     }
76 }
77
78 =head2 retrieve_data
79
80 retrieve_data allows a plugin to read the values that were previously saved with store_data
81
82 usage: my $value = $self->retrieve_data( $key );
83
84 =cut
85
86 sub retrieve_data {
87     my ( $self, $key ) = @_;
88
89     my $dbh = C4::Context->dbh;
90     my $sql = "SELECT plugin_value FROM plugin_data WHERE plugin_class = ? AND plugin_key = ?";
91     my $sth = $dbh->prepare($sql);
92     $sth->execute( $self->{'class'}, $key );
93     my $row = $sth->fetchrow_hashref();
94
95     return $row->{'plugin_value'};
96 }
97
98 =head2 get_template
99
100 get_template returns a Template object. Eventually this will probably be calling
101 C4:Template, but at the moment, it does not.
102
103 =cut
104
105 sub get_template {
106     my ( $self, $args ) = @_;
107
108     require C4::Auth;
109
110     my $template_name = $args->{'file'} // '';
111     # if not absolute, call mbf_path, which dies if file does not exist
112     $template_name = $self->mbf_path( $template_name )
113         if $template_name !~ m/^\//;
114     my ( $template, $loggedinuser, $cookie ) = C4::Auth::get_template_and_user(
115         {   template_name   => $template_name,
116             query           => $self->{'cgi'},
117             type            => "intranet",
118             authnotrequired => 1,
119         }
120     );
121
122     $template->param(
123         CLASS       => $self->{'class'},
124         METHOD      => scalar $self->{'cgi'}->param('method'),
125         PLUGIN_PATH => $self->get_plugin_http_path(),
126     );
127
128     return $template;
129 }
130
131 sub get_metadata {
132     my ( $self, $args ) = @_;
133
134     return $self->{'metadata'};
135 }
136
137 =head2 get_qualified_table_name
138
139 To avoid naming conflict, each plugins tables should use a fully qualified namespace.
140 To avoid hardcoding and make plugins more flexible, this method will return the proper
141 fully qualified table name.
142
143 usage: my $table = $self->get_qualified_table_name( 'myTable' );
144
145 =cut
146
147 sub get_qualified_table_name {
148     my ( $self, $table_name ) = @_;
149
150     return lc( join( '_', split( '::', $self->{'class'} ), $table_name ) );
151 }
152
153 =head2 get_plugin_http_path
154
155 To access a plugin's own resources ( images, js files, css files, etc... )
156 a plugin will need to know what path to use in the template files. This
157 method returns that path.
158
159 usage: my $path = $self->get_plugin_http_path();
160
161 =cut
162
163 sub get_plugin_http_path {
164     my ($self) = @_;
165
166     return "/plugin/" . join( '/', split( '::', $self->{'class'} ) );
167 }
168
169 =head2 go_home
170
171    go_home is a quick redirect to the Koha plugins home page
172
173 =cut
174
175 sub go_home {
176     my ( $self, $params ) = @_;
177
178     print $self->{'cgi'}->redirect("/cgi-bin/koha/plugins/plugins-home.pl");
179 }
180
181 =head2 output_html
182
183     $self->output_html( $data, $status, $extra_options );
184
185 Outputs $data setting the right headers for HTML content.
186
187 Note: this is a wrapper function for C4::Output::output_with_http_headers
188
189 =cut
190
191 sub output_html {
192     my ( $self, $data, $status, $extra_options ) = @_;
193     output_with_http_headers( $self->{cgi}, undef, $data, 'html', $status, $extra_options );
194 }
195
196 =head2 output
197
198    $self->output( $data, $content_type[, $status[, $extra_options]]);
199
200 Outputs $data with the appropriate HTTP headers,
201 the authentication cookie and a Content-Type specified in
202 $content_type.
203
204 $content_type is one of the following: 'html', 'js', 'json', 'xml', 'rss', or 'atom'.
205
206 $status is an HTTP status message, like '403 Authentication Required'. It defaults to '200 OK'.
207
208 $extra_options is hashref.  If the key 'force_no_caching' is present and has
209 a true value, the HTTP headers include directives to force there to be no
210 caching whatsoever.
211
212 Note: this is a wrapper function for C4::Output::output_with_http_headers
213
214 =cut
215
216 sub output {
217     my ( $self, $data, $content_type, $status, $extra_options ) = @_;
218     output_with_http_headers( $self->{cgi}, undef, $data, $content_type, $status, $extra_options );
219 }
220
221 1;
222 __END__
223
224 =head1 AUTHOR
225
226 Kyle M Hall <kyle.m.hall@gmail.com>
227
228 =cut