Changeset 1708

Show
Ignore:
Timestamp:
04/02/08 06:12:41 (15 months ago)
Author:
fumiakiy
Message:

Added ability to filter search by author and/or category. BugId:69286

Location:
branches/release-33/lib/MT
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • branches/release-33/lib/MT/App/Search.pm

    r1647 r1708  
    5050    my $app = shift; 
    5151    return { 
    52         params => [ qw( searchTerms search count limit startIndex offset ) ], 
     52        params => [ qw( searchTerms search count limit startIndex offset 
     53            category author )], 
    5354        types  => { 
    5455            #author => { 
     
    5859            #}, 
    5960            entry => { 
    60                 columns => [ qw( title keywords text text_more ) ], 
     61                columns => { 
     62                    title     => 'like', 
     63                    keywords  => 'like', 
     64                    text      => 'like', 
     65                    text_more => 'like' 
     66                }, 
    6167                'sort'  => 'authored_on', 
    6268                terms   => { status => 2 }, #MT::Entry::RELEASE() 
     69                filter_types => { 
     70                    author   => \&_join_author, 
     71                    category => \&_join_category, 
     72                }, 
    6373            }, 
    6474        }, 
     
    281291 
    282292    $count = $class->count( $terms, $args ); 
     293    return $app->error($class->errstr) unless defined $count; 
    283294 
    284295    my $cache_driver = $app->{cache_driver}; 
     
    296307 
    297308    my $count = $app->count( $class, $terms, $args ); 
    298     return $app->error($class->errstr) unless defined $count; 
     309    return $app->errtrans("Invalid query.  [_1]", $app->errstr) unless defined $count; 
    299310 
    300311    my $iter = $class->load_iter( $terms, $args ) 
     
    334345 
    335346    my $columns = $params->{columns}; 
     347    delete $columns->{'plugin'}; #FIXME: why is this in here? 
    336348    return $app->errtrans('No column was specified to search for [_1].', $app->{searchparam}{Type}) 
    337         unless $columns && @$columns; 
    338  
    339     my $parsed = $app->query_parse( $columns ); 
     349        unless $columns && %$columns; 
     350 
     351    my $parsed = $app->query_parse( %$columns ); 
    340352    return $app->errtrans('Parse error: [1]', $app->errstr) 
    341353        unless $parsed && %$parsed; 
     
    474486        # load specified template 
    475487        my $filename; 
    476         if (my @tmpls = ($app->config->default('SearchAltTemplate'), $app->config->SearchAltTemplate)) { 
     488        if (my @tmpls = ( 
     489          $app->config->default('SearchAltTemplate'), 
     490          $app->config->SearchAltTemplate) ) { 
    477491            for my $tmpl (@tmpls) { 
    478492                next unless defined $tmpl; 
     
    550564sub query_parse { 
    551565    my $app = shift; 
    552     my ( $columns ) = @_; 
     566    my ( %columns ) = @_; 
     567 
     568    my $search = $app->{search_string}; 
     569 
     570    my $reg = $app->registry( $app->mode, 'types', $app->{searchparam}{Type} ); 
     571    my $filter_types = $reg->{ 'filter_types' }; 
     572    foreach my $type ( keys %$filter_types ) { 
     573        if ( my $filter = $app->param($type) ) { 
     574            $search .= " $type:$filter"; 
     575        } 
     576    } 
    553577 
    554578    require Lucene::QueryParser; 
    555     my $lucene_struct = Lucene::QueryParser::parse_query( $app->{search_string} ); 
    556     my %columns = map { $_ => 1 } @$columns; 
    557     my $structure = $app->_query_parse_core( $lucene_struct, \%columns ); 
    558     { terms => $structure }; 
     579    my $lucene_struct = Lucene::QueryParser::parse_query( $search ); 
     580    my ( $terms, $joins ) = $app->_query_parse_core( $lucene_struct, \%columns, $filter_types ); 
     581    my $return = { 
     582        $terms && @$terms ? (terms => $terms) : () 
     583    }; 
     584    if ( $joins && @$joins ) { 
     585        my $args = {}; 
     586        _create_join_arg( $args, $joins ); 
     587        if ( $args && %$args ) { 
     588            $return->{args} = $args; 
     589        } 
     590    } 
     591    $return; 
     592} 
     593 
     594sub _create_join_arg { 
     595    my ( $args, $joins ) = @_; 
     596    my $join = shift @$joins; 
     597    return unless $join && @$join; 
     598    my $next = $join->[3]; 
     599    if ( defined $next ) { 
     600        if ( exists $next->{'join'} ) { 
     601            $next = $next->{'join'}->[3]; 
     602        } 
     603    } 
     604    else { 
     605        $next = {}; 
     606        $join->[3] = $next; 
     607    } 
     608    _create_join_arg($next, $joins); 
     609    $args->{'join'} = $join; 
    559610} 
    560611 
    561612sub _query_parse_core { 
    562613    my $app = shift; 
    563     my ( $lucene_struct, $columns ) = @_; 
    564  
    565     my @structure; 
     614    my ( $lucene_struct, $columns, $filter_types ) = @_; 
     615 
     616    my $rvalue = sub { 
     617        my %rvalues = ( 
     618            NORMALlike => { like => '%' . $_[1] . '%' }, 
     619            NORMAL1    => $_[1], 
     620            PROHIBITEDlike => { not_like => '%' . $_[1] . '%' }, 
     621            PROHIBITED1    => { not => $_[1] } 
     622        ); 
     623        $rvalues{$_[0]}; 
     624    }; 
     625 
     626    my ( @structure, @joins ); 
    566627    for my $term ( @$lucene_struct ) { 
    567         next if exists( $term->{field} ) 
    568             && !exists( $columns->{ $term->{field} } ); 
    569  
    570         my $test; 
     628        if ( exists $term->{field} ) { 
     629            unless ( exists $columns->{ $term->{field} } ) { 
     630                next if $filter_types && %$filter_types 
     631                    && !exists( $filter_types->{ $term->{field} } ); 
     632            } 
     633        } 
     634 
     635        my @tmp; 
    571636        if ( ( 'TERM' eq $term->{query} ) || ( 'PHRASE' eq $term->{query} ) ){ 
    572             if ( 'PROHIBITED' eq $term->{type} ) { 
    573                 $test = { not_like => '%'.$term->{term}.'%' }; 
     637            my $test; 
     638            if ( exists( $term->{field} ) ) { 
     639                if ( $filter_types && %$filter_types 
     640                  && exists( $filter_types->{ $term->{field} } ) ) { 
     641                    my $code = $app->handler_to_coderef($filter_types->{ $term->{field} }); 
     642                    if ( $code ) { 
     643                        my $join_args = $code->( $app, $term ); 
     644                        push @joins, $join_args; 
     645                        next; 
     646                    } 
     647                } 
     648                elsif ( exists $columns->{ $term->{field} } ) { 
     649                    my $test = $rvalue->( 
     650                        ( $term->{type} || '' ) . $columns->{ $term->{field} }, 
     651                        $term->{term} 
     652                    ); 
     653                    push @tmp, { $term->{field} => $test }; 
     654                } 
    574655            } 
    575656            else { 
    576                 $test = { like => '%'.$term->{term}.'%' }; 
     657                my @cols = keys %$columns; 
     658                my $number = scalar @cols; 
     659                for ( my $i = 0; $i < $number; $i++ ) { 
     660                    my $test = $rvalue->( 
     661                        ( $term->{type} || '' ) . $columns->{ $cols[$i] }, 
     662                        $term->{term} 
     663                    ); 
     664                    push @tmp, { $cols[$i] => $test }; 
     665                    unless ( $i == $number - 1 ) { 
     666                        push @tmp, '-or'; 
     667                    } 
     668                } 
    577669            } 
    578670        } 
    579671        elsif ( 'SUBQUERY' eq $term->{query} ) { 
    580             $test = $app->_query_parse_core( $term->{subquery}, $columns ); 
     672            my ( $test, $more_joins ) = $app->_query_parse_core( 
     673                $term->{subquery}, $columns, $filter_types ); 
    581674            next unless $test && @$test; 
    582675            if ( @structure ) { 
     
    586679            } 
    587680            push @structure, $test->[0]; 
     681            push @joins, @$more_joins; 
    588682            next; 
    589683        } 
    590684 
    591         my @tmp; 
    592         if ( exists( $term->{field} ) ) { 
    593             push @tmp, { $term->{field} => $test }; 
    594         } 
    595         else { 
    596             my @columns = keys %$columns; 
    597             my $number = scalar @columns; 
    598             for ( my $i = 0; $i < $number; $i++) { 
    599                 push @tmp, { $columns[$i] => $test }; 
    600                 unless ( $i == $number - 1 ) { 
    601                     push @tmp, '-or'; 
    602                 } 
    603             } 
    604         } 
    605685        if ( exists($term->{conj}) && ( 'OR' eq $term->{conj} ) ) { 
    606686            if ( my $prev = pop @structure ) { 
     
    615695        } 
    616696    } 
    617     \@structure; 
     697    ( \@structure, \@joins ); 
     698} 
     699 
     700# add category filter to entry search 
     701sub _join_category { 
     702    my ( $app, $term ) = @_; 
     703 
     704    my $query = $term->{term}; 
     705    if ( 'PHRASE' eq $term->{query} ) { 
     706        $query =~ s/'/"/g; 
     707    } 
     708 
     709    my $lucene_struct = Lucene::QueryParser::parse_query( $query ); 
     710    if ( 'PROHIBITED' eq $term->{type} ) { 
     711        $_->{type} = 'PROHIBITED' foreach @$lucene_struct; 
     712    } 
     713    # search for exact match 
     714    my ( $terms ) = $app->_query_parse_core( $lucene_struct, { label => 1 }, {} ); 
     715    return unless $terms && @$terms; 
     716    push @$terms, '-and', { 
     717        id => \'= placement_category_id', 
     718        blog_id => \'= entry_blog_id', 
     719    }; 
     720 
     721    require MT::Placement; 
     722    require MT::Category; 
     723    return MT::Placement->join_on( undef, 
     724        { entry_id => \'= entry_id', blog_id => \'= entry_blog_id' }, 
     725        { join => MT::Category->join_on( undef, $terms, {} ), 
     726          unique => 1 } 
     727    ); 
     728} 
     729 
     730# add author filter to entry search 
     731sub _join_author { 
     732    my ( $app, $term ) = @_; 
     733 
     734    my $query = $term->{term}; 
     735    if ( 'PHRASE' eq $term->{query} ) { 
     736        $query =~ s/'/"/g; 
     737    } 
     738 
     739    my $lucene_struct = Lucene::QueryParser::parse_query( $query ); 
     740    if ( 'PROHIBITED' eq $term->{type} ) { 
     741        $_->{type} = 'PROHIBITED' foreach @$lucene_struct; 
     742    } 
     743    my ( $terms ) = $app->_query_parse_core( $lucene_struct, { nickname => 'like' }, {} ); 
     744    return unless $terms && @$terms; 
     745    push @$terms, '-and', { 
     746        id => \'= entry_author_id', 
     747    }; 
     748    require MT::Author; 
     749    return MT::Author->join_on( undef, 
     750        $terms, 
     751        { unique => 1 } 
     752    ); 
    618753} 
    619754 
  • branches/release-33/lib/MT/Template/Context/Search.pm

    r1640 r1708  
    99use strict; 
    1010use base qw( MT::Template::Context ); 
    11 use MT::Util qw( encode_url ); 
     11use MT::Util qw( encode_url decode_html ); 
    1212 
    1313sub load_core_tags { 
     
    134134        my ( $ctx, $args, $cond ) = @_; 
    135135 
    136     my $search_string = encode_url($ctx->stash('search_string')); 
     136    my $search_string = decode_html( $ctx->stash('search_string') ) ; 
    137137    my $cgipath = $ctx->_hdlr_cgi_path($args); 
    138138    my $script = $ctx->{config}->SearchScript; 
    139     my $link = $cgipath.$script . '?search=' . $search_string; 
     139    my $link = $cgipath.$script . '?search=' . encode_url( $search_string ); 
    140140    if ( my $mode = $ctx->stash('mode') ) { 
    141141        $mode = encode_url($mode);