Talk:API:EPrints

From EPrints Documentation
Revision as of 19:04, 17 September 2009 by Cjg (Talk | contribs)

Jump to: navigation, search

I'm going to use this page to get my thoughts in order. Cjg 16:58, 2 September 2009 (BST)

Current 3.1 System

Unsessioned Classes

These classes don't store a session internally resulting in methods like $foo->render( $session, ARGS ).

  • Repository
  • DataSet
  • MetaField
  • Language

Sessioned Classes

These classes store a session internally resulting in methods like $foo->render( ARGS ).

  • Session
  • DataObj
  • Plugin
  • List
  • Search
  • Database
  • Workflow
  • ScreenProcessor

API

New Plan(!)

  • Merge Session and Repository into a single class.
  • Move XML functions into their own class.
  • Move Page functions into their own class.
  • Add a link to repository for dataset and metafield.
  • Ensure cleanup when repository object goes out of scope.
  • Make EPrints->new() return an eprints object which can pass out repository objects.
    • repository objects don't have a link to the EPrints object EVER.
    • When the eprints object is DESTROY'd it takes out the repositories, datasets and metafields etc.

EPrints

$ep = EPrints->new();
$repo = $ep->repository( "devel", noise=>1 );
$repo = $ep->current_repository(); # from Apache::Request URI
EPrints->abort( $message );

repo

Yes:

$xml = $repo->xml;
$dataset = $repo->dataset( "user" );
$user = $repo->current_user;
$query = $repo->query;
$current_page_url = $repo->current_url; 
$config_element = $repo->config( $key, [@subkeys] );
$repository->log( $message ); 
$string = $repo->query->param( "X" );
$repo->redirect( $url );

Maybe:

  • tdb: language accessors
    • cjg: I think thses don't belong in the API - why do people need access to them? If I'm wrong we add them in API 1.1?
$lang = $repo->language( $langid );
$lang = $repo->default_language; # needed? nee ->language( undef )
$lang = $repo->current_language;
  • cjg: I think these would be very useful but they are inconsistent.
$eprint = $repo->eprint( 23 );
$user = $repo->user( 23 );
$user = $repo->user_by_username( "cjg" );
$user = $repo->user_by_email( 'cjg@ecs.soton.ac.uk' );

dataset

$string = $dataset->base_id; # eprint
$string = $dataset->id; # inbox
$dataobj = $datasset->create_dataobj( $data );
$user = $dataset->dataobj( 23 );

$search = $dataset->prepare_search( %options );
$list = $dataset->search( %options ); # prepare_search( %options )->execute
$list = $dataset->search; # match ALL

$metafield = $dataset->field( $fieldname );
$metafield = $dataset->key_field;
@metafields = $dataset->fields; 

$dataset->search->map( sub {}, $ctx );
$n = $dataset->search->count; 
$ids = $dataset->search->ids;

Maybe:

  • tdb: is this common enough to replace EPrints::List->new()?
    • cjg: part of the API goal IMO is to get away from classnames if at all possible, so this would become the proper way to create a list object.
$list = $dataset->list( \@ids ); 

Maybe not:

  • pm5 why not this one? i think thats handy
    • cjg: because we could use (defined $dataset->field( $fieldname ))
$bool = $dataset->has_field( $fieldname );

list

$n = $list->count;
$list->map( sub {}, $ctx );
$dataobj = $list->item( offset );
@dataobjs = $list->slice( offset, length ); 
# tdb: consistent with creating a list: unbounded returns should use array ref?
\@ids = $list->ids;

search

TERM_EQUALS = "EQ"
TERM_INDEX = "IN"
TERM_EXACT = "EX"

MATCH_ALL = "ALL"
MATCH_ANY = "ANY"

$search = $dataset->prepare_search( order => "-date", satisfy_all=>1 );
$search = $dataset->prepare_search( terms => [], filters => [], ... );

$list = $search->execute;

# constructor interface
$s = $dataset->prepare_search( order => "-date", satisfy_all => 1, terms => [
 { fields => "type", values => [qw( article book )], op => TERM_EQUALS, match => MATCH_ANY },
 { fields => [qw( title abstract )], values => ["dogbert dilbert"], op => TERM_INDEX, match => MATCH_ALL },
 { fields => "userid", values => "52", op => TERM_EXACT },
] );
  • tdb: meta_fields/fields/field, value/values?
    • cjg: could have choice of fields=>["",""] or field=>""
# method interface
$s = $dataset->prepare_search( order => "-date", satisfy_all => 1 );
$s->add_term( "type", [qw( article book )], op => TERM_EQUALS, match => MATCH_ANY );
$s->add_term( [qw( title abstract )], ["dogbert dilbert"], op => TERM_INDEX, match => MATCH_ALL );
$s->add_term( "userid", "52", op => TERM_EXACT );
$list = $s->execute;

print $list->count, "\n";
  • tdb: I would like to make the value argument not automagically-split on ANY but explicitly use an array ref of values to match.
    • cjg: Agreed.

Maybe

$s->add_term( $dataset->field( "type" ), [qw/ article book/], merge => MERGE_ANY );
  • cjg: I'm not convinced we need this.

XML

$doc = $xml->parse_string( $string );
$doc = $xml->parse_file( $filename );
$doc = $xml->parse_url( $url );
$utf8_string = $xml->to_string( $dom_node, %opts );
# tdb: to_text needs a better name
$utf8_string = $xml->to_text( $dom_node, %opts ); # nee tree_to_utf8
$dom_node = $xml->clone( $dom_node ); # deep
$dom_node = $xml->clone_node( $dom_node ); # shallow
$dom_node = $xml->contents_of( $dom_node ); # clone and return child nodes
$utf8_string = $xml->text_contents_of( $dom_node ); # clone and return text child nodes
$dom_node = $xml->create_element( $name, %attr );
$dom_node = $xml->create_text_node( $value );
$dom_node = $xml->create_comment_node( $value );
$dom_node = $xml->create_document_fragment;
$xml->dispose( $dom_node );
        • pm5 firstly most of this looks good so well done. is there a reason why we have create_element but appendChild? i know the camel casing is sort of a hand me down from the various xml libraries might it be worth wrapping those or camel casing everything in this class (just for consistancy). Also im not sure about render_ what about create_ the result being createLink, createInputField etc
          • cjg: because appendChild is a DOM method, not part of the EPrints API. All EPrints API methods use the "foo_bar" style of method name. DOM is a defined standard we can't alter.

XHTML

$xhtml = $repo->xhtml;
$utf8_string = $xhtml->to_xhtml( $dom_node, %opts ); # remove NS prefixes, fix <script> etc.
$xhtml_dom_node = $xhtml->input_field( $name, $value, %opts ); # nb. type & noenter are now options.
$xhtml_dom_node = $xhtml->hidden_field( $name, $value, %opts ); # tdb: this is used *a lot* and is well defined
$xhtml_dom_node = $xhtml->text_area_field( $name, $value, %opts ); # tdb: value becomes a child text node 
$xhtml_dom_node = $xhtml->form( $method, $url );
$page = $xhtml->build_page( %opts );
# $repo->xhtml->phrase( $phrase_id )
$xhtml_dom_node = $xhtml->phrase( $phrase_id, %pins );
  • move this to repository? Cjg 20:03, 17 September 2009 (BST)
# is this an XHTML function or move to Repository?
$utf8string = $xhtml->text_phrase( $phrase_id, %pins );
# Maybe not (due to making Patrick sad, and just as easy to do with create_element( "a", href=>... )
$xhtml_dom_node = $xhtml->link( $url, %opts ); #nb will require clever hack if scalar @opts = 1;
  • tdb: these are really not useful - nbsp is a kludge, ruler should be done by CSS
    • Cjg: nbsp is just a convenient way of inserting a unicode character which is frequently used, so I vote to keep it in, name() is also useful IMO. Ruler can be easily replaced with a phrase call, and isn't used much in EP3+ so I can happily see that go into the west and diminish.
$xhtml_dom_node = $xhtml->ruler;
$xhtml_dom_node = $xhtml->nbsp;
$xhtml_dom_node = $xhtml->name( $namehash, render_order=>"gf" ); # or fg

Page

$page->send( %options ); 
$page->write_to_file( $filename );

DataObj

$dataobj = $dataset->dataobj( $id );
$dataobj->delete;
$dataobj->commit( $force );
$dataobj->set_value( $fieldname, $value );
$value = $dataobj->value( $fieldname );
\@value = $dataobj->value( $fieldname ); # multiple
$boolean = $dataobj->is_set( $fieldname );
$id = $dataobj->id;
$xhtml = $dataobj->render_value( $fieldname );
$xhtml = $dataobj->render_citation( $style, %opts );
($xhtml, $title, $head_elements) = $dataobj->render;
$uri = $dataobj->uri;
$url = $dataobj->url;
$string = $dataobj->export( $plugin_id, %opts );
$dataobj = $dataobj->create_subobject( $fieldname, $epdata );
  • cjg: would render() be better replaced with something which returns a hash not an array?

SubObject

  • tdb: superclass of Document, File, History, SavedSearch
$dataobj = $dataobj->parent;

EPrint

$eprint->set_status( "inbox" );
  • tdb: consistency - ->documents ~ ->value( "documents" ) and ->value() returns array ref for multiple
my $docs = $eprint->documents( %opts ); # isVolatileVersionOf => 0 ?
foreach my $document ( @$docs ) { .. }

# create a new document on $eprint 
$doc_data = { ... };
$doc = $eprint->create_subobject( "documents", $doc_data ); 
# eprint to which this document belongs
$eprint = $doc->parent;

User

$user = $repository->dataset( "user" )->dataobj( 23 ); 
  • tdb: is this accessor or action? c.f. send_page()
    • It's an action. Cjg 20:04, 17 September 2009 (BST)
$user->send_email( .... )

Subject

$subject = $repository->dataset("subject")->dataobj( "FOO" );
\@subjects = $subject->children;
\@subjects = $subject->parents; 
  • CJG: issue with confusion with subobjects like document, or are these really subobjects? Maybe child_subjects parent_subjects to avoid overlapping names?
  • tdb: subobject relation = if you remove parent, children are removed - is this true of subjects? Could extend subobject concept to be M:N
    • $subject->value( "children" ) = ->children
    • $subject->value( "parents" ) = ->parents

Document

$doc = $repo->dataset( "document" )->dataobj( 23 );

# delete a document object *forever*:
$ok = $doc->delete;

$url = $doc->url( [$file] );
  • tdb: is $file ^^ a file object or filename?
# change the file which is used as the URL for the document.
$doc->set_value( "main", "foo.html" );

# dealing with files
$file = $doc->file_by_filename( $filename ); # nee get_stored_file
\@files = $doc->value( "files" );
$file->value( "filename" );
$file->value( "filesize" );

# delete a file
$doc->file_by_filename( $filename )->delete;

# delete all files
$files = $doc->value( "files" );
foreach my $file (@$files) { $file->delete; } 

# icons and previews???? These need work!
$xhtml = $doc->render_icon_link( %opts );
$xhtml = $doc->render_preview_link( %opts );

Maybe

# Add files to the document
# tdb: these should be deprecated from Document and moved to Import/Screen plugins
$success = $doc->upload( $filehandle, $filename [, $preserve_path [, $filesize ] ] );
$success = $doc->upload_archive( $filehandle, $filename, $archive_format );
$success = $doc->add_archive( $file, $archive_format );
$success = $doc->add_directory( $directory );
$success = $doc->upload_url( $url );

File

$file = $history->file_by_filename( "dataobj.xml" );
$file->retrieve( sub { ... }, $info ); # callback-based file content retrieval
  • I don't know enough about this method to know what we *must* have in. Less is better IMO, though. Cjg 01:23, 17 September 2009 (BST)
  • tdb: files should probably be only created via a parent object

MetaField

Now has a handle on both it's repository/session AND dataset.

my $field = $dataset->field( $fieldname );
$field->set_property( $property, $value );

$name = $field->name;
$type = $field->type;
$value = $field->property( $property );

$xhtml = $field->render_name;
$xhtml = $field->render_help;
$xhtml = $field->render_value_label( $value );

$values = $field->values( %opts );
$sorted_list = $field->sort_values( $unsorted_list );