Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
BaseMapElement
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 13
1406
0.00% covered (danger)
0.00%
0 / 1
 getElementName
n/a
0 / 0
n/a
0 / 0
0
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 __get
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getProperty
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 __set
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setProperty
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 unsetProperty
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 parse
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 parseCoordinates
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 parseProperties
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
132
 isValid
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 reset
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getErrorMessages
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getData
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2namespace MultiMaps;
3
4use MediaWiki\MediaWikiServices;
5
6/**
7 * Base class for collection of map elements
8 *
9 * @file BaseService.php
10 * @ingroup MultiMaps
11 * @author Pavel Astakhov <pastakhov@yandex.ru>
12 * @license GPL-2.0-or-later
13 * @property-read array $pos Array of geographic coordinates
14 * @property string $title Title of element
15 * @property string $text Popup text of element
16 */
17abstract class BaseMapElement {
18
19    /**
20     * Geographic coordinates
21     * @var Point[]
22     */
23    protected $coordinates;
24
25    /**
26     * @todo Description
27     * @var bool
28     */
29    protected $isValid;
30
31    /**
32     * An array that is used to accumulate the error messages
33     * @var array
34     */
35    protected $errormessages;
36
37    /**
38     * Array of properties available for this element
39     * @var array
40     */
41    protected $availableProperties;
42
43    /**
44     * Array of element properties
45     * @var array
46     */
47    protected $properties;
48
49    /**
50     * Returns element name
51     * return string Element name
52     */
53    abstract public function getElementName();
54
55    function __construct() {
56        $this->availableProperties = [
57            'title',
58            'text',
59        ];
60
61        $this->reset();
62    }
63
64    public function __get( $name ) {
65        return $this->getProperty( $name );
66    }
67
68    /**
69     * Get element property by name
70     * @param string $name
71     * @return mixed
72     */
73    public function getProperty( $name ) {
74        $name = strtolower( $name );
75
76        switch ( $name ) {
77            case 'pos':
78                return $this->coordinates;
79            default:
80                if ( isset( $this->properties[$name] ) ) {
81                    return $this->properties[$name];
82                }
83                break;
84        }
85        return null;
86    }
87
88    public function __set( $name, $value ) {
89        $this->setProperty( $name, $value );
90    }
91
92    /**
93     * Set element property by name
94     * @param string $name
95     * @param mixed $value
96     * @return bool
97     */
98    public function setProperty( $name, $value ) {
99        $name = strtolower( $name );
100        if ( array_search( $name, $this->availableProperties ) === false ) {
101            return false;
102        }
103
104        if ( $name == 'title' || $name == 'text' ) {
105            $parser = MediaWikiServices::getInstance()->getParser();
106            $title = \Title::makeTitle( NS_SPECIAL, 'BadTitle/BaseMapElement' );
107            $value = trim( $value );
108            if ( defined( 'LINGO_VERSION' ) === true ) { // Do not allow Lingo extension to process value
109                $value .= "\n__NOGLOSSARY__";
110            }
111            $options = \ParserOptions::newFromAnon();
112            $this->properties[$name] = $parser->parse( $value, $title, $options )->getText( [ 'unwrap' => true ] );
113        } elseif ( is_string( $value ) ) {
114            $value = trim( $value );
115            $this->properties[$name] = htmlspecialchars( $value, ENT_NOQUOTES );
116        } else {
117            $this->properties[$name] = $value;
118        }
119        return true;
120    }
121
122    /**
123     * Unset element property by name
124     * @param string $name
125     */
126    public function unsetProperty( $name ) {
127        $name = strtolower( $name );
128
129        if ( isset( $this->properties[$name] ) ) {
130            unset( $this->properties[$name] );
131        }
132    }
133
134    /**
135     * Filling properties of the object according to the obtained data
136     * @global string $egMultiMaps_DelimiterParam
137     * @param string $param
138     * @param string|null $service Name of map service
139     * @return bool returns false if there were errors during parsing, it does not mean that the item was not added. Check with isValid()
140     */
141    public function parse( $param, $service = null ) {
142        global $egMultiMaps_DelimiterParam;
143        $this->reset();
144
145        $arrayparam = explode( $egMultiMaps_DelimiterParam, $param );
146
147        // The first parameter should always be coordinates
148        $coordinates = array_shift( $arrayparam );
149        if ( $this->parseCoordinates( $coordinates, $service ) === false ) {
150            $this->errormessages[] = \wfMessage( 'multimaps-unable-create-element', $this->getElementName() )->escaped();
151            return false;
152        }
153
154        // These parameters are optional
155        $this->isValid = true;
156        return $this->parseProperties( $arrayparam );
157    }
158
159    /**
160     * Filling property 'coordinates'
161     * @global string $egMultiMaps_CoordinatesSeparator
162     * @param string $coordinates
163     * @param string|null $service Name of map service
164     * @return bool
165     */
166    protected function parseCoordinates( $coordinates, $service = null ) {
167        global $egMultiMaps_CoordinatesSeparator;
168
169        $array = explode( $egMultiMaps_CoordinatesSeparator, $coordinates );
170        foreach ( $array as $value ) {
171            $point = new Point();
172            if ( $point->parse( $value, $service ) ) {
173                $this->coordinates[] = $point;
174            } else {
175                $this->errormessages[] = \wfMessage( 'multimaps-unable-parse-coordinates', $value )->escaped();
176                return false;
177            }
178        }
179        return true;
180    }
181
182    /**
183     *
184     * @param array $param
185     * @return bool false if there were errors during parsing
186     */
187    protected function parseProperties( array $param ) {
188        $return = true;
189        // filling properties with the names
190        $matches = [];
191        $properties = implode( '|', $this->availableProperties );
192        foreach ( $param as $key => $paramvalue ) {
193            if ( preg_match( "/^\\s*($properties)\\s*=(.+)$/si", $paramvalue, $matches ) ) {
194                if ( !$this->setProperty( $matches[1], $matches[2] ) ) {
195                    $return = false;
196                }
197                unset( $param[$key] );
198            }
199        }
200
201        // filling properties without the names
202        reset( $param );
203        $value = current( $param );
204        if ( $value === false ) {
205            return $return;
206        }
207        foreach ( $this->availableProperties as $name ) {
208            if ( $this->getProperty( $name ) === null ) {
209                if ( preg_match( '/^\s*$/s', $value ) == false ) { // Ignore empty values
210                    if ( !$this->setProperty( $name, $value ) ) {
211                        $return = false;
212                    }
213                }
214                $value = next( $param );
215                if ( $value === false ) {
216                    return $return;
217                }
218            }
219        }
220
221        $this->errormessages[] = \wfMessage( 'multimaps-element-more-parameters', $this->getElementName() )->escaped();
222        $notprocessed = [ $value ];
223        while ( $value = next( $param ) ) {
224            $notprocessed[] = $value;
225        }
226        $this->errormessages[] = \wfMessage( 'multimaps-element-parameters-not-processed', '"' . implode( '", "', $notprocessed ) . '"' )->escaped();
227        return false;
228    }
229
230    /**
231     * Checks if the object is valid
232     * @return bool
233     */
234    public function isValid() {
235        return $this->isValid;
236    }
237
238    /**
239     * Initializes the object again, and makes it invalid
240     */
241    public function reset() {
242        $this->isValid = false;
243        $this->coordinates = [];
244        $this->errormessages = [];
245        $this->properties = [];
246    }
247
248    /**
249     * Returns an error messages
250     * @return array
251     */
252    public function getErrorMessages() {
253        return $this->errormessages;
254    }
255
256    /**
257     * Returns an array of data
258     * @return array
259     */
260    public function getData() {
261        if ( $this->isValid() ) {
262            $ret = [];
263            foreach ( $this->coordinates as $pos ) {
264                $ret['pos'][] = $pos->getData();
265            }
266            return array_merge( $ret, $this->properties );
267        }
268    }
269}