Bug 22770: DBRev 19.06.00.004
[koha.git] / Koha / Misc / Files.pm
1 package Koha::Misc::Files;
2
3 # This file is part of Koha.
4 #
5 # Copyright 2012 Kyle M Hall
6 # Copyright 2014 Jacek Ablewicz
7 # Based on Koha/Borrower/Files.pm by Kyle M Hall
8 #
9 # Koha is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # Koha is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with Koha; if not, see <http://www.gnu.org/licenses>.
21
22 use Modern::Perl;
23
24 use C4::Context;
25 use C4::Output;
26
27 =head1 NAME
28
29 Koha::Misc::Files - module for managing miscellaneous files associated
30 with records from arbitrary tables
31
32 =head1 SYNOPSIS
33
34 use Koha::Misc::Files;
35
36 my $mf = Koha::Misc::Files->new( tabletag => $tablename,
37     recordid => $recordnumber );
38
39 =head1 FUNCTIONS
40
41 =over
42
43 =item new()
44
45 my $mf = Koha::Misc::Files->new( tabletag => $tablename,
46     recordid => $recordnumber );
47
48 Creates new Koha::Misc::Files object. Such object is essentially
49 a pair: in typical usage scenario, 'tabletag' parameter will be
50 a database table name, and 'recordid' an unique record ID number
51 from this table. However, this method does accept an arbitrary
52 string as 'tabletag', and an arbitrary integer as 'recordid'.
53
54 Particular Koha::Misc::Files object can have one or more file records
55 (actuall file contents + various file metadata) associated with it.
56
57 In case of an error (wrong parameter format) it returns undef.
58
59 =cut
60
61 sub new {
62     my ( $class, %args ) = @_;
63
64     my $recid = $args{'recordid'};
65     my $tag   = $args{'tabletag'};
66     ( defined($tag) && $tag ne '' && defined($recid) && $recid =~ /^\d+$/ )
67       || return ();
68
69     my $self = bless( {}, $class );
70
71     $self->{'table_tag'} = $tag;
72     $self->{'record_id'} = '' . ( 0 + $recid );
73
74     return $self;
75 }
76
77 =item GetFilesInfo()
78
79 my $files_descriptions = $mf->GetFilesInfo();
80
81 This method returns a reference to an array of hashes
82 containing files metadata (file_id, file_name, file_type,
83 file_description, file_size, date_uploaded) for all file records
84 associated with given $mf object, or an empty arrayref if there are
85 no such records yet.
86
87 In case of an error it returns undef.
88
89 =cut
90
91 sub GetFilesInfo {
92     my $self = shift;
93
94     my $dbh   = C4::Context->dbh;
95     my $query = '
96         SELECT
97             file_id,
98             file_name,
99             file_type,
100             file_description,
101             date_uploaded,
102             LENGTH(file_content) AS file_size
103         FROM misc_files
104         WHERE table_tag = ? AND record_id = ?
105         ORDER BY file_name, date_uploaded
106     ';
107     my $sth = $dbh->prepare($query);
108     $sth->execute( $self->{'table_tag'}, $self->{'record_id'} );
109     return $sth->fetchall_arrayref( {} );
110 }
111
112 =item AddFile()
113
114 $mf->AddFile( name => $filename, type => $mimetype,
115     description => $description, content => $content );
116
117 Adds a new file (we want to store for / associate with a given
118 object) to the database. Parameters 'name' and 'content' are mandatory.
119 Note: this method would (silently) fail if there is no 'name' given
120 or if the 'content' provided is empty.
121
122 =cut
123
124 sub AddFile {
125     my ( $self, %args ) = @_;
126
127     my $name        = $args{'name'};
128     my $type        = $args{'type'} // '';
129     my $description = $args{'description'};
130     my $content     = $args{'content'};
131
132     return unless ( defined($name) && $name ne '' && defined($content) && $content ne '' );
133
134     my $dbh   = C4::Context->dbh;
135     my $query = '
136         INSERT INTO misc_files ( table_tag, record_id, file_name, file_type, file_description, file_content )
137         VALUES ( ?,?,?,?,?,? )
138     ';
139     my $sth = $dbh->prepare($query);
140     $sth->execute( $self->{'table_tag'}, $self->{'record_id'}, $name, $type,
141         $description, $content );
142 }
143
144 =item GetFile()
145
146 my $file = $mf->GetFile( id => $file_id );
147
148 For an individual, specific file ID this method returns a hashref
149 containing all metadata (file_id, table_tag, record_id, file_name,
150 file_type, file_description, file_content, date_uploaded), plus
151 an actuall contents of a file (in 'file_content'). In typical usage
152 scenarios, for a given $mf object, specific file IDs have to be
153 obtained first by GetFilesInfo() call.
154
155 Returns undef in case when file ID specified as 'id' parameter was not
156 found in the database.
157
158 =cut
159
160 sub GetFile {
161     my ( $self, %args ) = @_;
162
163     my $file_id = $args{'id'};
164
165     my $dbh   = C4::Context->dbh;
166     my $query = '
167         SELECT * FROM misc_files WHERE file_id = ? AND table_tag = ? AND record_id = ?
168     ';
169     my $sth = $dbh->prepare($query);
170     $sth->execute( $file_id, $self->{'table_tag'}, $self->{'record_id'} );
171     return $sth->fetchrow_hashref();
172 }
173
174 =item DelFile()
175
176 $mf->DelFile( id => $file_id );
177
178 Deletes specific, individual file record (file contents and metadata)
179 from the database.
180
181 =cut
182
183 sub DelFile {
184     my ( $self, %args ) = @_;
185
186     my $file_id = $args{'id'};
187
188     my $dbh   = C4::Context->dbh;
189     my $query = '
190         DELETE FROM misc_files WHERE file_id = ? AND table_tag = ? AND record_id = ?
191     ';
192     my $sth = $dbh->prepare($query);
193     $sth->execute( $file_id, $self->{'table_tag'}, $self->{'record_id'} );
194 }
195
196 =item DelAllFiles()
197
198 $mf->DelAllFiles();
199
200 Deletes all file records associated with (stored for) a given $mf object.
201
202 =cut
203
204 sub DelAllFiles {
205     my ($self) = @_;
206
207     my $dbh   = C4::Context->dbh;
208     my $query = '
209         DELETE FROM misc_files WHERE table_tag = ? AND record_id = ?
210     ';
211     my $sth = $dbh->prepare($query);
212     $sth->execute( $self->{'table_tag'}, $self->{'record_id'} );
213 }
214
215 =item MergeFileRecIds()
216
217 $mf->MergeFileRecIds(@ids_to_be_merged);
218
219 This method re-associates all individuall file records associated with
220 some "parent" records IDs (provided in @ids_to_be_merged) with the given
221 single $mf object (which would be treated as a "parent" destination).
222
223 This a helper method; typically it needs to be called only in cases when
224 some "parent" records are being merged in the (external) 'tablename'
225 table.
226
227 =cut
228
229 sub MergeFileRecIds {
230     my ( $self, @ids_to_merge ) = @_;
231
232     my $dst_recid = $self->{'record_id'};
233     @ids_to_merge = map { ( $dst_recid == $_ ) ? () : ($_); } @ids_to_merge;
234     @ids_to_merge > 0 || return ();
235
236     my $dbh   = C4::Context->dbh;
237     my $query = '
238         UPDATE misc_files SET record_id = ?
239         WHERE table_tag = ? AND record_id = ?
240     ';
241     my $sth = $dbh->prepare($query);
242
243     for my $src_recid (@ids_to_merge) {
244         $sth->execute( $dst_recid, $self->{'table_tag'}, $src_recid );
245     }
246 }
247
248 1;
249
250 __END__
251
252 =back
253
254 =head1 SEE ALSO
255
256 Koha::Patron::Files
257
258 =head1 AUTHOR
259
260 Kyle M Hall E<lt>kyle.m.hall@gmail.comE<gt>,
261 Jacek Ablewicz E<lt>ablewicz@gmail.comE<gt>
262
263 =cut