Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.75% covered (success)
93.75%
15 / 16
85.71% covered (warning)
85.71%
6 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
InSourceFeature
93.75% covered (success)
93.75%
15 / 16
85.71% covered (warning)
85.71%
6 / 7
9.02
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getKeywords
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRegexHLFlavor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doApply
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getNonRegexFilterQuery
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildNonRegexHLFields
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 doGetNonRegexHLFields
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace CirrusSearch\Query;
4
5use CirrusSearch\Parser\AST\KeywordFeatureNode;
6use CirrusSearch\Query\Builder\QueryBuildingContext;
7use CirrusSearch\Search\Escaper;
8use CirrusSearch\Search\Fetch\HighlightedField;
9use CirrusSearch\Search\Fetch\HighlightFieldGenerator;
10use CirrusSearch\Search\Filters;
11use CirrusSearch\Search\SearchContext;
12use CirrusSearch\SearchConfig;
13use Elastica\Query\AbstractQuery;
14
15/**
16 * Handles non-regexp version of insource: keyword.  The value
17 * (including possible quotes) is used as part of a QueryString
18 * query while allows some bit of advanced syntax. Because quotes
19 * are included, if present, multi-word queries containing AND or
20 * OR do not work.
21 *
22 * Examples:
23 *   insource:Foo
24 *   insource:Foo*
25 *   insource:"gold rush"
26 *
27 * Regex support:
28 *   insource:/abc?/
29 *
30 * Things that don't work:
31 *   insource:"foo*"
32 *   insource:"foo OR bar"
33 */
34class InSourceFeature extends BaseRegexFeature {
35
36    /**
37     * Source field
38     */
39    private const FIELD = 'source_text';
40
41    /**
42     * @var Escaper an escaper used to sanitize queries when not used as regular expression
43     *
44     * TODO: do not rely on escaper here, this should be consistent with what the Parser does.
45     * @see Filters::intitle()
46     */
47    private $escaper;
48
49    public function __construct( SearchConfig $config ) {
50        parent::__construct( $config, [ self::FIELD => HighlightedField::TARGET_MAIN_SNIPPET ] );
51        $this->escaper = new Escaper( $config->get( 'LanguageCode' ), $config->get( 'CirrusSearchAllowLeadingWildcard' ) );
52    }
53
54    /**
55     * @return string[]
56     */
57    protected function getKeywords() {
58        return [ 'insource' ];
59    }
60
61    protected function getRegexHLFlavor(): string {
62        return "lucene_extended";
63    }
64
65    /**
66     * @param SearchContext $context
67     * @param string $key
68     * @param string $value
69     * @param string $quotedValue
70     * @param bool $negated
71     * @return array
72     */
73    protected function doApply( SearchContext $context, $key, $value, $quotedValue, $negated ) {
74        $filter = Filters::insource( $context->escaper(), $quotedValue );
75        if ( !$negated ) {
76            foreach ( $this->doGetNonRegexHLFields( $context->getFetchPhaseBuilder(), $filter ) as $field ) {
77                $context->getFetchPhaseBuilder()->addHLField( $field );
78            }
79        }
80        return [ $filter, false ];
81    }
82
83    /**
84     * @param KeywordFeatureNode $node
85     * @param QueryBuildingContext $context
86     * @return AbstractQuery|null
87     */
88    protected function getNonRegexFilterQuery( KeywordFeatureNode $node, QueryBuildingContext $context ) {
89        return Filters::insource( $this->escaper, $node->getQuotedValue() );
90    }
91
92    /**
93     * @inheritDoc
94     */
95    public function buildNonRegexHLFields( KeywordFeatureNode $node, QueryBuildingContext $buildingContext ) {
96        $query = Filters::insource( $this->escaper, $node->getQuotedValue() );
97        return $this->doGetNonRegexHLFields( $buildingContext->getHighlightFieldGenerator(), $query );
98    }
99
100    /**
101     * @param HighlightFieldGenerator $generator
102     * @param AbstractQuery $query
103     * @return HighlightedField[]
104     */
105    private function doGetNonRegexHLFields( HighlightFieldGenerator $generator, AbstractQuery $query ): array {
106        $field = $generator->newHighlightField( self::FIELD . '.plain',
107            HighlightedField::TARGET_MAIN_SNIPPET, HighlightedField::EXPERT_SYNTAX_PRIORITY );
108        $field->setHighlightQuery( $query );
109        return [ $field ];
110    }
111}