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,
167 CLASS
=> $self->{'class'},
168 METHOD
=> scalar $self->{'cgi'}->param('method'),
169 PLUGIN_PATH
=> $self->get_plugin_http_path(),
170 PLUGIN_DIR
=> $self->bundle_path(),
171 LANG
=> C4
::Languages
::getlanguage
($self->{'cgi'}),
178 my ( $self, $args ) = @_;
180 #FIXME: Why another encoding issue? For metadata containing non latin characters.
181 my $metadata = $self->{metadata
};
182 $metadata->{$_} && 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'} ) );
220 go_home is a quick redirect to the Koha plugins home page
225 my ( $self, $params ) = @_;
227 print $self->{'cgi'}->redirect("/cgi-bin/koha/plugins/plugins-home.pl");
232 $self->output_html( $data, $status, $extra_options );
234 Outputs $data setting the right headers for HTML content.
236 Note: this is a wrapper function for C4::Output::output_with_http_headers
241 my ( $self, $data, $status, $extra_options ) = @_;
242 output_with_http_headers
( $self->{cgi
}, undef, $data, 'html', $status, $extra_options );
247 my $bundle_path = $self->bundle_path
249 Returns the directory in which bundled files are.
256 return $self->{_bundle_path
};
261 $self->output( $data, $content_type[, $status[, $extra_options]]);
263 Outputs $data with the appropriate HTTP headers,
264 the authentication cookie and a Content-Type specified in
267 $content_type is one of the following: 'html', 'js', 'json', 'xml', 'rss', or 'atom'.
269 $status is an HTTP status message, like '403 Authentication Required'. It defaults to '200 OK'.
271 $extra_options is hashref. If the key 'force_no_caching' is present and has
272 a true value, the HTTP headers include directives to force there to be no
275 Note: this is a wrapper function for C4::Output::output_with_http_headers
280 my ( $self, $data, $content_type, $status, $extra_options ) = @_;
281 output_with_http_headers
( $self->{cgi
}, undef, $data, $content_type, $status, $extra_options );
284 =head2 _version_compare
286 Utility method to compare two version numbers.
287 Returns 1 if the first argument is the higher version
288 Returns -1 if the first argument is the lower version
289 Returns 0 if both versions are equal
291 if ( _version_compare( '2.6.26', '2.6.0' ) == 1 ) {
292 print "2.6.26 is greater than 2.6.0\n";
297 sub _version_compare
{
300 if ( $args[0]->isa('Koha::Plugins::Base') ) {
304 my $ver1 = shift @args || 0;
305 my $ver2 = shift @args || 0;
307 my @v1 = split /[.+:~-]/, $ver1;
308 my @v2 = split /[.+:~-]/, $ver2;
310 for ( my $i = 0 ; $i < max
( scalar(@v1), scalar(@v2) ) ; $i++ ) {
312 # Add missing version parts if one string is shorter than the other
313 # i.e. 0 should be lt 0.2.1 and not equal, so we append .0
314 # 0.0.0 <=> 0.2.1 = -1
315 push( @v1, 0 ) unless defined( $v1[$i] );
316 push( @v2, 0 ) unless defined( $v2[$i] );
317 if ( int( $v1[$i] ) > int( $v2[$i] ) ) {
320 elsif ( int( $v1[$i] ) < int( $v2[$i] ) ) {
329 Method that returns wether the plugin is enabled or not
338 return $self->retrieve_data( '__ENABLED__' );
343 Method for enabling plugin
352 $self->store_data( {'__ENABLED__' => 1} );
359 Method for disabling plugin
368 $self->store_data( {'__ENABLED__' => 0} );
378 Kyle M Hall <kyle.m.hall@gmail.com>