File Coverage

blib/lib/WE/DB/Content.pm
Criterion Covered Total %
statement 12 109 11.0
branch 0 60 0.0
condition 0 3 0.0
subroutine 4 17 23.5
pod 12 12 100.0
total 28 201 13.9


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # $Id: Content.pm,v 1.9 2005/02/02 22:13:43 eserte Exp $
5             # Author: Slaven Rezic
6             #
7             # Copyright (C) 2001 Online Office Berlin. All rights reserved.
8             # Copyright (C) 2002,2005 Slaven Rezic.
9             # This is free software; you can redistribute it and/or modify it under the
10             # terms of the GNU General Public License, see the file COPYING.
11              
12             #
13             # Mail: slaven@rezic.de
14             # WWW: http://we-framework.sourceforge.net
15             #
16              
17             package WE::DB::Content;
18              
19             =head1 NAME
20              
21             WE::DB::Content - the content database for the web.editor
22              
23             =head1 SYNOPSIS
24              
25             $content_db = new WE::DB::Content($root, $content_db_directory);
26              
27             =head1 DESCRIPTION
28              
29             The content database contains the real contents (HTML, text, images)
30             of the objects in the object database.
31              
32             =cut
33              
34 1     1   836 use base qw/Class::Accessor/;
  1         2  
  1         78  
35              
36             __PACKAGE__->mk_accessors(qw/Root Directory/);
37              
38 1     1   5 use strict;
  1         2  
  1         37  
39 1     1   5 use vars qw($VERSION $VERBOSE);
  1         2  
  1         66  
40             $VERSION = sprintf("%d.%02d", q$Revision: 1.9 $ =~ /(\d+)\.(\d+)/);
41              
42 1     1   5 use WE::Util::MIME qw(%mime_types);
  1         2  
  1         1337  
43              
44             =head2 CONSTRUCTOR WE::DB::Content->new($root, $directory);
45              
46             The Content database is usually created in the C object.
47              
48             =cut
49              
50             sub new {
51 0     0 1   my($class, $root, $directory) = @_;
52 0           my $self = {};
53 0           bless $self, $class;
54 0           $self->Root($root);
55 0           $self->Directory($directory);
56 0           $self;
57             }
58              
59             =head2 METHODS
60              
61             =over 4
62              
63             =item init
64              
65             Initializes the content database. This means that the directory
66             holding the content files is created.
67              
68             =cut
69              
70             sub init {
71 0     0 1   my($self) = @_;
72              
73 0 0         if (!defined $self->Directory) {
74 0           die "The directory is not defined!";
75             }
76              
77 0 0         if (!-d $self->Directory) {
78 0           require File::Path;
79 0           File::Path::mkpath([$self->Directory], 0, 0770);
80             }
81              
82 0 0         if (!-w $self->Directory) {
83 0           die "Can't write to directory @{[ $self->Directory ]}";
  0            
84             }
85             }
86              
87             =item store($objid, $content)
88              
89             Store the $content (which is a string) for object with id $objid. Dies
90             on failure. Existing content is not overwritten in case of errors.
91              
92             =cut
93              
94             sub store {
95 0     0 1   my($self, $obj, $content) = @_;
96 0           my $file = $self->filename($obj);
97 0           my $tempfile = "$file~";
98 0 0         if (!defined $content) {
99 0           unlink $file;
100             } else {
101 0           my(@oldstat) = stat $file;
102 0 0         open(C, ">$tempfile") or die "Can't write to file $tempfile: $!";
103 0 0         print C $content or die "Can't write content to file $tempfile: $!";
104 0 0         close C or die "Error while writing $tempfile: $!";
105 0 0         if (@oldstat) {
106             # try to preserve ownership and mode
107 0           eval {
108 0           chown -1, $oldstat[5], $tempfile;
109             };
110 0           eval {
111 0           chown $oldstat[4], -1, $tempfile;
112             };
113 0           chmod $oldstat[2] & 07777, $tempfile;
114             }
115 0 0         rename $tempfile, $file or die "Can't rename $tempfile to $file: $!";
116             }
117             }
118              
119             =item get_content($objid)
120              
121             Get the content for object with id $objid. The content is returned as
122             a string.
123              
124             =cut
125              
126             sub get_content {
127 0     0 1   my($self, $obj) = @_;
128 0           my $file = $self->filename($obj);
129 0 0         open(C, $file) or die "Can't read file $file: $!";
130 0           local $/ = undef;
131 0           my $content = ;
132 0           close C;
133 0           $content;
134             }
135              
136             =item remove($objid)
137              
138             Remove the content for object with id $objid.
139              
140             =cut
141              
142             sub remove {
143 0     0 1   my($self, $obj) = @_;
144 0           my $file = $self->filename($obj);
145 0           unlink $file;
146             }
147              
148             =item copy($from_objid, $to_objid)
149              
150             Copy the content from $from_objid to $to_objid. This may be
151             implemented efficiently using OS copy. Dies on failure.
152              
153             =cut
154              
155             sub copy {
156 0     0 1   my($self, $from_objid, $to_objid) = @_;
157 0 0         if (eval 'require File::Copy; 1') {
158 0           my $from_filename = $self->filename($from_objid);
159 0           my $to_filename = $self->filename($to_objid);
160 0 0         File::Copy::copy($from_filename, $to_filename)
161             or "Can't copy <$from_filename> to <$to_filename>: $!";
162             } else {
163 0           my $content = $self->get_content($from_objid);
164 0           $self->store($to_objid, $content);
165             }
166             }
167              
168             =item filename($objid)
169              
170             Return the absolute filename for the object with id $objid (or supply the
171             WE::Obj). Usually, the content should not be accessed directly. But we
172             are Perl, so it is possible nevertheless.
173              
174             =cut
175              
176             sub filename {
177 0     0 1   my($self, $obj) = @_;
178 0           my($ext, $id);
179 0 0         if (!UNIVERSAL::isa($obj, "WE::Obj")) {
180 0           $id = $obj;
181 0           $obj = $self->Root->ObjDB->get_object($id);
182 0 0         die "Can't get object for id $id" if !$obj;
183             }
184 0           $id = $obj->Id;
185 0           $id =~ s/\D/_/g; # only safe characters
186 0           $ext = _extension($obj->ContentType);
187 0           $self->Directory . "/" . $id . "." . $ext;
188             }
189              
190             =item extension($obj)
191              
192             Return the extension of the supplied C object.
193              
194             =cut
195              
196             sub extension {
197 0     0 1   my($self, $obj) = @_;
198 0           _extension($obj->ContentType);
199             }
200              
201             # XXX move real implementation to Util module!
202             sub _extension {
203 0     0     my($mimetype) = @_;
204 0 0         my $ext = exists $mime_types{$mimetype} ? $mime_types{$mimetype}->[0] : undef;
205 0 0         if (!defined $ext) {
206             # fallback...
207 0 0         if (eval 'require MIME::Types; 1') {
208 0           my @ext = MIME::Types::by_mediatype($mimetype);
209 0 0         $ext = $ext[0]->[0] if @ext;
210             }
211             }
212 0 0         if (!defined $ext) {
213 0 0         warn "Cannot get extension for mime type $mimetype" if $VERBOSE;
214 0           $ext = "bin";
215             }
216 0           $ext;
217             }
218              
219             =item get_mime_type_by_filename($filename)
220              
221             Return the MIME type (e.g. C) of the supplied file.
222              
223             =cut
224              
225             sub get_mime_type_by_filename {
226 0     0 1   my($self, $filename) = @_;
227 0           WE::Util::MIME::get_mime_type_by_filename($filename);
228             }
229              
230             =item delete_db_contents
231              
232             Delete all database contents
233              
234             =cut
235              
236             sub delete_db_contents {
237 0     0 1   my $self = shift;
238 0 0 0       return unless defined $self->Directory || !-d $self->Directory;
239 0           opendir(D, $self->Directory);
240 0           while(my $f = readdir D) {
241 0 0         next if $f =~ /^\.\.?$/;
242 0 0         unlink $self->Directory ."/". $f or warn "Can't delete $f: $!";
243             }
244 0           closedir D;
245             }
246              
247             =item search_fulltext($term, %args)
248              
249             Search the term in the content database and return a list of object
250             ids. Further options are:
251              
252             =over 4
253              
254             =item -scope => $id
255              
256             Id of the scope for the search.
257              
258             =item -lang => $lang
259              
260             Restrict search to the specified language. Otherwise all languages are
261             used. NYI.
262              
263             =item -casesensitive => $bool
264              
265             True, if the search should be case sensitive.
266              
267             =item -regexp => $bool
268              
269             True, if the search term is a regular expression.
270              
271             =back
272              
273             =cut
274              
275             sub search_fulltext {
276 0     0 1   my($self, $term, %args) = @_;
277              
278 0 0         my $obj = (defined $args{-scope}
279             ? $self->Root->ObjDB->get_object($args{-scope})
280             : $self->Root->ObjDB->root_object);
281 0 0         if (!$obj) {
282 0           die "Cannot get scoped object";
283             }
284              
285 0 0         if (!$args{-regexp}) {
286 0           $term = "\Q$term";
287             }
288 0 0         if (!$args{-casesensitive}) {
289 0           $term = "(?i)$term";
290             }
291              
292 0           delete $args{-scope};
293 0           $self->search_fulltext_in_object($obj, $term, %args);
294             }
295              
296             =item search_fulltext_in_object($obj, $term)
297              
298             Search C<$term> (treated as a regular expression) in the content
299             database recusively starting from the L object C<$obj> and
300             return a list of object ids. If C<$obj> is a non-folder object, then
301             only this object is searched.
302              
303             =cut
304              
305             sub search_fulltext_in_object {
306 0     0 1   my($self, $obj, $term, %args) = @_;
307 0           my @res_ids;
308 0 0         if ($obj->is_folder) {
    0          
309 0           foreach my $s_obj ($self->Root->ObjDB->children($obj)) {
310 0           push @res_ids, $self->search_fulltext_in_object($s_obj, $term, %args);
311             }
312             } elsif ($obj->is_doc) {
313 0           push @res_ids, $obj->Id
314 0 0         if grep { $_ =~ /$term/s } $self->get_content($obj->Id);
315             }
316 0           @res_ids;
317             }
318              
319             1;
320              
321             __END__