the metadata fetcher
[bse.git] / site / cgi-bin / modules / BSE / MetaOwnerBase.pm
index 9935820..f6bb2fe 100644 (file)
@@ -1,44 +1,40 @@
 package BSE::MetaOwnerBase;
 use strict;
+use Carp 'confess';
 
-our $VERSION = "1.000";
+our $VERSION = "1.005";
 
-sub clear_metadata {
-  my ($self) = @_;
+=head1 NAME
 
-  BSE::DB->run(bseClearArticleFileMetadata => $self->id, $self->meta_owner_type);
-}
+BSE::MetaOwnerBase - mix-in for objects that have metadata.
 
-sub clear_app_metadata {
-  my ($self) = @_;
+=head1 SYNOPSIS
 
-  BSE::DB->run(bseClearArticleFileAppMetadata => $self->id, $self->meta_owner_type);
-}
+  my $file = ...
+  my @meta = $file->metadata;
+  my @text = $file->text_metadata;
+  my $meta = $file->meta_by_name($name);
+  my @names = $file->metanames;
+  my @info = $file->metainfo;
+  my @config = $file->meta_config;
 
-sub clear_sys_metadata {
-  my ($self) = @_;
+=head1 DESCRIPTION
 
-  BSE::DB->run(bseClearArticleFileSysMetadata => $self->id, $self->meta_owner_type);
-}
+Provides generic metadata support methods.  These can be called on any
+L<BSE::TB::ArticleFile> object, and possibly other objects in the
+future.
 
-sub delete_meta_by_name {
-  my ($self, $name) = @_;
+=head1 PUBLIC METHODS
 
-print STDERR "Delete ", $self->id, ",", $name, ",", $self->meta_owner_type, ")\n";
-  BSE::DB->run(bseDeleteArticleFileMetaByName => $self->id, $name, $self->meta_owner_type);
-}
+These can be called from anywhere, including templates:
 
-sub add_meta {
-  my ($self, %opts) = @_;
+=over
 
-  require BSE::TB::Metadata;
-  return BSE::TB::Metadata->make
-      (
-       file_id => $self->id,
-       owner_type => $self->meta_owner_type,
-       %opts,
-      );
-}
+=item metadata
+
+Return all metadata for the object (as metadata objects).
+
+=cut
 
 sub metadata {
   my ($self) = @_;
@@ -51,6 +47,13 @@ sub metadata {
     );
 }
 
+=item text_metadata
+
+Return all metadata for the object with a content type of
+C<text/plain>.
+
+=cut
+
 sub text_metadata {
   my ($self) = @_;
 
@@ -63,6 +66,14 @@ sub text_metadata {
     );
 }
 
+=item meta_by_name
+
+Retrieve metadata with a specific name.
+
+Returns nothing if there is no metadata of that name.
+
+=cut
+
 sub meta_by_name {
   my ($self, $name) = @_;
 
@@ -78,4 +89,218 @@ sub meta_by_name {
   return $result;
 }
 
+=item meta_json_by_name
+
+Retrieve metadata with a specific name and decode it as JSON,
+returning a data structure.
+
+Returns nothing if there is no metadata of that name, or if the
+content type isn't a JSON content type or if the metadata cannot be
+decoded as JSON.
+
+=cut
+
+sub meta_json_by_name {
+  my ($self, $name) = @_;
+
+  my $meta = $self->meta_by_name($name)
+    or return;
+
+  return $meta->retrieve_json;
+}
+
+=item metanames
+
+Returns the names of each metadatum defined for the file.
+
+=cut
+
+sub metanames {
+  my ($self) = @_;
+
+  require BSE::TB::Metadata;
+  return BSE::TB::Metadata->getColumnBy
+    (
+     "name",
+     [
+      [ file_id => $self->id ],
+      [ owner_type => $self->meta_owner_type ],
+     ],
+    );
+
+}
+
+=item metainfo
+
+Returns all but the value for metadata defined for the file.
+
+This is useful to avoid loading large objects if the metadata happens
+to be file content.
+
+=cut
+
+sub metainfo {
+  my ($self) = @_;
+
+  require BSE::TB::Metadata;
+  my @cols = grep $_ ne "value", BSE::TB::MetaEntry->columns;
+  return BSE::TB::Metadata->getColumnsBy
+    (
+     \@cols,
+     [
+      [ file_id => $self->id ],
+      [ owner_type => $self->meta_owner_type ],
+     ],
+    );
+}
+
+=item meta_config
+
+Returns configured metadata fields for this object.
+
+=cut
+
+sub meta_config {
+  my ($self, $cfg) = @_;
+
+  $cfg || BSE::Cfg->single;
+
+  require BSE::MetaMeta;
+  my @metafields;
+  my $prefix = $self->meta_meta_cfg_prefix;
+  my @keys = $cfg->orderCS($self->meta_meta_cfg_section);
+  for my $name (@keys) {
+    my %opts = ( name => $name );
+    my $section = "$prefix $name";
+    for my $key (BSE::MetaMeta->keys) {
+      my $value = $cfg->entry($section, $key);
+      if (defined $value) {
+       $opts{$key} = $value;
+      }
+    }
+    push @metafields, BSE::MetaMeta->new(%opts, cfg => $cfg);
+  }
+
+  return @metafields;
+
+}
+
+=item all_meta_by_name
+
+Retrieves all metadata for this owner type with the given name.
+
+=cut
+
+sub all_meta_by_name {
+  my ($class, $name) = @_;
+
+  require BSE::TB::Metadata;
+  return BSE::TB::Metadata->getBy
+    (
+     owner_type => $class->meta_owner_type,
+     name => $name,
+    );
+}
+
+=back
+
+=head1 RESTRICTED METHODS
+
+These are not accessible from templates.
+
+=over
+
+=item clear_metadata
+
+Remove all metadata for this object.  Should be called when the object
+is removed.
+
+Restricted.
+
+=cut
+
+sub clear_metadata {
+  my ($self) = @_;
+
+  BSE::DB->run(bseClearArticleFileMetadata => $self->id, $self->meta_owner_type);
+}
+
+=item clear_app_metadata
+
+Remove all application metadata for this object.
+
+Restricted.
+
+=cut
+
+sub clear_app_metadata {
+  my ($self) = @_;
+
+  BSE::DB->run(bseClearArticleFileAppMetadata => $self->id, $self->meta_owner_type);
+}
+
+=item clear_sys_metadata
+
+Remove all system metadata for this object.
+
+Restricted.
+
+=cut
+
+sub clear_sys_metadata {
+  my ($self) = @_;
+
+  BSE::DB->run(bseClearArticleFileSysMetadata => $self->id, $self->meta_owner_type);
+}
+
+=item delete_meta_by_name
+
+Remove a single piece of metadata from the object.
+
+Restricted.
+
+=cut
+
+sub delete_meta_by_name {
+  my ($self, $name) = @_;
+
+  BSE::DB->run(bseDeleteArticleFileMetaByName => $self->id, $name, $self->meta_owner_type);
+}
+
+=item add_meta
+
+Add metadata to the object.
+
+Restricted.
+
+=cut
+
+sub add_meta {
+  my ($self, %opts) = @_;
+
+  my $value_text = delete $opts{value_text};
+  if ($value_text) {
+    utf8::encode($value_text);
+    $opts{value} = $value_text;
+  }
+
+  require BSE::TB::Metadata;
+  return BSE::TB::Metadata->make
+      (
+       file_id => $self->id,
+       owner_type => $self->meta_owner_type,
+       %opts,
+      );
+}
+
+sub restricted_method {
+  my ($self, $name) = @_;
+
+  return $name =~ /^(?:clear_|delete_|add_)/;
+}
+
 1;
+
+=back
+
+=cut