package App::ZofCMS::Plugin::Tagged; use warnings; use strict; our $VERSION = '0.0252'; use Data::Transformer; sub new { bless {}, shift } my %Tags; sub process { my ( $self, $template, $query, $config ) = @_; @Tags{ qw/T Q C/ } = ( $template, $query, $config->conf, ); my $opts = delete $template->{tagged_options}; $opts = {} unless ref $opts eq 'HASH'; return if $opts->{no_parse}; my $t = Data::Transformer->new( normal => \&callback ); $t->traverse( $template ); } sub callback { my $in = shift; while ( my ( $tag ) = $$in =~ /]+)>/ ) { if ( $tag eq 'NOOP' ) { $$in =~ s/]+>//; return; } elsif ( $tag =~ s/^RAND\s*// ) { my $integer_form; if ( $tag =~ s/^I\s*// ) { $integer_form = 1; } my $rand_number = $tag =~ /^[\d.]+$/ ? rand($tag) : rand; if ( $integer_form ) { $rand_number = int $rand_number; } $$in =~ s/]+>/$rand_number/; } my ( $cell, $var ) = split /:/, $tag, 2; my $default; if ( length($cell) > 1 ) { $default = substr $cell, 1; $cell = substr $cell, 0, 1; } my $tag_result = $Tags{ $cell }; my @parts = $var =~ /([{\[]) \s* ( [^}\]]+? ) \s* [}\]]/xg; for ( map [splice @parts, 0, 2 ], 0 .. $#parts/2 ) { $tag_result = $_->[0] eq '{' ? $tag_result->{ $_->[1] } : $tag_result->[ $_->[1] ] } $tag_result = $default unless defined $tag_result; if ( $@ ) { $Tags{T}{t}{tagged_error} = $@; } $$in =~ s/]+>/$tag_result/; } } 1; __END__ =head1 NAME App::ZofCMS::Plugin::Tagged - ZofCMS plugin to fill templates with data from query, template variables and configuration using =head1 SYNOPSIS Your ZofCMS template: { cookie_foo => '', query_foo => '[]', set_cookies => [ ['foo', 'bar' ]], plugins => [ { Cookies => 10 }, { Tagged => 20 } ], conf => { base => 'test.tmpl', }, } In your 'test.tmpl' base L template: Cookie 'foo' is set to:
Query 'foo' is set to: In ZofCMS template the Cookies plugin is set to run before Tagged plugin, thus on first page access cookies will not be set, and we will access the page without setting the 'foo' query parameter. What do we see: Cookie 'foo' is set to: No cookies Query 'foo' is set to: [] No, if we run the page the second time it (now cookies are set with L plugin) will look like this: Cookie 'foo' is set to: bar Query 'foo' is set to: [] If we pass query parameter 'foo' to the page, setting it to 'beer' our page will look like this: Cookie 'foo' is set to: bar Query 'foo' is set to: [beer] That's the power of Tagged plugin... now I'll explain what those weird looking tags mean. =head1 DESCRIPTION The module provides means to the user to use special "tags" in B values inside ZofCMS template. This provides the ability to display data generated by templates (i.e. stored in C<{d}> first level key), access query or configuration hashref. Possibilities are endless. B L B L B L =head1 STARTING WITH THE PRIORITY First of all, when using App::ZofCMS::Plugin::Tagged with other plugins make sure to set the correct priority. In our example above, we used L which reads currently set cookies into C<{d}> special key in ZofCMS template. That's why we set priority of C<10> to Cookies plugin and priority of C<20> to Tagged plugin - to insure Tagged runs after C<{d}{cookies}> have been filled in. B currently there is no support to run Tagged plugin twice, I'm not sure that will ever be needed, but if you do come across such situation, you can easily cheat. Just copy Tagged.pm in your C<$core/App/ZofCMS/Plugin/Tagged.pm> to Tagged2.pm (and ajust the name accordingly in the C line inside the file). Now you have two Tagged plugins, and you can do stuff like C<< plugins => [ {Tagged => 10}, { SomePlugin => 20 }, { Tagged2 => 30 } ] >> =head1 THE TAG foo => '', bar => 'beeer baz', baz => 'foo bar', nop => "", random => '', B First of all, the tag starts with C<< '> and ends with with a closing angle bracket (C<< '>' >>). The first character that follows C<< '> is a I. It can be either C<'Q>', C<'T'> or C<'C'>, which stand for Buery, Bemplate and Bonfiguration file. Each of those three cells is a hashref: a hashref of query parameters, your ZofCMS template hashref and your main configuration file hashref. What follows the cell letter until the colon (C<':'>) is the I, it will be used if whatever your tag references is undefined. Of course, you don't have to define the default value; if you don't - the tag value will be an empty string (not undef). B currently you can't use the actual colon (C<':'>) in your default variable. Currently it will stay that way, but there are plans to add custom delimiters in the future. After the colon (C<':'>) which signifies the end of the I and possible I follows a sequence which would access the value which you are after. This sequence is exactly how you would write it in perl. Let's look at some examples. First, let's define C<$template>, C<$query> and C<$config> variables as C, C and C "cells", these variables hold respective hashrefs (same as "cells"): same as $query->{foo} same as $template->{d}{foo} same as $config->{"fo o"}{"b a r"} same as $query->{foo} // 'none' same as $template->{t}{bar} // 'xxx' # arrayrefs are supported as well same as $template->{d}{foo}[0] C:{plugins}[1]> same as $config->{plugins}[1] =head1 THE RAND TAG rand1 => '', rand2 => '', rand3 => '', rand4 => '', rand5 => '', The I will be replaced by a pseudo-random number (obtained from perl's rand() function). In it's plainest form, C<< >>, it will be replaced by exactly what comes out from C, in other words, same as calling C. If a letter C<'I'> follows word C<'RAND'> in the tag, then C will be called on the result of C. When a number follows word C, that number will be used in the call to C. In other words, tag C<< >> will be replaced by a number which is obtained by the call to C. Note: the number must be B the letter C<'I'> if you are using it. You can have spaces between the letter C<'I'> or the number and the word C. In other words, these tags are equal: C<< >> and C<< >>. =head1 THE NOOP TAG nop => "", The I (read B Beration) is a special tag which tells Tagged plugin to stop processing this string as soon as it sees this tag. Tagged will remove the noop tag from the string. The above example would end up looking as C<< nop => "", >> B any tags I the noop tag B be parsed. =head1 OPTIONS { tagged_options => { no_parse => 1 }, } Behaviour options can be set for App::ZofCMS::Plugin::Tagged via C first level ZofCMS template key. This key takes a hashref as a value. The only currently supported key in that hashref is C which can be either a true or a false value. If it's set to a true value, Tagged will not parse this template. =head1 NOTE ON DEPLOYMENT This plugin requires L module which is not in Perl's core. If your webserver does not allow instalation of modules from CPAN, run the helper script to copy this module into your $core_dir/CPAN/ directory zofcms_helper --nocore --core your_sites_core --cpan Data::Transformer =head1 CAVEATS If your tag references some element of ZofCMS template which itself contains a tag the behaviour is undefined. =head1 SEE ALSO L, L, L =head1 AUTHOR Zoffix Znet, C<< >> (L, L) =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc App::ZofCMS::Plugin::Tagged You can also look for information at: =over 4 =item * RT: CPAN's request tracker L =item * AnnoCPAN: Annotated CPAN documentation L =item * CPAN Ratings L =item * Search CPAN L =back =head1 COPYRIGHT & LICENSE Copyright 2008 Zoffix Znet, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut