# $Id: /local/CPAN/Handel/trunk/lib/AxKit/XSP/Handel/Cart.pm 1916 2007-06-24T15:35:46.298350Z claco $ ## no critic package AxKit::XSP::Handel::Cart; use strict; use warnings; use vars qw($NS); use Handel::ConfigReader; use Handel::Constants qw(:cart str_to_const); use Handel::Exception; use Handel::L10N qw(translate); use base 'Apache::AxKit::Language::XSP'; $NS = 'http://today.icantfocus.com/CPAN/AxKit/XSP/Handel/Cart'; BEGIN { my $pkg = __PACKAGE__; no strict 'refs'; my @quoted = qw/ new_description new_id new_name new_shopper new_results_add_id new_results_add_sku new_results_add_quantity new_results_add_price new_results_add_description cart_filter cart_results_add_id cart_results_add_sku cart_results_add_quantity cart_results_add_price cart_results_add_description cart_results_delete_id cart_results_delete_sku cart_results_delete_quantity cart_results_delete_price cart_results_delete_description cart_results_update_name cart_results_update_shopper cart_results_update_description cart_results_item_filter cart_results_item_results_update_sku cart_results_item_results_update_quantity cart_results_item_results_update_price cart_results_item_results_update_description cart_results_items_filter cart_results_items_results_update_sku cart_results_items_results_update_quantity cart_results_items_results_update_price cart_results_items_results_update_description cart_results_restore_filter carts_filter carts_results_add_id carts_results_add_sku carts_results_add_quantity carts_results_add_price carts_results_add_description carts_results_delete_id carts_results_delete_sku carts_results_delete_quantity carts_results_delete_price carts_results_delete_description carts_results_item_filter carts_results_item_results_update_sku carts_results_item_results_update_quantity carts_results_item_results_update_price carts_results_item_results_update_description carts_results_items_filter carts_results_items_results_update_sku carts_results_items_results_update_quantity carts_results_items_results_update_price carts_results_items_results_update_description carts_results_update_name carts_results_update_shopper carts_results_update_description carts_results_restore_filter /; my @empty = qw/ new new_no_results new_results new_results_add new_results_add_results new_results_add_no_results cart cart_results cart_results_add cart_results_add_results cart_results_add_no_results cart_results_delete cart_results_update cart_results_item cart_results_item_results cart_results_item_results_update cart_results_item_no_results cart_results_items cart_results_items_results cart_results_items_results_update cart_results_items_no_results cart_results_restore cart_no_results carts carts_results carts_results_add carts_results_delete carts_results_update carts_results_item carts_results_item_results carts_results_item_results_update carts_results_item_no_results carts_results_items carts_results_items_results carts_results_items_results_update carts_results_items_no_results carts_results_restore carts_no_results /; my @constants = qw / new_type cart_results_update_type carts_results_update_type /; foreach (@quoted) { my $sub = $_ . "_char"; *{"$pkg\::$sub"} = \"ed_text; }; foreach (@empty) { my $sub = $_ . "_char"; *{"$pkg\::$sub"} = sub {}; }; foreach (@constants) { my $sub = $_ . "_char"; *{"$pkg\::$sub"} = \&constant_text; }; *{"$pkg\::guid_start"} = \&uuid_start; }; my @context = 'root'; sub start_document { return "use Handel::Cart;\nuse Handel::Compat::Currency;use Handel::Currency;\n"; }; sub quoted_text { my ($e, $text) = @_; return ".q|$text|"; }; sub constant_text { my ($e, $text) = @_; if ($text =~ /^[A-Z]{1}/) { $text = str_to_const($text); }; return ".q|$text|"; }; sub uuid_start { my ($e, $tag, %attr) = @_; $e->start_expr($tag); $e->append_to_script("Handel::Cart->storage->new_uuid"); $e->end_expr($tag); return; }; sub new_start { my ($e, $tag, %attr) = @_; throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_IN_OTHERS', $tag) ) if ($context[-1] ne 'root'); push @context, $tag; my $code = "my \$_xsp_handel_cart_cart;\nmy \$_xsp_handel_cart_called_new;\n"; $code .= scalar keys %attr ? 'my %_xsp_handel_cart_new_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_new_filter;' ; return "\n{\n$code\n"; }; sub new_description_start { my ($e, $tag, %attr) = @_; return "\n\$_xsp_handel_cart_new_filter{$tag} = ''"; }; sub new_id_start { my ($e, $tag, %attr) = @_; return "\n\$_xsp_handel_cart_new_filter{$tag} = ''"; }; sub new_name_start { my ($e, $tag, %attr) = @_; return "\n\$_xsp_handel_cart_new_filter{$tag} = ''"; }; sub new_shopper_start { my ($e, $tag, %attr) = @_; return "\n\$_xsp_handel_cart_new_filter{$tag} = ''"; }; sub new_type_start { my ($e, $tag, %attr) = @_; if (exists $attr{'type'}) { if ($attr{'type'} =~ /^[A-Z]{1}/) { $attr{'type'} = str_to_const($attr{'type'}); }; }; return "\n\$_xsp_handel_cart_new_filter{$tag} = ''"; }; sub new_results_start { my ($e, $tag, %attr) = @_; throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-1] !~ /^(new|add|cart(s?)|item(s?))$/); push @context, $tag; return ' if (!$_xsp_handel_cart_called_new && scalar keys %_xsp_handel_cart_new_filter) { $_xsp_handel_cart_cart = Handel::Cart->create(\%_xsp_handel_cart_new_filter); $_xsp_handel_cart_called_new = 1; }; if ($_xsp_handel_cart_cart) { '; }; sub new_results_count_start { my ($e, $tag, %attr) = @_; $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_cart->$tag;\n"); return; }; sub new_results_description_start { my ($e, $tag, %attr) = @_; $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_cart->$tag;\n"); return; }; sub new_results_name_start { my ($e, $tag, %attr) = @_; $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_cart->$tag;\n"); return; }; sub new_results_id_start { my ($e, $tag, %attr) = @_; $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_cart->$tag;\n"); return; }; sub new_results_shopper_start { my ($e, $tag, %attr) = @_; $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_cart->$tag;\n"); return; }; sub parse_char { my ($e, $text) = @_; my $tag = $e->current_element(); my $pkg = $AxKit::XSP::TaglibPkg; ######################################################################## ## New magic to make subclassing more feasable ######################################################################## my @ctx = @context; shift @ctx; if (($ctx[$#ctx] && $ctx[$#ctx] ne $tag) || !$ctx[$#ctx]) { push @ctx, $tag; }; push @ctx, 'char'; my $sub = join '_', @ctx;$sub =~ s/-/_/; if (my $coderef = $pkg->can($sub)) { AxKit::Debug(5, "[Handel] [Cart] parse_char: calling $sub"); return $coderef->($e, $text); } else { AxKit::Debug(5, "[Handel] [Cart] parse_char: $sub not found"); AxKit::Debug(5, "[Handel] [Cart] parse_char: processing $tag"); }; ######################################################################## return; }; sub parse_start { my ($e, $tag, %attr) = @_; my $pkg = $AxKit::XSP::TaglibPkg; AxKit::Debug(5, "[Handel] [Cart] parse_start: [$tag] context: " . join('->', @context)); ######################################################################## ## New magic to make subclassing more feasable ######################################################################## my @ctx = @context; shift @ctx; if (($ctx[$#ctx] && $ctx[$#ctx] ne $tag) || !$ctx[$#ctx]) { push @ctx, $tag; }; push @ctx, 'start'; my $sub = join '_', @ctx;$sub =~ s/-/_/; if (my $coderef = $pkg->can($sub)) { AxKit::Debug(5, "[Handel] [Cart] parse_start: calling $sub"); return $coderef->($e, $tag, %attr); } else { AxKit::Debug(5, "[Handel] [Cart] parse_start: $sub not found"); AxKit::Debug(5, "[Handel] [Cart] parse_start: processing $tag"); }; ######################################################################## if (exists $attr{'type'}) { if ($attr{'type'} =~ /^[A-Z]{1}/) { $attr{'type'} = str_to_const($attr{'type'}); }; }; ## cart:uuid if ($tag =~ /^(g|u)uid$/) { $e->start_expr($tag); $e->append_to_script("Handel::Cart->storage->new_uuid"); $e->end_expr($tag); ## cart:new } elsif ($tag eq 'new') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_IN_OTHERS', $tag) ) if ($context[-1] ne 'root'); push @context, $tag; my $code = "my \$_xsp_handel_cart_cart;\nmy \$_xsp_handel_cart_called_new;\n"; $code .= scalar keys %attr ? 'my %_xsp_handel_cart_new_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_new_filter;' ; return "\n{\n$code\n"; ## cart:restore } elsif ($tag eq 'restore') { throw Handel::Exception::Taglib( -text => translate('Tag [_1] not valid inside of tag [_2]', $tag, $context[-1]) ) if ($context[-1] =~ /^(cart(s?))$/); push @context, $tag; my $mode = str_to_const($attr{'mode'}) || CART_MODE_APPEND; delete $attr{'mode'}; my $code .= scalar keys %attr ? 'my %_xsp_handel_cart_restore_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_restore_filter;' ; return "\n{\nmy \$_xsp_handel_cart_restore_mode = $mode;\n$code\n"; ## cart:cart } elsif ($tag eq 'cart') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_IN_OTHERS', $tag) ) if ($context[-1] ne 'root'); push @context, $tag; my $code = "my \$_xsp_handel_cart_cart;\nmy \$_xsp_handel_cart_called_load;\n"; $code .= scalar keys %attr ? 'my %_xsp_handel_cart_load_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_load_filter;' ; return "\n{\n$code\n"; ## cart:carts } elsif ($tag eq 'carts') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_IN_OTHERS', $tag) ) if ($context[-1] ne 'root'); push @context, $tag; my $code = "my \@_xsp_handel_cart_carts;\nmy \$_xsp_handel_carts_called_load;\n"; $code .= scalar keys %attr ? 'my %_xsp_handel_carts_load_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_carts_load_filter;' ; return "\n{\n$code\n"; ## cart:item } elsif ($tag eq 'item') { throw Handel::Exception::Taglib( -text => translate('Tag [_1] not valid inside of tag [_2]', $tag, $context[-1]) ) if ($context[-1] =~ /^(cart(s?))$/); push @context, $tag; my $code = "my \$_xsp_handel_cart_item;\nmy \$_xsp_handel_cart_called_item;\n"; $code .= scalar keys %attr ? 'my %_xsp_handel_cart_item_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_item_filter;' ; return "\n{\n$code\n"; ## cart:items } elsif ($tag eq 'items') { throw Handel::Exception::Taglib( -text => translate('Tag [_1] not valid inside of tag [_2]', $tag, $context[-1]) ) if ($context[-1] =~ /^(cart(s?))$/); push @context, $tag; my $code = "my \@_xsp_handel_cart_items;\nmy \$_xsp_handel_cart_called_items;\n"; $code .= scalar keys %attr ? 'my %_xsp_handel_cart_items_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_items_filter;' ; return "\n{\n$code\n"; ## cart:clear } elsif ($tag eq 'clear') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-1] ne 'results' || $context[-2] !~ /^(cart(s?))$/); return "\n\$_xsp_handel_cart_cart->clear;\n"; ## cart:add } elsif ($tag eq 'add') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-1] ne 'results' || $context[-2] !~ /^(new|cart(s?))$/); push @context, $tag; my $code = "my \$_xsp_handel_cart_item;\nmy \$_xsp_handel_cart_called_add;\n"; $code .= scalar keys %attr ? 'my %_xsp_handel_cart_add_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_add_filter;' ; return "\n{\n$code\n"; ## cart:update } elsif ($tag eq 'update') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-1] ne 'results' || $context[-2] !~ /^((cart(s?)|item(s?)))$/); push @context, $tag; if ($context[-3] =~ /^(cart(s?))$/) { return "\n\$_xsp_handel_cart_cart->autoupdate(0);\n"; } elsif ($context[-3] =~ /^(item(s?))$/) { return "\n\$_xsp_handel_cart_item->autoupdate(0);\n"; }; return ''; } elsif ($tag eq 'save') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-2] !~ /^(cart(s?))$/); return ' $_xsp_handel_cart_cart->save; $_xsp_handel_cart_cart->update; '; ## cart:delete } elsif ($tag eq 'delete') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-1] ne 'results' || $context[-2] !~ /^(cart(s?))$/); push @context, $tag; my $code .= scalar keys %attr ? 'my %_xsp_handel_cart_delete_filter = ("' . join('", "', %attr) . '");' : 'my %_xsp_handel_cart_delete_filter;' ; return "\n{\n$code\n"; ## cart property tags ## cart:description, id, name, shopper, type, count, subtotal } elsif ($tag =~ /^(description|id|name|shopper|type|count|subtotal)$/) { if ($context[-1] eq 'new' && $tag !~ /^(count|subtotal)$/) { return "\n\$_xsp_handel_cart_new_filter{$tag} = ''"; } elsif ($context[-1] eq 'add' && $tag =~ /^(id|description)$/) { return "\n\$_xsp_handel_cart_add_filter{$tag} = ''"; } elsif ($context[-1] eq 'results' && $context[-2] =~ /^(new|cart(s?))$/) { $e->start_expr($tag); if ($tag eq 'subtotal' && ($attr{'format'} || $attr{'convert'})) { my $cfg = Handel::ConfigReader->new(); my $code = $attr{'to'} || $attr{'code'} || $cfg->{'HandelCurrencyCode'}; my $format = $attr{'options'} || $cfg->{'HandelCurrencyFormat'}; my $from = $attr{'from'} || $cfg->{'HandelCurrencyCode'}; my $to = $attr{'to'} || $attr{'code'} || $cfg->{'HandelCurrencyCode'}; AxKit::Debug(5, "[Handel] [Cart] [$tag] code=$code, format=$format, from=$from, to=$to"); if ($attr{'convert'}) { $e->append_to_script("Handel::Compat::Currency::convert(Handel::Compat::Currency->new(\$_xsp_handel_cart_cart->$tag->value), '$from', '$to', '".($attr{'format'}||'')."', '$format');\n"); } elsif ($attr{'format'}) { $e->append_to_script("Handel::Compat::Currency::format(Handel::Compat::Currency->new(\$_xsp_handel_cart_cart->$tag->value), '$code', '$format');\n"); }; } elsif ($tag eq 'subtotal') { $e->append_to_script("\$_xsp_handel_cart_cart->$tag->value;\n"); } else { $e->append_to_script("\$_xsp_handel_cart_cart->$tag;\n"); }; } elsif ($context[-1] eq 'results' && $context[-2] eq 'item') { $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_item->$tag;\n"); } elsif ($context[-1] eq 'results' && $context[-2] eq 'items') { $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_item->$tag;\n"); } elsif ($context[-1] eq 'results' && $context[-2] eq 'add') { $e->start_expr($tag); $e->append_to_script("\$_xsp_handel_cart_item->$tag;\n"); } elsif ($context[-1] eq 'delete' && $tag !~ /^(count|subtotal)$/) { return "\n\$_xsp_handel_cart_delete_filter{$tag} = ''"; } elsif ($context[-1] eq 'update') { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($tag eq 'id'); if ($context[-3] =~ /^(cart(s?))$/) { return "\n\$_xsp_handel_cart_cart->$tag(''"; } elsif ($context[-3] =~ /^(item(s?))$/) { return "\n\$_xsp_handel_cart_item->$tag(''"; }; }; ## cart item property tags ## cart:sku, price, quantity, total } elsif ($tag =~ /^(sku|price|quantity|total)$/) { if ($context[-1] eq 'add' && $tag ne 'total') { return "\n\$_xsp_handel_cart_add_filter{$tag} = ''"; #} elsif ($context[-1] eq 'results' && $context[-2] eq 'add') { # $e->start_expr($tag); # $e->append_to_script("\$_xsp_handel_cart_item->$tag;\n"); } elsif ($context[-1] eq 'results' && $context[-2] =~ /^(item(s?)|add)$/) { $e->start_expr($tag); if ($tag =~ /^(price|total)$/ && ($attr{'format'} || $attr{'convert'})) { my $cfg = Handel::ConfigReader->new(); my $code = $attr{'to'} || $attr{'code'} || $cfg->{'HandelCurrencyCode'}; my $format = $attr{'options'} || $cfg->{'HandelCurrencyFormat'}; my $from = $attr{'from'} || $cfg->{'HandelCurrencyCode'}; my $to = $attr{'to'} || $attr{'code'} || $cfg->{'HandelCurrencyCode'}; AxKit::Debug(5, "[Handel] [Cart] [$tag] code=$code, format=$format, from=$from, to=$to"); if ($attr{'convert'}) { $e->append_to_script("Handel::Compat::Currency::convert(Handel::Compat::Currency->new(\$_xsp_handel_cart_item->$tag->value), '$from', '$to', '".($attr{'format'}||'')."', '$format');\n"); } elsif ($attr{'format'}) { $e->append_to_script("Handel::Compat::Currency::format(Handel::Compat::Currency->new(\$_xsp_handel_cart_item->$tag->value), '$code', '$format');\n"); }; } elsif ($tag =~ /^(price|total)$/) { $e->append_to_script("\$_xsp_handel_cart_item->$tag->value;\n"); } else { $e->append_to_script("\$_xsp_handel_cart_item->$tag;\n"); }; } elsif ($context[-1] eq 'delete') { return "\n\$_xsp_handel_cart_delete_filter{$tag} = ''"; } elsif ($context[-1] eq 'update') { if ($context[-3] =~ /^(cart(s?))$/) { return "\n\$_xsp_handel_cart_cart->$tag(''"; } elsif ($context[-3] =~ /^(item(s?))$/) { return "\n\$_xsp_handel_cart_item->$tag(''"; }; }; ## cart:filter } elsif ($tag eq 'filter') { my $key = $attr{'name'} || 'id'; if ($context[-1] eq 'cart') { return "\n\$_xsp_handel_cart_load_filter{'$key'} = ''"; } elsif ($context[-1] eq 'carts') { return "\n\$_xsp_handel_carts_load_filter{'$key'} = ''"; } elsif ($context[-1] eq 'item') { return "\n\$_xsp_handel_cart_item_filter{'$key'} = ''"; } elsif ($context[-1] eq 'items') { return "\n\$_xsp_handel_cart_items_filter{'$key'} = ''"; } elsif ($context[-1] eq 'restore') { return "\n\$_xsp_handel_cart_restore_filter{'$key'} = ''"; }; ## cart:results } elsif ($tag =~ /^result(s?)$/) { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-1] !~ /^(new|add|cart(s?)|item(s?))$/); push @context, $tag; if ($context[-2] eq 'new') { return ' if (!$_xsp_handel_cart_called_new && scalar keys %_xsp_handel_cart_new_filter) { $_xsp_handel_cart_cart = Handel::Cart->create(\%_xsp_handel_cart_new_filter); $_xsp_handel_cart_called_new = 1; }; if ($_xsp_handel_cart_cart) { '; } elsif ($context[-2] eq 'cart') { return ' if (!$_xsp_handel_cart_called_load) { $_xsp_handel_cart_cart = (scalar keys %_xsp_handel_cart_load_filter) ? Handel::Cart->search(\%_xsp_handel_cart_load_filter)->next : Handel::Cart->search->next; $_xsp_handel_cart_called_load = 1; }; if ($_xsp_handel_cart_cart) { '; } elsif ($context[-2] eq 'carts') { return ' if (!$_xsp_handel_carts_called_load) { @_xsp_handel_cart_carts = (scalar keys %_xsp_handel_carts_load_filter) ? Handel::Cart->search(\%_xsp_handel_carts_load_filter) : Handel::Cart->search; $_xsp_handel_carts_called_load = 1; }; foreach my $_xsp_handel_cart_cart (@_xsp_handel_cart_carts) { '; } elsif ($context[-2] eq 'item') { return ' if (!$_xsp_handel_cart_called_item) { $_xsp_handel_cart_item = (scalar keys %_xsp_handel_cart_item_filter) ? $_xsp_handel_cart_cart->items(\%_xsp_handel_cart_item_filter)->next : $_xsp_handel_cart_cart->items->next; $_xsp_handel_cart_called_item = 1; }; if ($_xsp_handel_cart_item) { '; } elsif ($context[-2] eq 'items') { return ' if (!$_xsp_handel_cart_called_items) { @_xsp_handel_cart_items = (scalar keys %_xsp_handel_cart_items_filter) ? $_xsp_handel_cart_cart->items(\%_xsp_handel_cart_items_filter) : $_xsp_handel_cart_cart->items; $_xsp_handel_cart_called_items = 1; }; foreach my $_xsp_handel_cart_item (@_xsp_handel_cart_items) { '; } elsif ($context[-2] eq 'add') { return ' if (!$_xsp_handel_cart_called_add && scalar keys %_xsp_handel_cart_add_filter) { $_xsp_handel_cart_item = $_xsp_handel_cart_cart->add(\%_xsp_handel_cart_add_filter); $_xsp_handel_cart_called_add = 1; }; if ($_xsp_handel_cart_item) { '; }; ## cart:no-results } elsif ($tag =~ /^no-result(s?)$/) { throw Handel::Exception::Taglib( -text => translate('TAG_NOT_ALLOWED_HERE', $tag) ) if ($context[-1] !~ /^(new|add|cart(s?)|item(s?))$/); push @context, $tag; if ($context[-2] eq 'new') { return ' if (!$_xsp_handel_cart_called_new && scalar keys %_xsp_handel_cart_new_filter) { $_xsp_handel_cart_cart = Handel::Cart->create(\%_xsp_handel_cart_new_filter); $_xsp_handel_cart_called_new = 1; }; if (!$_xsp_handel_cart_cart) { '; } elsif ($context[-2] eq 'cart') { return ' if (!$_xsp_handel_cart_called_load) { $_xsp_handel_cart_cart = (scalar keys %_xsp_handel_cart_load_filter) ? Handel::Cart->search(\%_xsp_handel_cart_load_filter)->next : Handel::Cart->search->next; $_xsp_handel_cart_called_load = 1; }; if (!$_xsp_handel_cart_cart) { '; } elsif ($context[-2] eq 'carts') { return ' if (!$_xsp_handel_carts_called_load) { @_xsp_handel_cart_carts = (scalar keys %_xsp_handel_carts_load_filter) ? Handel::Cart->search(\%_xsp_handel_carts_load_filter) : Handel::Cart->search; $_xsp_handel_carts_called_load = 1; }; if (!scalar @_xsp_handel_cart_carts) { '; } elsif ($context[-2] eq 'item') { return ' if (!$_xsp_handel_cart_called_item) { $_xsp_handel_cart_item = (scalar keys %_xsp_handel_cart_item_filter) ? $_xsp_handel_cart_cart->items(\%_xsp_handel_cart_item_filter)->next : $_xsp_handel_cart_cart->items->next; $_xsp_handel_cart_called_item = 1; }; if (!$_xsp_handel_cart_item) { '; } elsif ($context[-2] eq 'items') { return ' if (!$_xsp_handel_cart_called_items) { @_xsp_handel_cart_items = (scalar keys %_xsp_handel_cart_items_filter) ? $_xsp_handel_cart_cart->items(\%_xsp_handel_cart_items_filter) : $_xsp_handel_cart_cart->items; $_xsp_handel_cart_called_items = 1; }; if (!scalar @_xsp_handel_cart_items) { '; } elsif ($context[-2] eq 'add') { return ' if (!$_xsp_handel_cart_called_add && scalar keys %_xsp_handel_cart_add_filter) { $_xsp_handel_cart_item = $_xsp_handel_cart_cart->add(\%_xsp_handel_cart_add_filter); $_xsp_handel_cart_called_add = 1; }; if (!$_xsp_handel_cart_item) { '; }; }; return ''; }; sub parse_end { my ($e, $tag) = @_; AxKit::Debug(5, "[Handel] [Cart] parse_end: [$tag] context: " . join('->', @context)); ## cart:new if ($tag eq 'new') { pop @context; return ' if (!$_xsp_handel_cart_called_new && scalar keys %_xsp_handel_cart_new_filter) { $_xsp_handel_cart_cart = Handel::Cart->create(\%_xsp_handel_cart_new_filter); $_xsp_handel_cart_called_new = 1; }; };'; ## cart:restore } elsif ($tag eq 'restore') { pop @context; return ' $_xsp_handel_cart_cart->restore(\%_xsp_handel_cart_restore_filter, $_xsp_handel_cart_restore_mode); }; '; ## cart:cart } elsif ($tag eq 'cart') { pop @context; return "\n};\n"; ## cart:carts } elsif ($tag eq 'carts') { pop @context; return "\n};\n"; ## cart:item } elsif ($tag eq 'item') { pop @context; return "\n};\n"; ## cart:items } elsif ($tag eq 'items') { pop @context; return "\n};\n"; ## cart:add } elsif ($tag eq 'add') { pop @context; return ' if (!$_xsp_handel_cart_called_add && scalar keys %_xsp_handel_cart_add_filter) { $_xsp_handel_cart_item = $_xsp_handel_cart_cart->add(\%_xsp_handel_cart_add_filter); $_xsp_handel_cart_called_add = 1; }; }; '; ## cart:update } elsif ($tag eq 'update') { if ($context[-3] =~ /^(cart(s?))$/) { pop @context; return ' $_xsp_handel_cart_cart->update; $_xsp_handel_cart_cart->autoupdate(1); '; } elsif ($context[-3] =~ /^(item(s?))$/) { pop @context; return ' $_xsp_handel_cart_item->update; $_xsp_handel_cart_item->autoupdate(1); '; }; pop @context; ## cart:delete } elsif ($tag eq 'delete') { pop @context; return ' if (scalar keys %_xsp_handel_cart_delete_filter) { $_xsp_handel_cart_cart->delete(\%_xsp_handel_cart_delete_filter); }; }; '; ## cart propery tags ## cart:description, id, name, shopper, type, count, subtotal } elsif ($tag =~ /^(description|id|name|shopper|type|count|subtotal)$/) { if ($context[-1] eq 'new' && $tag !~ /^(count|subtotal)$/) { return ";\n"; } elsif ($context[-1] eq 'add' && $tag !~ /^(count|subtotal)$/) { return ";\n"; } elsif ($context[-1] eq 'results') { $e->end_expr($tag); } elsif ($context[-1] eq 'delete' && $tag !~ /^(count|subtotal)$/) { return ";\n"; } elsif ($context[-1] eq 'update') { if ($context[-3] =~ /^(cart(s?))$/) { return ");\n"; } elsif ($context[-3] =~ /^(item(s?))$/) { return ");\n"; }; }; ## cart item property tags ## cart:sku, price, quantity } elsif ($tag =~ /^(sku|price|quantity|total)$/) { if ($context[-1] eq 'add' && $tag ne 'total') { return ";\n"; } elsif ($context[-1] eq 'results' && $context[-2] eq 'add') { $e->end_expr($tag); } elsif ($context[-1] eq 'results' && $context[-2] eq 'item') { $e->end_expr($tag); } elsif ($context[-1] eq 'results' && $context[-2] eq 'items') { $e->end_expr($tag); } elsif ($context[-1] eq 'delete' && $tag !~ /^(count|subtotal)$/) { return ";\n"; } elsif ($context[-1] eq 'update') { if ($context[-3] =~ /^(cart(s?))$/) { return ");\n"; } elsif ($context[-3] =~ /^(item(s?))$/) { return ");\n"; }; }; ## cart:filter } elsif ($tag eq 'filter') { if ($context[-1] eq 'cart') { return ";\n"; } elsif ($context[-1] eq 'carts') { return ";\n"; } elsif ($context[-1] eq 'item') { return ";\n"; } elsif ($context[-1] eq 'items') { return ";\n"; } elsif ($context[-1] eq 'restore') { return ";\n"; }; ## cart:results } elsif ($tag =~ /^result(s?)$/) { if ($context[-2] eq 'new') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'cart') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'carts') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'item') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'items') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'add') { pop @context; return "\n};\n"; }; pop @context; ## cart:no-results } elsif ($tag =~ /^no-result(s?)$/) { if ($context[-2] eq 'new') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'cart') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'carts') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'item') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'items') { pop @context; return "\n};\n"; } elsif ($context[-2] eq 'add') { pop @context; return "\n};\n"; }; pop @context; }; return ''; }; #}; 1; __END__ =head1 NAME AxKit::XSP::Handel::Cart - AxKit XSP Shopping Cart Taglib =head1 SYNOPSIS Add this taglib to AxKit in your http.conf or .htaccess: AxAddXSPTaglib AxKit::XSP::Handel::Cart Add the namespace to your XSP file and use the tags: There are currently no items in your shopping cart. The cart requested could not be found. =head1 DESCRIPTION This tag library provides an interface to use C inside of your AxKit XSP pages. =head1 CHANGES Starting in version C<0.09>, Ccart:typeE>, the C attribute, and the C attribute in Ccart:restoreE> now take the constants declared in C: CART_TYPE_SAVED ... ... Starting in version C<0.13>, the currency formatting options from C are now available within the taglib: Starting in version C<0.15>, the currency conversion options from C are now available within the taglib: =head1 TAG HIERARCHY value value value value value value value value value value ... ... value value value value value value ... value value value value value value value value value value ... value ... =head1 TAG REFERENCE =head2 Adds an a item to the current cart. You can specify the item properties as attributes in the tag itself: or you can add them as child elements: My New Part 11111111-1111-1111-1111-111111111111 1234 1 1.23 or any combination of the two: My New Part 11111111-1111-1111-1111-111111111111 1234 1.23 This tag is only valid within the Ccart:resultsE> block for C and C. See C for more information about adding parts to the shopping cart. You can also access the newly added item using the Ccart:resultsE>. =head2 Container tag for the current cart used to load a specific cart. If C or its Cs load more than one cart, C will contain only the first cart. If you're looking for loop through multiple carts, try Ccart:cartsE> instead. 11111111-1111-1111-1111-111111111111 < ... The cart requested could not be found. =head2 Loops through all loaded carts. 11111111-1111-1111-1111-111111111111 < ... No carts were found matching your query. =head2 Deletes all items in the current shopping cart. 11111111-1111-1111-1111-111111111111 The cart requested could not be found. =head2 Returns the number of items in the current shopping cart. < The cart requested could not be found. =head2 Context aware tag to get or set the description of various other parent tags. Within Ccart:cartE> or Ccart:cartsE> it returns the current carts description: Within Ccart:addE> or Ccart:updateE> it sets the current cart or cart items description: My Updated Cart Description My New SKU Description My Updated SKU Description The cart item could not be found for updating The cart requested could not be found. =head2 Adds a new name/value pair to the filter used in Ccart:cartE>, Ccart:cartsE>, Ccart:deleteE>, Ccart:itemE>, and Ccart:itemsE>. Pass the name of the pair in the C attribute and the value between the start and end filter tags: 12345678-9098-7654-3212-345678909876 sku1234 The cart item could not be found for deletion If the same attribute is specified in a filter, the child filter tag value takes precedence over the parent tags attribute. 1 You can supply as many Cs as needed to get the job done. 0 12345678-9098-7654-3212-345678909876 =head2 Context aware tag to get or set the record id within various other tags. In Ccart:cartE> and Ccart:itemE> it returns the record id for the object: The cart requested could not be found. Within Ccart:addE>, Ccart:deleteE>, and Ccart:newE> it sets the id value used in the operation specified: 11111111-1111-1111-1111-111111111111 The cart requested could not be found. ... 11112222-3333-4444-5555-6666777788889999 New Cart It cannot be used within Ccart:updateE> and will return a C exception if you try updating the record ids which are the primary keys. =head2 Loops through all items in the current cart: Your shopping cart is empty The cart requested could not be found. =head2 Context aware tag to get or set the name within various other tags. In Ccart:cartE> it returns the name for the cart object: ... The cart requested could not be found. Within Ccart:updateE> and Ccart:newE> it sets the name value used in the operation specified: My Updated Cart Name The cart requested could not be found. ... New Cart =head2 Creates a new shopping cart using the supplied attributes and child tags: 22222222-2222-2222-2222-222222222222 New Cart The child tags take precedence over the attributes of the same name. C B within it's declared namespace. It will throw an C exception otherwise. =head2 Context aware tag to get or set the price of a cart item. In Ccart:addE> and Ccart:updateE> it sets the price: 1.24 The cart requested could not be found. In Ccart:itemE> or Ccart:itemsE> it returns the price for the cart item: Your shopping cart is empty The cart requested could not be found. =head3 Currency Formatting Starting in version C<0.13>, the currency formatting options from C are now available within the taglib if C is installed. =over =item format Toggle switch that enables or disables currency formatting. If empty, unspecified, or set to 0, no formatting will take place and the result price (usually in decimal form) is returned unaltered. If C is set to anything else, the default formatting will be applied. See C for the default currency formatting settings. =item code If formatting is enabled, the C attribute specifies the desired three letter ISO currency code to be used when formatting currency. See C for the available codes. If you are also using the currency conversion options below, the value of C will always be used first, even if C is not empty. If C is empty and C is also empty, the C configuration setting will be used instead. =item options If formatting is enabled, the C attribute specifies the desired formatting options to be used when formatting currency. See C for the available options. =back =head3 Currency Conversion Starting in version C<0.15>, the currency conversion options from C are now available within the taglib if C is installed. =over =item convert Toggle switch that enables or disables currency conversion. If empty, unspecified, or set to 0, no currency conversion will take place and the result price is returned unaltered. If C is set to anything else, the default conversion will be applied. See C for the default currency conversion settings. =item from If conversion is enabled, the C attribute specifies the three letter ISO currency code of the price to be converted. If no C is specified, the C configuration setting will be used instead. See C for the available codes. =item to If conversion is enabled, the C attribute specifies what the current C should be converted to. If no C is specified, the C attribute from the formatting options above will be used instead. If both C and C are empty, the C configuration setting will be used as a last resort. =back If you try to convert from and to the same currency, the C is returned as is. =head3 Precedence If you are using both the currency conversion and the currency formatting options, the conversion will be performed first, then the result will be formatted. =head2 Context aware tag to get or set the quantity of a cart item. In Ccart:addE> and Ccart:updateE> it sets the quantity: 1.24 The cart requested could not be found. In Ccart:itemE> or Ccart:itemsE> it returns the quantity for the cart item: The item requested could not be found for updating The cart requested could not be found. =head2 Updates the current cart values: My Updated Cart Name The cart requested could not be found. Ccart:idE> is not valid within an update statement. =head2 Contains the results for the current action. both the singular and plural forms are valid for your syntactic sanity: ... =head2 The anti-results or 'not found' tag. This tag is executed when C, C, C, or C fails to find a match for it's filters. As with Ccart:resultsE>, both the singular and plural forms are available for your enjoyment: ... =head2 Restores another cart into the current cart. 11111111-1111-1111-1111-111111111111 See L for the available C values. =head2 Saves the current cart by setting its type to C: The cart requested could not be found. =head2 Context aware tag that gets or sets the shopper id for the current cart. =head2 Context aware tag to get or set the sku of a cart item. In Ccart:addE> and Ccart:updateE> it sets the sku: sku1234 The cart requested could not be found. In Ccart:itemE> or Ccart:itemsE> it returns the sku for the current cart item: Your shopping cart is empty The cart requested could not be found. =head2 Returns the subtotal of the items in the current cart: The cart requested could not be found. Starting in version C<0.13>, the currency formatting options from C are now available within the taglib. Starting in version C<0.15>, the currency conversion options from C are now available within the taglib. See above for further details about price formatting. =head2 Returns the total of the current cart item: Your shopping cart is empty The cart requested could not be found. Starting in version C<0.13>, the currency formatting options from C are now available within the taglib. Starting in version C<0.15>, the currency conversion options from C are now available within the taglib. See above for further details about price formatting. =head2 Context aware tag to get or set the type within various other tags. In Ccart:cartE> or Ccart:cartsE> it returns the type for the object: The cart requested could not be found. Within Ccart:updateE> and Ccart:newE> it sets the type value used in the operation specified: 1 The cart requested could not be found. ... 1 =head2 This tag returns a new uuid/guid for use in C and C in the following format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx For those like me who always type the wrong thing, Ccart:guid/> returns the same things as Ccart:uuid/>. =head1 AUTHOR Christopher H. Laco CPAN ID: CLACO claco@chrislaco.com http://today.icantfocus.com/blog/