Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
63.16% covered (warning)
63.16%
24 / 38
41.67% covered (danger)
41.67%
5 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
CoordinatesOutput
63.16% covered (warning)
63.16%
24 / 38
41.67% covered (danger)
41.67%
5 / 12
40.00
0.00% covered (danger)
0.00%
0 / 1
 getOrBuildFromParserOutput
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setToParserOutput
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFromParserOutput
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 getCount
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 addPrimary
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 addSecondary
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getPrimary
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasPrimary
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSecondary
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAll
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 jsonSerialize
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 newFromJson
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace GeoData;
4
5use InvalidArgumentException;
6use JsonSerializable;
7use LogicException;
8use MediaWiki\Parser\ParserOutput;
9use Wikimedia\Assert\Assert;
10use Wikimedia\Parsoid\Core\ContentMetadataCollector;
11
12/**
13 * Class that holds output of a parse opertion
14 */
15class CoordinatesOutput implements JsonSerializable {
16    /**
17     * Key used to store this object in the ParserOutput extension data.
18     * Visible for testing only.
19     */
20    public const GEO_DATA_COORDS_OUTPUT = 'GeoDataCoordsOutput';
21
22    /** @var bool */
23    public $limitExceeded = false;
24    /** @var Coord|false */
25    private $primary = false;
26    /** @var Coord[] */
27    private $secondary = [];
28
29    /**
30     * Fetch the current CoordinatesOutput attached to this ParserOutput
31     * or create a new one.
32     *
33     * @note The changes made to the CoordinatesOutput object are not stored
34     * back into the ParserOutput until self::setToParserOutput is called.
35     *
36     * @see setToParserOutput
37     * @param ParserOutput $parserOutput
38     * @return CoordinatesOutput
39     */
40    public static function getOrBuildFromParserOutput(
41        ParserOutput $parserOutput
42    ): CoordinatesOutput {
43        return self::getFromParserOutput( $parserOutput ) ?? new CoordinatesOutput();
44    }
45
46    /**
47     * Write the coords to ParserOutput object.
48     * @param ContentMetadataCollector $parserOutput
49     */
50    public function setToParserOutput( ContentMetadataCollector $parserOutput ) {
51        $parserOutput->setExtensionData( self::GEO_DATA_COORDS_OUTPUT, $this->jsonSerialize() );
52    }
53
54    /**
55     * Get the CoordinatesOutput attached to this ParserOutput
56     * @param ParserOutput $parserOutput
57     * @return CoordinatesOutput|null existing CoordinatesOutput or null
58     */
59    public static function getFromParserOutput( ParserOutput $parserOutput ) {
60        $coordsOutput = $parserOutput->getExtensionData( self::GEO_DATA_COORDS_OUTPUT );
61        if ( $coordsOutput !== null ) {
62            if ( is_array( $coordsOutput ) ) {
63                $coordsOutput = self::newFromJson( $coordsOutput );
64            }
65            Assert::invariant( $coordsOutput instanceof CoordinatesOutput,
66                'ParserOutput extension data ' . self::GEO_DATA_COORDS_OUTPUT .
67                ' must be an instance of CoordinatesOutput' );
68        }
69        return $coordsOutput;
70    }
71
72    /**
73     * @return int
74     */
75    public function getCount() {
76        return count( $this->secondary ) + ( $this->primary ? 1 : 0 );
77    }
78
79    /**
80     * Sets primary coordinates, throwing an exception if already set
81     *
82     * @param Coord $c
83     * @throws LogicException
84     */
85    public function addPrimary( Coord $c ) {
86        if ( $this->primary ) {
87            throw new LogicException( 'Primary coordinates already set' );
88        }
89        $this->primary = $c;
90    }
91
92    /**
93     * @param Coord $c
94     * @throws InvalidArgumentException
95     */
96    public function addSecondary( Coord $c ) {
97        if ( $c->primary ) {
98            throw new InvalidArgumentException( 'Attempt to pass primary coordinates as secondary' );
99        }
100        $this->secondary[] = $c;
101    }
102
103    /**
104     * @return Coord|false
105     */
106    public function getPrimary() {
107        return $this->primary;
108    }
109
110    /**
111     * @return bool Whether this output has primary coordinates
112     */
113    public function hasPrimary(): bool {
114        return (bool)$this->primary;
115    }
116
117    /**
118     * @return Coord[]
119     */
120    public function getSecondary() {
121        return $this->secondary;
122    }
123
124    /**
125     * @return Coord[]
126     */
127    public function getAll() {
128        $res = $this->secondary;
129        if ( $this->primary ) {
130            array_unshift( $res, $this->primary );
131        }
132        return $res;
133    }
134
135    /**
136     * @return array
137     */
138    public function jsonSerialize(): array {
139        return [
140            'limitExceeded' => $this->limitExceeded,
141            'primary' => $this->primary ? $this->primary->jsonSerialize() : $this->primary,
142            'secondary' => array_map( static function ( Coord $coord ) {
143                return $coord->jsonSerialize();
144            }, $this->secondary )
145        ];
146    }
147
148    /**
149     * Instantiate a CoordinatesOutput from $json array created with self::jsonSerialize.
150     *
151     * @internal
152     * @param array $jsonArray
153     * @return static
154     * @see jsonSerialize
155     */
156    public static function newFromJson( array $jsonArray ): self {
157        $coordOutput = new CoordinatesOutput();
158        $coordOutput->limitExceeded = $jsonArray['limitExceeded'];
159        $coordOutput->primary = $jsonArray['primary'] ? Coord::newFromJson( $jsonArray['primary'] ) : false;
160        $coordOutput->secondary = array_map( static function ( array $jsonCoord ) {
161            return Coord::newFromJson( $jsonCoord );
162        }, $jsonArray['secondary'] );
163        return $coordOutput;
164    }
165}