=head1 NAME Konstrukt::Plugin - Base class for the Konstrukt plugins. =head1 SYNOPSIS =head2 Writing own plugins package Konstrukt::Plugin::my_plugin; use base 'Konstrukt::Plugin'; #overwrite (some of) the methods: sub execute { my ($self, $tag) = @_; #... $self->reset_nodes(); #... $self->add_node('foo'); #... return $self->get_nodes(); } #... =head2 Using existing plugins use Konstrukt::Plugin; #import use_plugin #... sub init { #... #if you use a plugin in several places you may load it once at initialization $self->{some_plugin} = use_plugin 'some_plugin' or return undef; #... } #... sub my_method { #if you saved the plugin object at init, you may use it like this $self->{some_plugin}->some_method(); #alternatively. but more unsafe (use_plugin may return undef on error) my $plugin = use_plugin 'some_plugin'; $plugin->some_method(); #or even use_plugin('some_plugin')->some_method(); } =head1 DESCRIPTION Base class for Konstrukt plugins. To write your own plugins you have to overload some of the methods of this class. Take a look at the documentation of the methods and at the L to get an overview of what has to be done to create an own plugin. You might also want to take a look at L, at L and at the plugins that already exist. =cut package Konstrukt::Plugin; use strict; use warnings; use Konstrukt::Debug; use Konstrukt::Parser::Node; use Konstrukt::TagHandler::Plugin; =head1 EXPORTS =head2 use_plugin Exported by default. Allows you to load a plugin easily and get its object: use Konstrukt::Plugin; #import use_plugin my $plugin = use_plugin 'someplugin'; =cut use Exporter (); @Konstrukt::Plugin::ISA = qw(Exporter); @Konstrukt::Plugin::EXPORT = qw/use_plugin/; sub use_plugin { return $Konstrukt::TagHandler::Plugin->load_plugin($_[0]); } =head1 METHODS =head2 new Constructor of this class =cut sub new { my ($class) = @_; return bless {}, $class; } #= /new =head2 init Method that will be called right before the first usage within a request. Here you should do per request initialization work like definition of L. Should be overridden by the inheriting class. =cut sub init { return 1; } # /init =head2 install Should be overloaded by your plugin and its backends, if they need installation before the first run. The installation should be performed according to the current settings like the selected backend and database settings as well as the template path. Usually in the backend module this method will create database tables for your plugin. The "main" plugin should load the backend plugin on init, that is defined in the settings, and then the install method will be called automatically on the backend module when it gets loaded. The "main" plugin may create templates that are needed for the output. Will be called automatically after the plugin has been loaded and Cialized, if the setting C is true. You may want to use L for the installation of your DBI backend plugins and L for the installation of default templates for your plugin, which can be embedded at the end of your plugin module. Don't confuse this method with L, which will be called once on B request. B none =cut sub install { return 1; } # /install =head2 prepare_again If this method returns a true value the result generated by this plugin will be piped through the prepare run before it will be inserted into the result tree. Should return true, when this plugin may generate plaintext, that will parse to dynamic content (e.g. return plaintext nodes that contain Konstrukt tags (<& .. &>)), or tag nodes that should be prepare()'d. In detail all returned plaintext nodes will be parsed for special tags and existing tag nodes will be prepare()'d recursively. As this is a time consuming job (especially when your tag has many/deeply nested children), you should only return true, if your plugin really generates new tags (as plaintext or as tag nodes). =cut sub prepare_again { return 0; } #= /prepare_again =head2 execute_again If this method returns a true value the result generated by this plugin will be piped through the execute run before it will be inserted into the result tree. Should return true, when this plugin may generate (dynamic) tag nodes that shall be executed (e.g. return a template or perl node). =cut sub execute_again { return 0; } #= /execute_again =head2 executionstage Returns the execution stage of the tag. Defaults to 1. Usually all tags are Ld in the order of appearence in the processed document. But sometimes you might want a tag to be executed last/later, although it's located at the top of the document. The Cs allow you to specifiy an execution order that's different from the appearance order. <& perl executionstage="2" &>print `date +%H:%M:%S`<& / &> <& perl &>print `date +%H:%M:%S`; sleep 2<& / &> Will actually be rendered to something like: 10:50:54 10:50:52 =cut sub executionstage { return 1; } #= /executionstage =head2 prepare The prepare method of this plugin. This sub should be overridden by the inheriting class. Every content that will be the same with each page request ("static" content) should be processed by the plugin in this stage. If you want to replace the tag with other nodes, you must return a (dummy) tag L whose children will replace the original tag. You may also just return a scalar(ref). You may want to use L, L and L for an easier node handling. Note that you should return C if you modify the tree yourself instead of returning replacement nodes. (Some of) the nodes passed to your plugin may be dynamic content (i.e. tags that have to be executed on every request as they may produce different output on every request). You can check it like this: if ($tag->{dynamic}) { ... } If B plugin has to do some work in the execute run, you should set the dynamic flag of your tag to a true value to let the parser know, that this tag cannot be finally processed in the prepare run: $tag->{dynamic} = 1; If your plugin returns plaintext that will parse into new tag nodes or if it returns new tag nodes that should be prepare()'d your L method should return a true value. B: =over =item * $tag - Reference to the tag node (and its children) that shall be handled. Contains the plugin tag in the parse tree and all related information - espeacially the tag attributes (C<$tag->{tag}->{attributes}>) and the content inside the tag: my $node = $tag->{first_child}; while (defined $node) { #do stuff on $node->{content}... $node = $node->{next}; } =back =cut sub prepare { my ($self, $tag) = @_; $Konstrukt::Debug->error_message("Not overloaded!") if Konstrukt::Debug::ERROR; return 'Your plugin should do its prepare-work here!'; } #= /prepare =head2 execute The execute method of this plugin. This sub should be overridden by the inheriting class. Every content that may be different on each page request ("dynamic" content) should be processed by the plugin in this stage. If you want to replace the tag with other nodes, you must return a (dummy) tag L whose children will replace the original tag. You may also just return a scalar(ref). You may want to use L, L and L for an easier node handling. Note that you should return C if you modify the tree yourself instead of returning replacement nodes. B: =over =item * $tag - Reference to the tag node (and its children) that shall be handled. Contains the plugin tag in the parse tree and all related information - espeacially the tag attributes (C<$tag->{tag}->{attributes}>) and the content inside the tag: my $node = $tag->{first_child}; while (defined $node) { #do stuff on $node->{content}... $node = $node->{next}; } =back =cut sub execute { my ($self, $tag) = @_; $Konstrukt::Debug->error_message("Not overloaded!") if Konstrukt::Debug::ERROR; return 'Your plugin should do its execute work here!'; } #= /execute =head2 reset_nodes Creates a new node collection. See L. =cut sub reset_nodes { my ($self) = @_; $self->{collector_node} = Konstrukt::Parser::Node->new(); } #= /reset_nodes =head2 add_node This method allows you to add a node to the list of temporary nodes. Usually you would use it like this, if your plugin will return some nodes: $self->reset_nodes(); $self->add_node('some plaintext node'); $self->add_node(Konstrukt::Parser::Node->new({ type => 'comment', content => ''})); #you may also add any other tag return $self->get_nodes(); If the argument is no C object, a plaintext node with the argument as content will be created. B: =over =item * $node - C object. =back =cut sub add_node { my ($self, $node) = @_; #the node must be a hash reference if (ref($node) ne 'Konstrukt::Parser::Node') { $Konstrukt::Debug->debug_message("Passed node is no Konstrukt::Parser::Node! Assuming plaintext node.") if Konstrukt::Debug::DEBUG; $node = Konstrukt::Parser::Node->new({ type => 'plaintext', content => $node }); } #add node $self->{collector_node}->add_child($node); } #= /add_node =head2 get_nodes Retruns the node, whose children are the collected nodes. =cut sub get_nodes { my ($self) = @_; return $self->{collector_node}; } #= /get_nodes 1; =head1 AUTHOR Copyright 2006 Thomas Wittek (mail at gedankenkonstrukt dot de). All rights reserved. This document is free software. It is distributed under the same terms as Perl itself. =head1 SEE ALSO L, L, L, L =cut