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