Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
CirrusNearCoordBoostFeature
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
6 / 6
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
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
 doApply
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 parseValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBoostFunctionBuilder
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 buildBoostFunction
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace GeoData\Search;
4
5use CirrusSearch\Parser\AST\KeywordFeatureNode;
6use CirrusSearch\Query\BoostFunctionFeature;
7use CirrusSearch\Query\Builder\QueryBuildingContext;
8use CirrusSearch\Query\SimpleKeywordFeature;
9use CirrusSearch\Search\Rescore\BoostFunctionBuilder;
10use CirrusSearch\Search\SearchContext;
11use CirrusSearch\SearchConfig;
12use CirrusSearch\WarningCollector;
13use GeoData\Coord;
14use MediaWiki\Config\Config;
15
16/**
17 * Applies geo boosting to the query by providing coordinates.
18 *
19 * it increases the score of results within the geographic area. All values can be prefixed
20 * with a radius in m or km to apply. If not specified this defaults to 5km.
21 *
22 * Examples:
23 *  boost-nearcoord:-12.345,87.654
24 *  boost-nearcoord:77km,34.567,76.543
25 */
26class CirrusNearCoordBoostFeature extends SimpleKeywordFeature implements BoostFunctionFeature {
27    use CirrusGeoFeature;
28
29    /**
30     * @var Config
31     */
32    private $config;
33
34    /**
35     * @param Config $config
36     */
37    public function __construct( Config $config ) {
38        $this->config = $config;
39    }
40
41    /** @inheritDoc */
42    protected function getKeywords() {
43        return [ 'boost-nearcoord' ];
44    }
45
46    /**
47     * @param SearchContext $context
48     * @param string $key The keyword
49     * @param string $value The value attached to the keyword with quotes stripped
50     * @param string $quotedValue The original value in the search string, including quotes if used
51     * @param bool $negated Is the search negated? Not used to generate the returned AbstractQuery,
52     *  that will be negated as necessary. Used for any other building/context necessary.
53     * @return array Two element array, first an AbstractQuery or null to apply to the
54     *  query. Second a boolean indicating if the quotedValue should be kept in the search
55     *  string.
56     */
57    protected function doApply( SearchContext $context, $key, $value, $quotedValue, $negated ) {
58        [ $coord, $radius ] = $this->parseValue( $key, $value, $quotedValue, '', '', $context );
59        if ( $coord !== null ) {
60            $context->addCustomRescoreComponent(
61                $this->buildBoostFunction( $context->getConfig(), $coord, $radius )
62            );
63        }
64
65        return [ null, false ];
66    }
67
68    /**
69     * @param string $key
70     * @param string $value
71     * @param string $quotedValue
72     * @param string $valueDelimiter
73     * @param string $suffix
74     * @param WarningCollector $warningCollector
75     * @return array
76     */
77    public function parseValue(
78        $key,
79        $value,
80        $quotedValue,
81        $valueDelimiter,
82        $suffix,
83        WarningCollector $warningCollector
84    ) {
85        return $this->parseGeoNearby( $warningCollector, $this->config, $key, $value );
86    }
87
88    /**
89     * @param KeywordFeatureNode $node
90     * @param QueryBuildingContext $context
91     * @return BoostFunctionBuilder|null
92     */
93    public function getBoostFunctionBuilder(
94        KeywordFeatureNode $node,
95        QueryBuildingContext $context
96    ) {
97        [ $coord, $radius ] = $node->getParsedValue();
98        if ( $coord !== null ) {
99            return $this->buildBoostFunction( $context->getSearchConfig(), $coord, $radius );
100        }
101        return null;
102    }
103
104    /**
105     * @param SearchConfig $config
106     * @param array $coord
107     * @param int $radius
108     * @return GeoRadiusFunctionScoreBuilder
109     */
110    private function buildBoostFunction( SearchConfig $config, array $coord, $radius ) {
111        $coordObject = new Coord( $coord['lat'], $coord['lon'], $coord['globe'] );
112        return new GeoRadiusFunctionScoreBuilder( $config,
113            1, $coordObject, $radius );
114    }
115}