XML manipulation of the EPrints Workflow using a Bazaar Package

From EPrints Documentation
Revision as of 15:25, 16 December 2011 by Sf03r@ecs.soton.ac.uk (talk | contribs) (Add a new deposit type)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search


Manipulation of built in EPrint files, such as the Workflows, is currently performed using the enable method which is run as a package is being installed on a single repository.

Likewise when the package is removed, the disable method needs to call exactly the opposite set of operations to clean itself up before full removal.

Every package has an enable and disable method which is called, we simply need to subclass the EPMC screen and add our own enable and disable methods.

Pre-Requisites

Below is a simple framework for your plug-in (it's a Screen::EPMC plug-in so needs to go in the lib/plugins/EPrints/Plugin/Screen/EPMC directory). Remember to name it applicably and remember the EPMC::Package_Name when filling out your package specification (this is what calls it!).

NOTE: The following line:

 $self->{package_name} = "package_name";

If your package name is "my_package", this line should read:

 $self->{package_name} = "my_package";

This way you don't need to type your package name in anywhere else in the code, You can just use $self->{package_name} which is the variable that contains the name.

 package EPrints::Plugin::Screen::EPMC::Package_Name;
 
 @ISA = ( 'EPrints::Plugin::Screen::EPMC' );
 
 use strict;
 # Make the plug-in
 sub new
 {
       my( $class, %params ) = @_;
 
       my $self = $class->SUPER::new( %params );
 
       $self->{actions} = [qw( enable disable )];
       $self->{disable} = 0; # always enabled, even in lib/plugins
 
       $self->{package_name} = "Package_Name";
 
       return $self;
 }
 
 =item $screen->action_enable( [ SKIP_RELOAD ] )
 
 Enable the L<EPrints::DataObj::EPM> for the current repository.
 
 If SKIP_RELOAD is true will not reload the repository configuration.
 
 =cut
 
 sub action_enable
 {
       my( $self, $skip_reload ) = @_;
 
       $self->SUPER::action_enable( $skip_reload );
 
       my $repo = $self->{repository};
 
       # ADD STUFF HERE
 
       $self->reload_config if !$skip_reload;
 }
 
 =item $screen->action_disable( [ SKIP_RELOAD ] )
 
 Disable the L<EPrints::DataObj::EPM> for the current repository.
 
 If SKIP_RELOAD is true will not reload the repository configuration.
 
 =cut
 
 sub action_disable
 {
       my( $self, $skip_reload ) = @_;
 
       $self->SUPER::action_disable( $skip_reload );
       my $repo = $self->{repository};
 
       # ADD STUFF HERE
       
       $self->reload_config if !$skip_reload;
 
 }
 
 1;

Exercise 1

In this exercise we are going to do some simple workflow editing exercises. These follow the standard EPrints training materials which teach you how to manually edit the workflow. Here we are going to do all the same stuff with API calls.

Adding a Divisions Stage to the Workflow

Basically we are simply editing XML so all we need to do is tell the repository which file to manipulate and then give it the stuff add to this file.

So to the enable routine we need to add the following lines. Note that you don't need to manually specify your package_name

 my $filename = $repository->config( "config_path" )."/workflows/eprint/default.xml";
 
 # Gap for the stuff to be defined we need to add
 
 EPrints::XML::add_to_xml( $filename, $xml, $self->{package_name} );


At the same time then it is worth adding the equivalent remove lines to the disable method. Again you need to specify your package name.

 my $filename = $repository->config( "config_path" )."/workflows/eprint/default.xml";
 
 EPrints::XML::remove_package_from_xml( $filename, $self->{package_name} );

Lastly we need to actually tell the enable method the block of XML to add.

 my $xml = '
 <workflow xmlns="http://eprints.org/ep3/workflow" xmlns:epc="http://eprints.org/ep3/control">
       <flow>
               <stage ref="divisions"/>
       </flow>
       <stage name="divisions">
               <component type="Field::Subject">
                       <field ref="divisions" required="yes" />
               </component>
       </stage>
</workflow>
';

Here you can see that we can simply specify the XML as a string. We can then either parse this string and send a dom object to the add method, or simply send the string and let the add_to_xml method do it for us.

If you want to parse it yourself you will need the following code block:

 my $xml = EPrints::XML::parse_string( undef, $string );
 

The XML represents the exact same tree as in the workflow XML file we are attempting to edit. You can view this by clicking the "View Configuration" button on the "Config. Tools" tab of the admin screen. Once here you will need to scroll down to find the file you specified (in this case /workflows/eprint/default.xml). Since it represents the same tree, only nodes which don't exist are added and marked as belonging to your package. This marker is how they are removed.

Alternatively you can build an XML tree using the EPrints::XML methods like make_element("flow") etc. At this point (unless you added blank nodes) you won't need the remove line, but it doesn't hurt to leave it in there.

Divisions Phrases

For the divisions screen to work fully you will need to define a number of phrases.

As usual you need a new file, basically take a copy of lib/lang/en/phrases/zz_webcfg in cfg/lang/en/phrases/package_name.

The clear all the defined phrases from this file and add the follow 2:

 <epp:phrase id="metapage_title_divisions">Divisions</epp:phrase>
 <epp:phrase id="Plugin/InputForm/Component/Field/Subject:divisions_search_bar"><div class="ep_subjectinput_searchbar">Search for division: <epc:pin name="input"/> <epc:pin name="search_button"/> <epc:pin name="clear_button"/></div></epp:phrase>

Package and Test

Finally, package all these files up and test in from the Bazaar. Note that in the spec file you need to set your Control Screen to EPMC::PackageName or whatever your screen is called.

You can test this package by click the "manage deposits" link in the admin toolbar and adding a new item. You should see a divisions tab.

Exercise 2

Change this package to add a conditional element somewhere, for example:

 <epc:if test="type = 'book'">
    <field ref="pres_type"/>
 </epc:if>

Experiment with this and use the "view configuration" to see what your changes do to the workflow file each time.

Clue: The correct place to put this code block is under the <component type="Field::Multi"> tag which is in the core stage <stage name="core">. You need to wrap the above code blog in both these tags.

If you are using the same package as before you will need to updated your cached version and then restart apache to make it work. This is a known bug and applies the the XML manipulation code only.

Exercise 3

Here we are going to define a whole new type "map" and a different set of stages for it.

This exercise is also one of manual customisation exercises we run.

Add a new deposit type

This stage involves the editing of the repository namedsets, specifically the eprints namedset.

Again this used to be an entirely manual process however it can now be done with an API call via the enable/disable methods:

In enable:

 # Load your namedset, in this case the eprint namedset
 my $namedset = EPrints::NamedSet->new( "eprint",repository => $repository );
 
 # Add a new option (string type, package_name, offset from top) 
 # Setting the offset to 0 will add the item at the top of list of eprint types in this case. 
 $namedset->add_option( "map", $self->{package_name}, 0 );
 

In disable we need the corresponding remove calls!

 my $namedset = EPrints::NamedSet->new( "eprint",repository => $repository );
 
 $namedset->remove_option( "map", $self->{package_name} );

Each namedset item also needs some phrase so in our phrase file we need to add phrases for "eprint_typename_map" and "eprint_optdetails_type_map". Lets set these to "Map" and "A map or chart." respectively.

Adding a new stage and simple map workflow

In this section we are going to define a whole new workflow for our "map" type, so if someone selects this as their EPrint type they won't see upload (files), subjects and divisions, just a new state we going to call "map_stage".

Of course in order to customise the workflow we need to handle if/else statements. Helpfully there is a clever API call that does it for you.

All we have to define in the types we want to match and the stages that these types have. Everything that doesn't match thus goes in the else condition.

So in our enable lets now define some variables

 #our matching types 
 my @types = ( "map" );
 
 #the stages
 my @stages = ( "map_stage" );

Then we add these to our workflow with a similar API call to before.

 $rc = EPrints::Workflow::add_workflow_flow( $repository, $filename, $self->{package_name}, \@types, \@stages );

We can then use the xml string which we defined before to add the new stage:

 my $string = '
 <workflow xmlns="http://eprints.org/ep3/workflow" xmlns:epc="http://eprints.org/ep3/control">
       <stage name="map_stage">
              <component type="Field::Multi">
                    <title>Publisher Details</title>
                    <field ref="place_of_pub" />
                    <field ref="publisher" required="yes" />
                    <field ref="date" />
                    <field ref="date_type" />
              </component>
              <component>
                    <field ref="id_number" />
              </component>
              <component>
                    <field ref="official_url"/>
              </component>      
       </stage>
 </workflow>
 ';

Package and Test

Finally, package all these files up and test in from the Bazaar.

You can test this package by click the "manage deposits" link in the admin toolbar and adding a new item. You should now have a new eprint type on the first screen called "map" and selecting this will give you a much shorter workflow containing only a few fields.

Are all your phrases defined?