Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
27 / 27 |
|
100.00% |
6 / 6 |
CRAP | |
100.00% |
1 / 1 |
CirrusNearTitleFilterFeature | |
100.00% |
27 / 27 |
|
100.00% |
6 / 6 |
9 | |
100.00% |
1 / 1 |
getKeywords | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
doApply | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
expand | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
createQuery | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
2 | |||
getFilterQuery | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
doGetFilterQuery | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace GeoData\Search; |
4 | |
5 | use CirrusSearch\Parser\AST\KeywordFeatureNode; |
6 | use CirrusSearch\Query\Builder\QueryBuildingContext; |
7 | use CirrusSearch\Query\FilterQueryFeature; |
8 | use CirrusSearch\Query\SimpleKeywordFeature; |
9 | use CirrusSearch\Search\SearchContext; |
10 | use CirrusSearch\SearchConfig; |
11 | use CirrusSearch\WarningCollector; |
12 | use Elastica\Query\AbstractQuery; |
13 | use Elastica\Query\BoolQuery; |
14 | use Elastica\Query\GeoDistance; |
15 | use Elastica\Query\Nested; |
16 | use Elastica\Query\Term; |
17 | use GeoData\Coord; |
18 | |
19 | /** |
20 | * Applies geo filtering to the query by providing a Title. |
21 | * |
22 | * Limits search results to a geographic area within the geographic area. All values |
23 | * can be prefixed with a radius in m or km to apply. If not specified this defaults |
24 | * to 5km. |
25 | * |
26 | * Examples: |
27 | * neartitle:Shanghai |
28 | * neartitle:50km,Seoul |
29 | */ |
30 | class CirrusNearTitleFilterFeature extends SimpleKeywordFeature implements FilterQueryFeature { |
31 | use CirrusGeoFeature; |
32 | |
33 | /** |
34 | * @return string[] |
35 | */ |
36 | protected function getKeywords() { |
37 | return [ 'neartitle' ]; |
38 | } |
39 | |
40 | /** @inheritDoc */ |
41 | protected function doApply( SearchContext $context, $key, $value, $quotedValue, $negated ) { |
42 | [ $coord, $radius, $excludedPageId ] = $this->parseGeoNearbyTitle( $context, $key, $value ); |
43 | $filter = null; |
44 | if ( $coord !== null ) { |
45 | $filter = $this->doGetFilterQuery( $context->getConfig(), $coord, $radius, $excludedPageId ); |
46 | } |
47 | return [ $filter, false ]; |
48 | } |
49 | |
50 | /** |
51 | * @param KeywordFeatureNode $node |
52 | * @param SearchConfig $config |
53 | * @param WarningCollector $warningCollector |
54 | * @return array{?Coord,int,int|string} |
55 | */ |
56 | public function expand( |
57 | KeywordFeatureNode $node, |
58 | SearchConfig $config, |
59 | WarningCollector $warningCollector |
60 | ) { |
61 | return $this->parseGeoNearbyTitle( $warningCollector, $node->getKey(), $node->getValue() ); |
62 | } |
63 | |
64 | /** |
65 | * Create a filter for near: and neartitle: queries. |
66 | * |
67 | * @param Coord $coord |
68 | * @param int $radius Search radius in meters |
69 | * @param string $docIdToExclude Document id to exclude, or "" for no exclusions. |
70 | * @return AbstractQuery |
71 | */ |
72 | public static function createQuery( Coord $coord, $radius, $docIdToExclude = '' ) { |
73 | $query = new BoolQuery(); |
74 | $query->addFilter( new Term( [ 'coordinates.globe' => $coord->globe ] ) ); |
75 | $query->addFilter( new Term( [ 'coordinates.primary' => true ] ) ); |
76 | |
77 | $distanceFilter = new GeoDistance( |
78 | 'coordinates.coord', |
79 | [ 'lat' => $coord->lat, 'lon' => $coord->lon ], |
80 | $radius . 'm' |
81 | ); |
82 | $query->addFilter( $distanceFilter ); |
83 | |
84 | if ( $docIdToExclude !== '' ) { |
85 | $query->addMustNot( new Term( [ '_id' => $docIdToExclude ] ) ); |
86 | } |
87 | |
88 | $nested = new Nested(); |
89 | $nested->setPath( 'coordinates' )->setQuery( $query ); |
90 | |
91 | return $nested; |
92 | } |
93 | |
94 | /** |
95 | * @param KeywordFeatureNode $node |
96 | * @param QueryBuildingContext $context |
97 | * @return AbstractQuery|null |
98 | */ |
99 | public function getFilterQuery( KeywordFeatureNode $node, QueryBuildingContext $context ) { |
100 | [ $coord, $radius, $excludedPageId ] = $context->getKeywordExpandedData( $node ); |
101 | if ( $coord === null ) { |
102 | return null; |
103 | } |
104 | return $this->doGetFilterQuery( $context->getSearchConfig(), $coord, $radius, $excludedPageId ); |
105 | } |
106 | |
107 | /** |
108 | * @param SearchConfig $config |
109 | * @param Coord $coord |
110 | * @param int $radius |
111 | * @param int $excludedPageId |
112 | * @return AbstractQuery |
113 | */ |
114 | protected function doGetFilterQuery( |
115 | SearchConfig $config, |
116 | Coord $coord, |
117 | $radius, |
118 | $excludedPageId |
119 | ) { |
120 | $excludedDocId = $config->makeId( $excludedPageId ); |
121 | return self::createQuery( $coord, $radius, $excludedDocId ); |
122 | } |
123 | } |