Show
Ignore:
Timestamp:
05/28/06 10:08:06 (2 years ago)
Author:
ogawa
Message:

Lots of changes.
Fix for memory leak in the persistent environments such as FastCGI.
Now properly update MT::PluginData? when removing entries.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • tagwire/trunk/tagwire.pl

    r198 r211  
    1 # Tagwire Plugin (aka AllKeywords Plugin) 
    2 # a plugin for listing and handling "tags" 
     1# Tagwire - A plugin for listing and handling "tags" 
    32# 
    43# $Id$ 
     
    76# personal use. If you distribute it, please keep this notice intact. 
    87# 
    9 # Copyright (c) 2005 Hirotaka Ogawa 
     8# Copyright (c) 2005,2006 Hirotaka Ogawa 
    109 
    1110package MT::Plugin::Tagwire; 
    1211use strict; 
     12use MT; 
     13use base qw(MT::Plugin); 
     14 
    1315use MT::Template::Context; 
     16use MT::Entry; 
    1417use MT::Request; 
    15 use vars qw($VERSION); 
    16  
    17 $VERSION = '0.25'; 
    1818 
    1919# DEBUG 
    2020my $FORCE_PD_REFRESH = 0; 
    21 my $ENABLE_PD_INDEXES = 1; 
    22 my $ENABLE_REQ_CACHE = 1; 
    23  
     21 
     22our $HAVE_MT_PLUGINDATA = 0; 
     23our $HAVE_MT_XSEARCH = 0; 
     24 
     25our $cache; 
    2426my $plugin; 
    25 eval { 
    26     require MT::Plugin; 
    27     $plugin = new MT::Plugin({ 
     27 
     28BEGIN { 
     29    our $VERSION = '0.26'; 
     30    $plugin = __PACKAGE__->new({ 
    2831        name => 'Tagwire Plugin', 
    2932        description => 'A plugin for listing and handling blog-wide tags and entry tags.', 
    30         doc_link => 'http://as-is.net/wiki/Tagwire_Plugin', 
     33        doc_link => 'http://as-is.net/hacks/2005/06/tagwire_plugin.html', 
    3134        author_name => 'Hirotaka Ogawa', 
    3235        author_link => 'http://profile.typekey.com/ogawa/', 
    33         version => $VERSION 
     36        version => $VERSION, 
     37    }); 
     38    MT->add_plugin($plugin); 
     39 
     40    eval { require MT::PluginData; $HAVE_MT_PLUGINDATA = 1 }; 
     41 
     42    if ($HAVE_MT_PLUGINDATA) { 
     43        MT::Entry->add_callback('post_save', 10, $plugin, \&post_save); 
     44        MT::Entry->add_callback('post_remove', 10, $plugin, \&post_remove); 
     45    } 
     46 
     47    $cache = MT::Request->instance; 
     48 
     49    MT::Template::Context->add_container_tag(Tags => \&tags); 
     50    MT::Template::Context->add_container_tag(EntryTags => \&entry_tags); 
     51    MT::Template::Context->add_container_tag(RelatedTags => \&related_tags); 
     52    MT::Template::Context->add_tag(Tag => \&tag); 
     53    MT::Template::Context->add_tag(TagCount => \&tag_count); 
     54    MT::Template::Context->add_tag(TagDate => \&tag_date); 
     55    MT::Template::Context->add_tag(TagsTotal => \&tags_total); 
     56    MT::Template::Context->add_tag(TagsTotalSum => \&tags_total_sum); 
     57    MT::Template::Context->add_container_tag(EntriesWithTags => \&entries); 
     58    MT::Template::Context->add_container_tag(MostRelatedEntries => \&most_related_entries); 
     59    MT::Template::Context->add_global_filter(encode_urlplus => \&encode_urlplus); 
     60 
     61    # For compatibility (this plugin was formerly named 'AllKeywords') 
     62    MT::Template::Context->add_container_tag(AllKeywords => \&tags); 
     63    MT::Template::Context->add_container_tag(EntryAllKeywords => \&entry_tags); 
     64    MT::Template::Context->add_tag(AllKeyword => \&tag); 
     65    MT::Template::Context->add_tag(AllKeywordCount => \&tag_count); 
     66    MT::Template::Context->add_tag(AllKeywordsTotal => \&tags_total); 
     67    MT::Template::Context->add_tag(AllKeywordsTotalSum => \&tags_total_sum); 
     68    MT::Template::Context->add_container_tag(EntriesWithKeywords => \&entries); 
     69 
     70    eval { require MT::XSearch; $HAVE_MT_XSEARCH = 1 }; 
     71 
     72    if ($HAVE_MT_XSEARCH) { 
     73        MT::XSearch->add_search_plugin('Tagwire', { 
     74            label => 'Tag(Keyword) Search', 
     75            description => 'Tag(Keyword) Search plugin for MT-XSearch', 
     76            on_execute => \&xsearch_on_execute, 
     77            on_stash => \&xsearch_on_stash, 
    3478        }); 
    35     MT->add_plugin($plugin); 
    36 }; 
    37  
    38 if (MT->can('add_callback')) { 
    39     my $mt = MT->instance; 
    40     MT->add_callback((ref $mt eq 'MT::App::CMS' ? 'AppPostEntrySave' : 'MT::Entry::post_save'), 
    41                      10, $plugin, \&update_pd_indexes); 
    42 } 
    43  
    44 sub update_pd_indexes { 
    45     return unless $ENABLE_PD_INDEXES && $plugin; 
    46     my ($eh, $app, $entry) = @_; 
    47     require MT::Entry; 
     79        MT::Template::Context->add_container_tag(XSearchTags => \&xsearch_tags); 
     80    } 
     81} 
     82 
     83sub post_save { 
     84    my ($eh, $dummy, $obj) = @_; 
     85    update_plugindata($obj); 
     86} 
     87 
     88sub post_remove { 
     89    my ($eh, $obj) = @_; 
     90    # set it to be "draft" to remove 
     91    $obj->status(MT::Entry::HOLD()) if $obj->status == MT::Entry::RELEASE(); 
     92    update_plugindata($obj); 
     93} 
     94 
     95sub update_plugindata { 
     96    return unless $HAVE_MT_PLUGINDATA && $plugin; 
     97    my ($entry) = @_; 
     98    my $refresh = $FORCE_PD_REFRESH || 0; 
     99    my $version = $plugin->version; 
    48100    my $blog_id = $entry->blog_id; 
    49     require MT::PluginData; 
    50101    my $pd = MT::PluginData->load({ plugin => $plugin->name, 
    51102                                    key => $blog_id }); 
    52     my (%eindex, %tindex); 
    53     my $data; 
    54     my $refresh = $FORCE_PD_REFRESH || 0; 
    55103    if (!$pd) { 
    56104        $pd = new MT::PluginData(); 
     
    59107        $refresh = 1; 
    60108    } 
    61     $data = $pd->data() || {}; 
    62     $refresh = 1 if !exists $data->{version} || ${$data->{version}} ne $VERSION; 
     109    my $data = $pd->data() || {}; 
     110 
     111    $refresh = 1 if !exists $data->{version} || ${$data->{version}} ne $version; 
     112 
     113    my (%eindex, %tindex); 
    63114    if ($refresh) { 
    64115        my $iter = MT::Entry->load_iter({ blog_id => $blog_id, 
     
    86137        } 
    87138    } 
    88     $data->{version} = \$VERSION; 
     139    $data->{version} = \$version; 
    89140    $data->{eindex} = \%eindex; 
    90141    $data->{tindex} = \%tindex; 
    91142    $pd->data($data); 
    92143    $pd->save or die $pd->errstr; 
    93     if ($ENABLE_REQ_CACHE) { 
    94         my $r = MT::Request->instance; 
    95         $r->cache('Tagwire::Cache::' . $blog_id, undef); 
    96     } 
    97 } 
    98  
    99 MT::Template::Context->add_container_tag('Tags' => \&tags); 
    100 MT::Template::Context->add_container_tag('EntryTags' => \&entry_tags); 
    101 MT::Template::Context->add_container_tag('RelatedTags' => \&related_tags); 
    102 MT::Template::Context->add_tag('Tag' => \&tag); 
    103 MT::Template::Context->add_tag('TagCount' => \&tag_count); 
    104 MT::Template::Context->add_tag('TagDate' => \&tag_date); 
    105 MT::Template::Context->add_tag('TagsTotal' => \&tags_total); 
    106 MT::Template::Context->add_tag('TagsTotalSum' => \&tags_total_sum); 
    107 MT::Template::Context->add_container_tag('EntriesWithTags' => \&entries); 
    108 MT::Template::Context->add_container_tag('MostRelatedEntries' => \&most_related_entries); 
    109 MT::Template::Context->add_global_filter('encode_urlplus' => \&encode_urlplus); 
    110  
    111 # For compatibility (this plugin was formerly named 'AllKeywords') 
    112 MT::Template::Context->add_container_tag('AllKeywords' => \&tags); 
    113 MT::Template::Context->add_container_tag('EntryAllKeywords' => \&entry_tags); 
    114 MT::Template::Context->add_tag('AllKeyword' => \&tag); 
    115 MT::Template::Context->add_tag('AllKeywordCount' => \&tag_count); 
    116 MT::Template::Context->add_tag('AllKeywordsTotal' => \&tags_total); 
    117 MT::Template::Context->add_tag('AllKeywordsTotalSum' => \&tags_total_sum); 
    118 MT::Template::Context->add_container_tag('EntriesWithKeywords' => \&entries); 
     144    $cache->cache('Tagwire::Cache::' . $blog_id, undef); 
     145} 
    119146 
    120147sub split_args { 
     
    162189} 
    163190 
    164 sub get_pd_indexes { 
    165     return unless $ENABLE_PD_INDEXES && $plugin; 
    166     my $blog_id = $_[0] or return; 
    167     my ($r, $cname); 
    168     if ($ENABLE_REQ_CACHE) { 
    169         $r = MT::Request->instance; 
    170         $cname = 'Tagwire::Cache::' . $blog_id; 
    171         return $r->cache($cname) if defined $r->cache($cname); 
    172         $r->cache($cname, undef); 
    173     } 
     191sub get_indexes { 
     192    my $blog_id = shift or return; 
     193    my $cname = 'Tagwire::Cache::' . $blog_id; 
     194    return $cache->cache($cname) if defined $cache->cache($cname); 
     195    $cache->cache($cname, undef); 
     196 
    174197    my $data; 
    175     eval { 
    176         require MT::PluginData; 
     198    if ($HAVE_MT_PLUGINDATA && $plugin) { 
    177199        my $pd = MT::PluginData->load({ plugin => $plugin->name, 
    178200                                        key => $blog_id }); 
    179201        $data = $pd->data() if $pd; 
    180     }; 
    181     return if !exists $data->{version} || ${$data->{version}} ne $VERSION; 
    182     $r->cache($cname, $data) if $ENABLE_REQ_CACHE && $data; 
    183     $data; 
    184 } 
    185  
    186 sub get_db_indexes { 
    187     my $blog_id = $_[0] or return; 
    188     my ($r, $cname); 
    189     if ($ENABLE_REQ_CACHE) { 
    190         $r = MT::Request->instance; 
    191         $cname = 'Tagwire::Cache::' . $blog_id; 
    192         return $r->cache($cname) if defined $r->cache($cname); 
    193         $r->cache($cname, undef); 
    194     } 
    195     my $data; 
    196     my (%eindex, %tindex); 
     202 
     203        $data = undef if (!exists $data->{version} || ${$data->{version}} ne $plugin->version); 
     204    } 
     205 
     206    $data = get_indexes_from_db($blog_id) unless defined $data; 
     207 
     208    $cache->cache($cname, $data) if $data; 
     209} 
     210 
     211sub get_indexes_from_db { 
     212    my $blog_id = shift or return; 
     213    my ($eindex, $tindex); 
    197214    my $iter = MT::Entry->load_iter({ blog_id => $blog_id, 
    198215                                      status => MT::Entry::RELEASE() }); 
    199216    while (my $e = $iter->()) { 
    200217        my @tags = split_tags($e->keywords, 1) or next; 
    201         $eindex{$e->id} = { tags => \@tags, 
    202                             created_on => $e->created_on }; 
    203     } 
    204     foreach my $eid (keys %eindex) { 
    205         my $ts = $eindex{$eid}->{created_on}; 
    206         foreach (@{$eindex{$eid}->{tags}}) { 
    207             push @{$tindex{$_}->{eids}}, $eid; 
    208             $tindex{$_}->{ts} = $ts if !exists $tindex{$_}->{ts} || $tindex{$_}->{ts} < $ts; 
    209         } 
    210     } 
    211     $data->{eindex} = \%eindex; 
    212     $data->{tindex} = \%tindex; 
    213     $r->cache($cname, $data) if $ENABLE_REQ_CACHE; 
     218        $eindex->{$e->id} = { tags => \@tags, 
     219                              created_on => $e->created_on }; 
     220    } 
     221    foreach my $eid (keys %$eindex) { 
     222        my $eidx = $eindex->{$eid}; 
     223        my $ts = $eidx->{created_on}; 
     224        foreach (@{$eidx->{tags}}) { 
     225            push @{$tindex->{$_}->{eids}}, $eid; 
     226            $tindex->{$_}->{ts} = $ts if !exists $tindex->{$_}->{ts} || $tindex->{$_}->{ts} < $ts; 
     227        } 
     228    } 
     229 
     230    my $data = { eindex => $eindex, tindex => $tindex }; 
    214231    $data; 
    215232} 
     
    228245        $args->{case_sensitive} : 1; 
    229246 
    230     my $blog_id = $ctx->stash('blog_id'); 
    231     my %tags = (); 
    232     my %ts = (); 
    233  
    234     my $data = get_pd_indexes($blog_id) || get_db_indexes($blog_id) 
    235         or return ''; 
    236     my %tindex = %{$data->{tindex}}; 
     247    my $data = get_indexes($ctx->stash('blog_id')) or return ''; 
     248    my $tindex = $data->{tindex}; 
     249 
     250    my %tags; 
    237251    if ($case_sensitive) { 
    238         foreach (keys %tindex) { 
    239             $tags{$_} = scalar @{$tindex{$_}->{eids}}; 
    240             $ts{$_} = $tindex{$_}->{ts}; 
    241         } 
    242     } else { 
    243         foreach (keys %tindex) { 
     252        foreach (keys %$tindex) { 
     253            my $tidx = $tindex->{$_}; 
     254            $tags{$_} = [ scalar @{$tidx->{eids}}, $tidx->{ts} ]; 
     255        } 
     256    } else { 
     257        foreach (keys %$tindex) { 
     258            my $tidx = $tindex->{$_}; 
    244259            my $t = lc $_; 
    245             $tags{$t} += scalar @{$tindex{$_}->{eids}}; 
    246             $ts{$t} = $tindex{$_}->{ts} if !exists $ts{$t} || $ts{$t} < $tindex{$_}->{ts}; 
     260            if (!exists $tags{$t}) { 
     261                $tags{$t} = [ scalar @{$tidx->{eids}}, $tidx->{ts} ]; 
     262            } else { 
     263                $tags{$t}[0] += scalar @{$tidx->{eids}}; 
     264                $tags{$t}[1] = $tidx->{ts} if $tags{$t}[1] < $tidx->{ts}; 
     265            } 
    247266        } 
    248267    } 
     
    259278    } else { 
    260279        @list = $sort_order eq 'ascend' ? 
    261             sort { $tags{$a} <=> $tags{$b} } keys %tags : 
    262             sort { $tags{$b} <=> $tags{$a} } keys %tags; 
     280            sort { $tags{$a}[0] <=> $tags{$b}[0] } keys %tags : 
     281            sort { $tags{$b}[0] <=> $tags{$a}[0] } keys %tags; 
    263282    } 
    264283 
     
    266285 
    267286    my $total_sum = 0; 
    268     $total_sum += $tags{$_} foreach (@list); 
     287    $total_sum += $tags{$_}[0] foreach (@list); 
    269288    $ctx->stash('Tagwire::tags_total_sum', $total_sum); 
    270289 
     
    276295        last if $lastn && $i >= $lastn; 
    277296        local $ctx->{__stash}{'Tagwire::tag'} = $_; 
    278         local $ctx->{__stash}{'Tagwire::tag_count'} = $tags{$_}; 
    279         local $ctx->{__stash}{'Tagwire::tag_date'} = $ts{$_}; 
     297        local $ctx->{__stash}{'Tagwire::tag_count'} = $tags{$_}[0]; 
     298        local $ctx->{__stash}{'Tagwire::tag_date'} = $tags{$_}[1]; 
    280299        defined(my $out = $builder->build($ctx, $tokens)) 
    281300            or return $ctx->error($ctx->errstr); 
     
    324343        $args->{case_sensitive} : 1; 
    325344 
    326     my $blog_id = $ctx->stash('blog_id'); 
    327     my %tags = (); 
    328     my %ts = (); 
    329  
    330     my $data = get_pd_indexes($blog_id) || get_db_indexes($blog_id) 
    331         or return ''; 
    332     my %tindex = %{$data->{tindex}}; 
    333     my %eindex = %{$data->{eindex}}; 
     345    my $data = get_indexes($ctx->stash('blog_id')) or return ''; 
     346    my ($tindex, $eindex) = ($data->{tindex}, $data->{eindex}); 
     347 
     348    my %tags; 
    334349    if ($case_sensitive) { 
    335         foreach my $eid (@{$tindex{$tag}->{eids}}) { 
    336             foreach (@{$eindex{$eid}->{tags}}) { 
     350        foreach my $eid (@{$tindex->{$tag}->{eids}}) { 
     351            foreach (@{$eindex->{$eid}->{tags}}) { 
    337352                next if $_ eq $tag; 
    338                 $tags{$_} = exists $tags{$_} ? $tags{$_} + 1 : 1; 
    339                 $ts{$_} = $tindex{$_}->{ts} if !defined $ts{$_}; 
     353                if (!exists $tags{$_}) { 
     354                    $tags{$_} = [ 1, $tindex->{$_}->{ts} ]; 
     355                } else { 
     356                    $tags{$_}[0]++; 
     357                } 
    340358            } 
    341359        } 
    342360    } else { 
    343361        $tag = lc $tag; 
    344         foreach my $nctag (grep { lc $_ eq $tag } keys %tindex) { 
    345             foreach my $eid (@{$tindex{$nctag}->{eids}}) { 
    346                 foreach (@{$eindex{$eid}->{tags}}) { 
    347                     my $mtag = lc $_; 
    348                     next if $mtag eq $tag; 
    349                     $tags{$mtag} = exists $tags{$mtag} ? $tags{$mtag} + 1 : 1; 
    350                     $ts{$mtag} = $tindex{$_}->{ts} if $ts{$mtag} < $tindex{$_}->{ts}; 
     362        foreach my $nctag (grep { lc $_ eq $tag } keys %$tindex) { 
     363            foreach my $eid (@{$tindex->{$nctag}->{eids}}) { 
     364                foreach (@{$eindex->{$eid}->{tags}}) { 
     365                    my $t = lc $_; 
     366                    next if $t eq $tag; 
     367                    if (!exists $tags{$t}) { 
     368                        $tags{$t} = [ 1, $tindex->{$_}->{ts} ]; 
     369                    } else { 
     370                        $tags{$t}[0]++; 
     371                        $tags{$t}[1] = $tindex->{$_}->{ts} if $tags{$t}[1] < $tindex->{$_}->{ts}; 
     372                    } 
    351373                } 
    352374            } 
     
    364386    } else { 
    365387        @list = $sort_order eq 'ascend' ? 
    366             sort { $tags{$a} <=> $tags{$b} } keys %tags : 
    367             sort { $tags{$b} <=> $tags{$a} } keys %tags; 
     388            sort { $tags{$a}[0] <=> $tags{$b}[0] } keys %tags : 
     389            sort { $tags{$b}[0] <=> $tags{$a}[0] } keys %tags; 
    368390    } 
    369391 
     
    371393 
    372394    my $total_sum = 0; 
    373     $total_sum += $tags{$_} foreach (@list); 
     395    $total_sum += $tags{$_}[0] foreach (@list); 
    374396    $ctx->stash('Tagwire::tags_total_sum', $total_sum); 
    375397 
     
    381403        last if $lastn && $i >= $lastn; 
    382404        local $ctx->{__stash}{'Tagwire::tag'} = $_; 
    383         local $ctx->{__stash}{'Tagwire::tag_count'} = $tags{$_}; 
    384         local $ctx->{__stash}{'Tagwire::tag_date'} = $ts{$_}; 
     405        local $ctx->{__stash}{'Tagwire::tag_count'} = $tags{$_}[0]; 
     406        local $ctx->{__stash}{'Tagwire::tag_date'} = $tags{$_}[1]; 
    385407        defined(my $out = $builder->build($ctx, $tokens)) 
    386408            or return $ctx->error($ctx->errstr); 
     
    420442    # tags(keywords) (REQUIRED) 
    421443    my $search = $args->{tags} || $args->{keywords} or return ''; 
    422     # delimiter for "tags" argument (default = space characters) 
     444    # delimiter for "tags" argument (default = space) 
    423445    my $delimiter = $args->{delimiter} || ''; 
    424446    # case_sensitive (0/1, default = 1) 
     
    435457        or return ''; 
    436458 
    437     my $blog_id = $ctx->stash('blog_id'); 
    438     my $data = get_pd_indexes($blog_id) || get_db_indexes($blog_id) 
    439         or return ''; 
    440     my %tindex = %{$data->{tindex}}; 
    441     my %eindex = %{$data->{eindex}}; 
     459    my $data = get_indexes($ctx->stash('blog_id')) or return ''; 
     460    my ($tindex, $eindex) = ($data->{tindex}, $data->{eindex}); 
     461 
    442462    my %match; 
    443463    if ($case_sensitive) { 
    444464        foreach my $tag (@tags) { 
    445             foreach (@{$tindex{$tag}->{eids}}) { 
     465            foreach (@{$tindex->{$tag}->{eids}}) { 
    446466                $match{$_} = exists $match{$_} ? $match{$_} + 1 : 1; 
    447467            } 
     
    449469    } else { 
    450470        foreach my $tag (@tags) { 
    451             foreach my $mtag (grep { lc $_ eq $tag } keys %tindex) { 
    452                 foreach (@{$tindex{$mtag}->{eids}}) { 
     471            foreach my $t (grep { lc $_ eq $tag } keys %$tindex) { 
     472                foreach (@{$tindex->{$t}->{eids}}) { 
    453473                    $match{$_} = exists $match{$_} ? $match{$_} + 1 : 1; 
    454474                } 
     
    459479    my @eids = grep { $match{$_} == $count } keys %match or return ''; 
    460480    @eids = $sort_order eq 'descend' ? 
    461         sort { $eindex{$b}->{created_on} <=> $eindex{$a}->{created_on} } @eids : 
    462         sort { $eindex{$a}->{created_on} <=> $eindex{$b}->{created_on} } @eids; 
     481        sort { $eindex->{$b}->{created_on} <=> $eindex->{$a}->{created_on} } @eids : 
     482        sort { $eindex->{$a}->{created_on} <=> $eindex->{$b}->{created_on} } @eids; 
    463483    splice(@eids, $lastn) if $lastn && (scalar @eids > $lastn); 
    464     require MT::Entry; 
     484 
    465485    my @entries; 
    466486    map { push @entries, MT::Entry->load($_) } @eids; 
     
    507527        or return ''; 
    508528 
    509     my $blog_id = $ctx->stash('blog_id'); 
    510     my $data = get_pd_indexes($blog_id) || get_db_indexes($blog_id) 
    511         or return ''; 
    512     my %tindex = %{$data->{tindex}}; 
    513     my %eindex = %{$data->{eindex}}; 
     529    my $data = get_indexes($ctx->stash('blog_id')) or return ''; 
     530    my ($tindex, $eindex) = ($data->{tindex}, $data->{eindex}); 
     531 
    514532    my %match; 
     533    my $entry_id = $entry->id; 
    515534    if ($case_sensitive) { 
    516535        foreach my $tag (@tags) { 
    517             foreach (@{$tindex{$tag}->{eids}}) { 
    518                 next if $_ == $entry->id; 
     536            foreach (@{$tindex->{$tag}->{eids}}) { 
     537                next if $_ == $entry_id; 
    519538                $match{$_} = exists $match{$_} ? $match{$_} + 1 : 1; 
    520539            } 
     
    522541    } else { 
    523542        foreach my $tag (@tags) { 
    524             foreach my $mtag (grep { lc $_ eq $tag } keys %tindex) { 
    525                 foreach (@{$tindex{$mtag}->{eids}}) { 
    526                     next if $_ == $entry->id; 
     543            foreach my $t (grep { lc $_ eq $tag } keys %$tindex) { 
     544                foreach (@{$tindex->{$t}->{eids}}) { 
     545                    next if $_ == $entry_id; 
    527546                    $match{$_} = exists $match{$_} ? $match{$_} + 1 : 1; 
    528547                } 
     
    532551    my @eids = keys %match or return ''; 
    533552    @eids = $sort_order eq 'descend' ? 
    534         sort { $eindex{$b}->{created_on} <=> $eindex{$a}->{created_on} } @eids : 
    535         sort { $eindex{$a}->{created_on} <=> $eindex{$b}->{created_on} } @eids; 
     553        sort { $eindex->{$b}->{created_on} <=> $eindex->{$a}->{created_on} } @eids : 
     554        sort { $eindex->{$a}->{created_on} <=> $eindex->{$b}->{created_on} } @eids; 
    536555    @eids = sort { $match{$b} <=> $match{$a} } @eids; 
    537556    splice(@eids, $lastn) if $lastn && (scalar @eids > $lastn); 
    538     require MT::Entry; 
    539557    my @entries; 
    540558    map { push @entries, MT::Entry->load($_) } @eids; 
     
    564582} 
    565583 
     584use MT::Util; 
    566585sub encode_urlplus { 
    567586    my $s = $_[0]; 
    568587    return $s unless $_[1]; 
    569     require MT::Util; 
    570588    $s =~ tr/ /+/; 
    571589    MT::Util::encode_url($s); 
    572590} 
    573591 
    574 eval { 
    575     require MT::XSearch; 
    576     MT::XSearch->add_search_plugin('Tagwire', { 
    577         label => 'Tag(Keyword) Search', 
    578         description => 'Tag(Keyword) Search plugin for MT-XSearch', 
    579         on_execute => \&xsearch_on_execute, 
    580         on_stash => \&xsearch_on_stash }); 
    581 }; 
    582  
    583 MT::Template::Context->add_container_tag('XSearchTags' => \&xsearch_tags); 
    584592sub xsearch_tags { 
    585593    my ($ctx, $args, $cond) = @_; 
    586     my $r = MT::Request->instance; 
    587     return '' unless defined $r->cache('Tagwire::xsearch_tags'); 
    588     my @tags = @{$r->cache('Tagwire::xsearch_tags')}; 
     594 
     595    return '' unless defined $ctx->stash('xsearch_tags'); 
     596    my $tags = $ctx->stash('xsearch_tags'); 
     597 
    589598    my @res; 
    590599    my $builder = $ctx->stash('builder'); 
    591600    my $tokens = $ctx->stash('tokens'); 
    592     foreach (@tags) { 
     601    foreach (@$tags) { 
    593602        local $ctx->{__stash}{'Tagwire::tag'} = $_; 
    594603        defined(my $out = $builder->build($ctx, $tokens)) 
     
    601610 
    602611sub xsearch_on_stash { 
    603     $_[0]->stash('entry', $_[1]); 
    604     $_[0]->{current_timestamp} = $_[1]->created_on; 
    605     $_[0]->{modification_timestamp} = $_[1]->modified_on; 
     612    my ($ctx, $val, $self) = @_; 
     613    $ctx->stash('entry', $val); 
     614    $ctx->{current_timestamp} = $val->created_on; 
     615    $ctx->{modification_timestamp} = $val->modified_on; 
     616    $ctx->stash('xsearch_tags', $self->{xsearch_tags}); 
    606617} 
    607618 
    608619sub xsearch_on_execute { 
    609     my $args = shift; 
    610     my $blog_id = $args->{blog_id} or MT->error('Blog ID is required.'); 
    611     my $sort_by = $args->{sort_by} || 'created_on'; 
    612     my $sort_order = $args->{sort_order} || 'descend'; 
     620    my ($args, $self) = @_; 
     621 
     622    MT->error('Blog ID is required.') unless $args->{blog_id}; 
    613623    my $delimiter = $args->{delimiter} || ''; 
    614624    my $case_sensitive = defined $args->{case_sensitive} ? 
    615625        $args->{case_sensitive} : 1; 
    616  
    617     my @entries; 
     626    my $sort_by = $args->{sort_by} || 'created_on'; 
     627    my $sort_order = $args->{sort_order} || 'descend'; 
     628    my $lastn = $args->{lastn} || 0; 
     629 
    618630    my @tags = split_args($args->{search}, $delimiter, $case_sensitive) 
    619         or return \@entries; 
    620  
    621     my $r = MT::Request->instance; 
    622     $r->cache('Tagwire::xsearch_tags', \@tags); 
    623  
    624     my $data = get_pd_indexes($blog_id) || get_db_indexes($blog_id) 
    625         or return \@entries; 
    626     my %tindex = %{$data->{tindex}}; 
    627     my %eindex = %{$data->{eindex}}; 
     631        or return []; 
     632 
     633    $self->{xsearch_tags} = \@tags; 
     634 
     635    my $data = get_indexes($args->{blog_id}) or return []; 
     636    my ($tindex, $eindex) = ($data->{tindex}, $data->{eindex}); 
     637 
    628638    my %match; 
    629639    if ($case_sensitive) { 
    630640        foreach my $tag (@tags) { 
    631             foreach (@{$tindex{$tag}->{eids}}) { 
     641            foreach (@{$tindex->{$tag}->{eids}}) { 
    632642                $match{$_} = exists $match{$_} ? $match{$_} + 1 : 1; 
    633643            } 
     
    635645    } else { 
    636646        foreach my $tag (@tags) { 
    637             foreach my $mtag (grep { lc $_ eq $tag } keys %tindex) { 
    638                 foreach (@{$tindex{$mtag}->{eids}}) { 
     647            foreach my $t (grep { lc $_ eq $tag } keys %$tindex) { 
     648                foreach (@{$tindex->{$t}->{eids}}) { 
    639649                    $match{$_} = exists $match{$_} ? $match{$_} + 1 : 1; 
    640650                } 
     
    643653    } 
    644654    my $count = scalar @tags; 
    645     my @eids = grep { $match{$_} == $count } keys %match 
    646         or return \@entries; 
     655    my @eids = grep { $match{$_} == $count } keys %match or return []; 
    647656    @eids = $sort_order eq 'descend' ? 
    648         sort { $eindex{$b}->{created_on} <=> $eindex{$a}->{created_on} } @eids : 
    649         sort { $eindex{$a}->{created_on} <=> $eindex{$b}->{created_on} } @eids; 
    650     require MT::Entry; 
     657        sort { $eindex->{$b}->{created_on} <=> $eindex->{$a}->{created_on} } @eids : 
     658        sort { $eindex->{$a}->{created_on} <=> $eindex->{$b}->{created_on} } @eids; 
     659    splice(@eids, $lastn) if $lastn && (scalar @eids > $lastn); 
     660 
     661    my @entries; 
    651662    map { push @entries, MT::Entry->load($_) } @eids; 
     663 
    652664    \@entries; 
    653665} 
    654666 
    6556671; 
    656  
    657 package MT::Plugin::Tagwire::Cache; 
    658 use strict; 
    659 use MT::Request; 
    660 use vars qw($cache); 
    661  
    662 sub new { 
    663     $cache ||= MT::Request->instance; 
    664 }