Bug 29697: Use flag embed_items
[koha.git] / Koha / OAI / Server / Repository.pm
1 # Copyright Tamil s.a.r.l. 2008-2015
2 # Copyright Biblibre 2008-2015
3 # Copyright The National Library of Finland, University of Helsinki 2016
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 package Koha::OAI::Server::Repository;
21
22 use Modern::Perl;
23 use HTTP::OAI;
24 use HTTP::OAI::Repository qw( validate_request );
25
26 use base ("HTTP::OAI::Repository");
27
28 use Koha::OAI::Server::Identify;
29 use Koha::OAI::Server::ListSets;
30 use Koha::OAI::Server::ListMetadataFormats;
31 use Koha::OAI::Server::GetRecord;
32 use Koha::OAI::Server::ListRecords;
33 use Koha::OAI::Server::ListIdentifiers;
34 use XML::SAX::Writer;
35 use YAML::XS;
36 use CGI qw/:standard -oldstyle_urls/;
37 use C4::Context;
38 use C4::XSLT qw( transformMARCXML4XSLT );
39 use Koha::XSLT::Base;
40 use Koha::Biblios;
41
42 =head1 NAME
43
44 Koha::OAI::Server::Repository - Handles OAI-PMH requests for a Koha database.
45
46 =head1 SYNOPSIS
47
48   use Koha::OAI::Server::Repository;
49
50   my $repository = Koha::OAI::Server::Repository->new();
51
52 =head1 DESCRIPTION
53
54 This object extend HTTP::OAI::Repository object.
55 It accepts OAI-PMH HTTP requests and returns result.
56
57 This OAI-PMH server can operate in a simple mode and extended one.
58
59 In simple mode, repository configuration comes entirely from Koha system
60 preferences (OAI-PMH:archiveID and OAI-PMH:MaxCount) and the server returns
61 records in marcxml or dublin core format. Dublin core records are created from
62 koha marcxml records transformed with XSLT. Used XSL file is located in koha-
63 tmpl/intranet-tmpl/prog/en/xslt directory and chosen based on marcflavour,
64 respecively MARC21slim2OAIDC.xsl for MARC21 and  MARC21slim2OAIDC.xsl for
65 UNIMARC.
66
67 In extended mode, it's possible to parameter other format than marcxml or
68 Dublin Core. A new syspref OAI-PMH:ConfFile specify a YAML configuration file
69 which list available metadata formats and XSL file used to create them from
70 marcxml records. If this syspref isn't set, Koha OAI server works in simple
71 mode. A configuration file koha-oai.conf can look like that:
72
73   ---
74   format:
75     vs:
76       metadataPrefix: vs
77       metadataNamespace: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs
78       schema: http://veryspecial.tamil.fr/vs/format-pivot/1.1/vs.xsd
79       xsl_file: /usr/local/koha/xslt/vs.xsl
80     marc21:
81       metadataPrefix: marc21
82       metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
83       schema: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
84       include_items: 1
85     marcxml:
86       metadataPrefix: marcxml
87       metadataNamespace: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim
88       schema: http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
89       include_items: 1
90       expanded_avs: 1
91     oai_dc:
92       metadataPrefix: oai_dc
93       metadataNamespace: http://www.openarchives.org/OAI/2.0/oai_dc/
94       schema: http://www.openarchives.org/OAI/2.0/oai_dc.xsd
95       xsl_file: /usr/local/koha/koha-tmpl/intranet-tmpl/xslt/UNIMARCslim2OAIDC.xsl
96
97 Note the 'include_items' parameter which is the only mean to return item-level info.
98
99 =cut
100
101
102 sub new {
103     my ($class, %args) = @_;
104     my $self = $class->SUPER::new(%args);
105
106     $self->{ koha_identifier      } = C4::Context->preference("OAI-PMH:archiveID");
107     $self->{ koha_max_count       } = C4::Context->preference("OAI-PMH:MaxCount");
108     $self->{ koha_metadata_format } = ['oai_dc', 'marc21', 'marcxml'];
109     $self->{ xslt_engine          } = Koha::XSLT::Base->new;
110
111     # Load configuration file if defined in OAI-PMH:ConfFile syspref
112     if ( my $file = C4::Context->preference("OAI-PMH:ConfFile") ) {
113         $self->{ conf } = YAML::XS::LoadFile( $file );
114         my @formats = keys %{ $self->{conf}->{format} };
115         $self->{ koha_metadata_format } =  \@formats;
116     }
117
118     # OAI-PMH handles dates in UTC, so do that on the database level to avoid need for
119     # any conversions
120     my $sth = C4::Context->dbh->prepare('SELECT @@session.time_zone');
121     $sth->execute();
122     my ( $orig_tz ) = $sth->fetchrow();
123     $self->{ mysql_orig_tz } = $orig_tz;
124     C4::Context->dbh->prepare("SET time_zone='+00:00'")->execute();
125
126     # Check for grammatical errors in the request
127     my @errs = validate_request( CGI::Vars() );
128
129     # Is metadataPrefix supported by the repository?
130     my $mdp = param('metadataPrefix') || '';
131     if ( $mdp && !grep { $_ eq $mdp } @{$self->{ koha_metadata_format }} ) {
132         push @errs, HTTP::OAI::Error->new(
133             code    => 'cannotDisseminateFormat',
134             message => "Dissemination as '$mdp' is not supported",
135         );
136     }
137
138     my $response;
139     if ( @errs ) {
140         $response = HTTP::OAI::Response->new(
141             requestURL  => self_url(),
142             errors      => \@errs,
143         );
144     }
145     else {
146         my %attr = CGI::Vars();
147         my $verb = delete $attr{verb};
148         my $class = "Koha::OAI::Server::$verb";
149         $response = $class->new($self, %attr);
150     }
151
152     $response->set_handler( XML::SAX::Writer->new( Output => *STDOUT ) );
153     $response->xslt( "/opac-tmpl/xslt/OAI.xslt" );
154     $response->generate;
155
156     bless $self, $class;
157     return $self;
158 }
159
160
161 sub DESTROY {
162     my ( $self ) = @_;
163
164     # Reset time zone to the original value
165     C4::Context->dbh->prepare("SET time_zone='" . $self->{ mysql_orig_tz } . "'")->execute()
166         if $self->{ mysql_orig_tz };
167 }
168
169
170 sub get_biblio_marcxml {
171     my ( $self, $biblionumber, $format ) = @_;
172     my $with_items   = 0;
173     my $expanded_avs = 0;
174     if ( my $conf = $self->{conf} ) {
175         $with_items   = $conf->{format}->{$format}->{include_items  };
176         $expanded_avs = $conf->{format}->{$format}->{expanded_avs};
177     }
178
179     my $biblio = Koha::Biblios->find($biblionumber);
180     my $record = $biblio->metadata->record({ embed_items => $with_items, opac => 1 });
181     $record = transformMARCXML4XSLT( $biblionumber, $record )
182         if $expanded_avs;
183
184     return $record ? $record->as_xml_record() : undef;
185 }
186
187
188 sub stylesheet {
189     my ( $self, $format ) = @_;
190     my $xsl_file = $self->{ conf }
191         ? $self->{ conf }->{ format }->{ $format }->{ xsl_file }
192         : ( C4::Context->config('intrahtdocs') .
193             '/prog/en/xslt/' .
194             C4::Context->preference('marcflavour') .
195             'slim2OAIDC.xsl'
196     );
197     return $xsl_file;
198 }
199
200
201 sub items_included {
202     my ( $self, $format ) = @_;
203
204     if ( my $conf = $self->{ conf } ) {
205         return $conf->{ format }->{ $format }->{ include_items };
206     }
207     return 0;
208 }
209
210 1;