1 package Koha
::Plugins
::Base
;
3 # Copyright 2012 Kyle Hall
5 # This file is part of Koha.
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.
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.
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>.
22 use Module
::Pluggable
require => 1;
24 use List
::Util
qw(max);
26 use base
qw{Module
::Bundled
::Files
};
29 use C4
::Output
qw(output_with_http_headers output_html_with_http_headers);
33 Koha::Plugins::Base - Base Module for plugins
38 my ( $class, $args ) = @_;
40 return unless ( C4
::Context
->config("enable_plugins") || $args->{'enable_plugins'} );
42 $args->{'class'} = $class;
43 $args->{'template'} = Template
->new( { ABSOLUTE
=> 1, ENCODING
=> 'UTF-8' } );
45 my $self = bless( $args, $class );
47 my $plugin_version = $self->get_metadata->{version
};
48 my $database_version = $self->retrieve_data('__INSTALLED_VERSION__') || 0;
50 ## Run the installation method if it exists and hasn't been run before
51 if ( $self->can('install') && !$self->retrieve_data('__INSTALLED__') ) {
52 if ( $self->install() ) {
53 $self->store_data( { '__INSTALLED__' => 1, '__ENABLED__' => 1 } );
54 if ( my $version = $plugin_version ) {
55 $self->store_data({ '__INSTALLED_VERSION__' => $version });
58 warn "Plugin $class failed during installation!";
60 } elsif ( $self->can('upgrade') ) {
61 if ( _version_compare
( $plugin_version, $database_version ) == 1 ) {
62 if ( $self->upgrade() ) {
63 $self->store_data({ '__INSTALLED_VERSION__' => $plugin_version });
65 warn "Plugin $class failed during upgrade!";
68 } elsif ( $plugin_version ne $database_version ) {
69 $self->store_data({ '__INSTALLED_VERSION__' => $plugin_version });
72 $self->{_bundle_path
} = abs_path
($self->mbf_dir);
79 store_data allows a plugin to store key value pairs in the database for future use.
81 usage: $self->store_data({ param1 => 'param1val', param2 => 'param2value' })
86 my ( $self, $data ) = @_;
88 my $dbh = C4
::Context
->dbh;
89 my $sql = "REPLACE INTO plugin_data SET plugin_class = ?, plugin_key = ?, plugin_value = ?";
90 my $sth = $dbh->prepare($sql);
92 foreach my $key ( keys %$data ) {
93 $sth->execute( $self->{'class'}, $key, $data->{$key} );
99 retrieve_data allows a plugin to read the values that were previously saved with store_data
101 usage: my $value = $self->retrieve_data( $key );
106 my ( $self, $key ) = @_;
108 my $dbh = C4
::Context
->dbh;
109 my $sql = "SELECT plugin_value FROM plugin_data WHERE plugin_class = ? AND plugin_key = ?";
110 my $sth = $dbh->prepare($sql);
111 $sth->execute( $self->{'class'}, $key );
112 my $row = $sth->fetchrow_hashref();
114 return $row->{'plugin_value'};
119 get_template returns a Template object. Eventually this will probably be calling
120 C4:Template, but at the moment, it does not.
122 The returned template contains 3 variables that can be used in the plugin
129 The name of the plugin class.
133 Then name of the plugin method used. For example 'tool' or 'report'.
137 The URL path to the plugin. It can be used in templates in order to localize
138 ressources like images in html tags, or other templates.
142 The absolute pathname to the plugin directory. Necessary to include other
143 templates from a template with the [% INCLUDE %] directive.
151 my ( $self, $args ) = @_;
155 my $template_name = $args->{'file'} // '';
156 # if not absolute, call mbf_path, which dies if file does not exist
157 $template_name = $self->mbf_path( $template_name )
158 if $template_name !~ m/^\//;
159 my ( $template, $loggedinuser, $cookie ) = C4
::Auth
::get_template_and_user
(
160 { template_name
=> $template_name,
161 query
=> $self->{'cgi'},
163 authnotrequired
=> 1,
168 CLASS
=> $self->{'class'},
169 METHOD
=> scalar $self->{'cgi'}->param('method'),
170 PLUGIN_PATH
=> $self->get_plugin_http_path(),
171 PLUGIN_DIR
=> $self->get_plugin_dir(),
178 my ( $self, $args ) = @_;
180 #FIXME: Why another encoding issue? For metadata containing non latin characters.
181 my $metadata = $self->{metadata
};
182 utf8
::decode
($metadata->{$_}) for keys %$metadata;
186 =head2 get_qualified_table_name
188 To avoid naming conflict, each plugins tables should use a fully qualified namespace.
189 To avoid hardcoding and make plugins more flexible, this method will return the proper
190 fully qualified table name.
192 usage: my $table = $self->get_qualified_table_name( 'myTable' );
196 sub get_qualified_table_name
{
197 my ( $self, $table_name ) = @_;
199 return lc( join( '_', split( '::', $self->{'class'} ), $table_name ) );
202 =head2 get_plugin_http_path
204 To access a plugin's own resources ( images, js files, css files, etc... )
205 a plugin will need to know what path to use in the template files. This
206 method returns that path.
208 usage: my $path = $self->get_plugin_http_path();
212 sub get_plugin_http_path
{
215 return "/plugin/" . join( '/', split( '::', $self->{'class'} ) );
218 =head2 get_plugin_dir
220 To [% INCLUDE %] another TT template from a template, an absolute path to the
221 template is required. This method returns that absolute file system path.
223 usage: my $path = $self->get_plugin_dir();
230 my $base = C4
::Context
->config('pluginsdir');
231 return "$base/" . join( '/', split( '::', $self->{'class'} ) );
236 go_home is a quick redirect to the Koha plugins home page
241 my ( $self, $params ) = @_;
243 print $self->{'cgi'}->redirect("/cgi-bin/koha/plugins/plugins-home.pl");
248 $self->output_html( $data, $status, $extra_options );
250 Outputs $data setting the right headers for HTML content.
252 Note: this is a wrapper function for C4::Output::output_with_http_headers
257 my ( $self, $data, $status, $extra_options ) = @_;
258 output_with_http_headers
( $self->{cgi
}, undef, $data, 'html', $status, $extra_options );
263 my $bundle_path = $self->bundle_path
265 Returns the directory in which bundled files are.
272 return $self->{_bundle_path
};
277 $self->output( $data, $content_type[, $status[, $extra_options]]);
279 Outputs $data with the appropriate HTTP headers,
280 the authentication cookie and a Content-Type specified in
283 $content_type is one of the following: 'html', 'js', 'json', 'xml', 'rss', or 'atom'.
285 $status is an HTTP status message, like '403 Authentication Required'. It defaults to '200 OK'.
287 $extra_options is hashref. If the key 'force_no_caching' is present and has
288 a true value, the HTTP headers include directives to force there to be no
291 Note: this is a wrapper function for C4::Output::output_with_http_headers
296 my ( $self, $data, $content_type, $status, $extra_options ) = @_;
297 output_with_http_headers
( $self->{cgi
}, undef, $data, $content_type, $status, $extra_options );
300 =head2 _version_compare
302 Utility method to compare two version numbers.
303 Returns 1 if the first argument is the higher version
304 Returns -1 if the first argument is the lower version
305 Returns 0 if both versions are equal
307 if ( _version_compare( '2.6.26', '2.6.0' ) == 1 ) {
308 print "2.6.26 is greater than 2.6.0\n";
313 sub _version_compare
{
316 if ( $args[0]->isa('Koha::Plugins::Base') ) {
320 my $ver1 = shift @args || 0;
321 my $ver2 = shift @args || 0;
323 my @v1 = split /[.+:~-]/, $ver1;
324 my @v2 = split /[.+:~-]/, $ver2;
326 for ( my $i = 0 ; $i < max
( scalar(@v1), scalar(@v2) ) ; $i++ ) {
328 # Add missing version parts if one string is shorter than the other
329 # i.e. 0 should be lt 0.2.1 and not equal, so we append .0
330 # 0.0.0 <=> 0.2.1 = -1
331 push( @v1, 0 ) unless defined( $v1[$i] );
332 push( @v2, 0 ) unless defined( $v2[$i] );
333 if ( int( $v1[$i] ) > int( $v2[$i] ) ) {
336 elsif ( int( $v1[$i] ) < int( $v2[$i] ) ) {
345 Method that returns wether the plugin is enabled or not
354 return $self->retrieve_data( '__ENABLED__' );
359 Method for enabling plugin
368 $self->store_data( {'__ENABLED__' => 1} );
375 Method for disabling plugin
384 $self->store_data( {'__ENABLED__' => 0} );
394 Kyle M Hall <kyle.m.hall@gmail.com>