summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Maps/src/Presentation/WikitextParsers/LocationParser.php
blob: 26af76ef69711233019c595e2952deeda0060a9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<?php

namespace Maps\Presentation\WikitextParsers;

use DataValues\Geo\Parsers\LatLongParser;
use Jeroen\SimpleGeocoder\Geocoder;
use Maps\Elements\Location;
use Maps\FileUrlFinder;
use Maps\MapsFactory;
use Title;
use ValueParsers\ParseException;
use ValueParsers\StringValueParser;
use ValueParsers\ValueParser;

/**
 * ValueParser that parses the string representation of a location.
 *
 * @since 3.0
 *
 * @licence GNU GPL v2+
 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 */
class LocationParser implements ValueParser {

	private $geocoder;
	private $fileUrlFinder;
	private $useAddressAsTitle;

	/**
	 * @deprecated Use newInstance instead
	 */
	public function __construct( $enableLegacyCrud = true ) {
		if ( $enableLegacyCrud ) {
			$this->geocoder = MapsFactory::globalInstance()->getGeocoder();
			$this->fileUrlFinder = MapsFactory::globalInstance()->getFileUrlFinder();
			$this->useAddressAsTitle = false;
		}
	}

	public static function newInstance( Geocoder $geocoder, FileUrlFinder $fileUrlFinder, bool $useAddressAsTitle = false ): self {
		$instance = new self( false );
		$instance->geocoder = $geocoder;
		$instance->fileUrlFinder = $fileUrlFinder;
		$instance->useAddressAsTitle = $useAddressAsTitle;
		return $instance;
	}

	/**
	 * @see StringValueParser::stringParse
	 *
	 * @since 3.0
	 *
	 * @param string $value
	 *
	 * @return Location
	 * @throws ParseException
	 */
	public function parse( $value ) {
		$separator = '~';

		$metaData = explode( $separator, $value );

		$coordinatesOrAddress = array_shift( $metaData );
		$coordinates = $this->geocoder->geocode( $coordinatesOrAddress );

		if ( $coordinates === null ) {
			throw new ParseException( 'Location is not a parsable coordinate and not a geocodable address' );
		}

		$location = new Location( $coordinates );

		if ( $metaData !== [] ) {
			$this->setTitleOrLink( $location, array_shift( $metaData ) );
		} else {
			if ( $this->useAddressAsTitle && $this->isAddress( $coordinatesOrAddress ) ) {
				$location->setTitle( $coordinatesOrAddress );
			}
		}

		if ( $metaData !== [] ) {
			$location->setText( array_shift( $metaData ) );
		}

		if ( $metaData !== [] ) {
			$location->setIcon( $this->fileUrlFinder->getUrlForFileName( array_shift( $metaData ) ) );
		}

		if ( $metaData !== [] ) {
			$location->setGroup( array_shift( $metaData ) );
		}

		if ( $metaData !== [] ) {
			$location->setInlineLabel( array_shift( $metaData ) );
		}

		if ( $metaData !== [] ) {
			$location->setVisitedIcon( $this->fileUrlFinder->getUrlForFileName( array_shift( $metaData ) ) ) ;
		}

		return $location;
	}

	private function setTitleOrLink( Location $location, $titleOrLink ) {
		if ( $this->isLink( $titleOrLink ) ) {
			$this->setLink( $location, $titleOrLink );
		} else {
			$location->setTitle( $titleOrLink );
		}
	}

	private function isLink( $value ) {
		return strpos( $value, 'link:' ) === 0;
	}

	private function setLink( Location $location, $link ) {
		$link = substr( $link, 5 );
		$location->setLink( $this->getExpandedLink( $link ) );
	}

	private function getExpandedLink( $link ) {
		if ( filter_var( $link, FILTER_VALIDATE_URL ) ) {
			return $link;
		}

		$title = Title::newFromText( $link );

		if ( $title === null ) {
			return '';
		}

		return $title->getFullURL();
	}

	private function isAddress( string $coordsOrAddress ): bool {
		$coordinateParser = new LatLongParser();

		try {
			$coordinateParser->parse( $coordsOrAddress );
		}
		catch ( ParseException $parseException ) {
			return true;
		}

		return false;
	}

}