Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
68.42% covered (warning)
68.42%
26 / 38
58.33% covered (warning)
58.33%
7 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
CoordinatesOutput
68.42% covered (warning)
68.42%
26 / 38
58.33% covered (warning)
58.33%
7 / 12
32.60
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
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasPrimary
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSecondary
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 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 array $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     */
38    public static function getOrBuildFromParserOutput(
39        ParserOutput $parserOutput
40    ): CoordinatesOutput {
41        return self::getFromParserOutput( $parserOutput ) ?? new CoordinatesOutput();
42    }
43
44    /**
45     * Write the coords to ParserOutput object.
46     */
47    public function setToParserOutput( ContentMetadataCollector $parserOutput ) {
48        $parserOutput->setExtensionData( self::GEO_DATA_COORDS_OUTPUT, $this->jsonSerialize() );
49    }
50
51    /**
52     * Get the CoordinatesOutput attached to this ParserOutput
53     * @param ParserOutput $parserOutput
54     * @return CoordinatesOutput|null existing CoordinatesOutput or null
55     */
56    public static function getFromParserOutput( ParserOutput $parserOutput ) {
57        $coordsOutput = $parserOutput->getExtensionData( self::GEO_DATA_COORDS_OUTPUT );
58        if ( $coordsOutput !== null ) {
59            if ( is_array( $coordsOutput ) ) {
60                $coordsOutput = self::newFromJson( $coordsOutput );
61            }
62            Assert::invariant( $coordsOutput instanceof CoordinatesOutput,
63                'ParserOutput extension data ' . self::GEO_DATA_COORDS_OUTPUT .
64                ' must be an instance of CoordinatesOutput' );
65        }
66        return $coordsOutput;
67    }
68
69    public function getCount(): int {
70        return count( $this->secondary ) + ( $this->primary ? 1 : 0 );
71    }
72
73    /**
74     * Sets primary coordinates, throwing an exception if already set
75     *
76     * @param Coord $c
77     * @throws LogicException
78     */
79    public function addPrimary( Coord $c ): void {
80        if ( $this->primary ) {
81            throw new LogicException( 'Primary coordinates already set' );
82        }
83        $this->primary = $c;
84    }
85
86    /**
87     * @param Coord $c
88     * @throws InvalidArgumentException
89     */
90    public function addSecondary( Coord $c ): void {
91        if ( $c->primary ) {
92            throw new InvalidArgumentException( 'Attempt to pass primary coordinates as secondary' );
93        }
94        $this->secondary[] = $c;
95    }
96
97    /**
98     * @return Coord|false
99     */
100    public function getPrimary() {
101        return $this->primary;
102    }
103
104    /**
105     * @return bool Whether this output has primary coordinates
106     */
107    public function hasPrimary(): bool {
108        return (bool)$this->primary;
109    }
110
111    /**
112     * @return Coord[]
113     */
114    public function getSecondary(): array {
115        return $this->secondary;
116    }
117
118    /**
119     * @return Coord[]
120     */
121    public function getAll(): array {
122        $res = $this->secondary;
123        if ( $this->primary ) {
124            array_unshift( $res, $this->primary );
125        }
126        return $res;
127    }
128
129    public function jsonSerialize(): array {
130        return [
131            'limitExceeded' => $this->limitExceeded,
132            'primary' => $this->primary ? $this->primary->jsonSerialize() : $this->primary,
133            'secondary' => array_map( static function ( Coord $coord ) {
134                return $coord->jsonSerialize();
135            }, $this->secondary )
136        ];
137    }
138
139    /**
140     * Instantiate a CoordinatesOutput from $json array created with self::jsonSerialize.
141     *
142     * @internal
143     * @param array $jsonArray
144     * @return static
145     * @see jsonSerialize
146     */
147    public static function newFromJson( array $jsonArray ): self {
148        $coordOutput = new CoordinatesOutput();
149        $coordOutput->limitExceeded = $jsonArray['limitExceeded'];
150        $coordOutput->primary = $jsonArray['primary'] ? Coord::newFromJson( $jsonArray['primary'] ) : false;
151        $coordOutput->secondary = array_map( static function ( array $jsonCoord ) {
152            return Coord::newFromJson( $jsonCoord );
153        }, $jsonArray['secondary'] );
154        return $coordOutput;
155    }
156}