MapsFactory   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 254
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 32

Test Coverage

Coverage 73.88%

Importance

Changes 0
Metric Value
wmc 42
lcom 2
cbo 32
dl 0
loc 254
ccs 99
cts 134
cp 0.7388
rs 9.0399
c 0
b 0
f 0

31 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A globalInstance() 0 7 2
A newDefault() 0 3 1
A newLocationParser() 0 6 1
A getGeocoder() 0 13 2
A newCoreGeocoder() 0 21 5
A newGoogleGeocoder() 0 7 1
A getFileFetcher() 0 3 1
A newFileFetcher() 0 3 1
A getGeoJsonFileFetcher() 0 10 2
A getMediaWikiSimpleCache() 0 6 1
A getMediaWikiCache() 0 3 1
A getPageContentFetcher() 0 6 1
A getCoordinateFormatter() 0 3 1
A getFileUrlFinder() 0 3 1
A getMappingServices() 0 8 1
A getGoogleMapsService() 0 7 2
A getLeafletService() 0 9 2
A getDisplayMapFunction() 0 5 1
A getParamDefinitionFactory() 0 15 1
A newGeoJsonFetcher() 0 7 1
A smwIntegrationIsEnabled() 0 3 2
A newSemanticMapsSetup() 0 3 1
A newSemanticGeoJsonStore() 0 8 1
A getSmwFactory() 0 3 1
A getImageRepository() 0 5 1
A getRepoGroup() 0 3 1
A getMapOutputBuilder() 0 6 1
A newCargoOutputBuilder() 0 8 1
A newParserHookSetup() 0 3 1
A newNonMapParserHooks() 0 15 2

How to fix   Complexity   

Complex Class

Complex classes like MapsFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MapsFactory, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace Maps;
6
7
use DataValues\Geo\Parsers\LatLongParser;
8
use FileFetcher\Cache\Factory as CacheFactory;
9
use FileFetcher\FileFetcher;
10
use Jeroen\SimpleGeocoder\Geocoder;
11
use Jeroen\SimpleGeocoder\Geocoders\Decorators\CoordinateFriendlyGeocoder;
12
use Jeroen\SimpleGeocoder\Geocoders\FileFetchers\GeoNamesGeocoder;
13
use Jeroen\SimpleGeocoder\Geocoders\FileFetchers\GoogleGeocoder;
14
use Jeroen\SimpleGeocoder\Geocoders\FileFetchers\NominatimGeocoder;
15
use Jeroen\SimpleGeocoder\Geocoders\NullGeocoder;
16
use Maps\DataAccess\CachingGeocoder;
17
use Maps\DataAccess\GeoJsonFetcher;
18
use Maps\DataAccess\ImageRepository;
19
use Maps\DataAccess\MapsFileFetcher;
20
use Maps\DataAccess\MediaWikiFileUrlFinder;
21
use Maps\DataAccess\MwImageRepository;
22
use Maps\DataAccess\PageContentFetcher;
23
use Maps\GeoJsonPages\GeoJsonStore;
24
use Maps\GeoJsonPages\Semantic\SemanticGeoJsonStore;
25
use Maps\GeoJsonPages\Semantic\SubObjectBuilder;
26
use Maps\Map\CargoFormat\CargoOutputBuilder;
27
use Maps\Map\DisplayMap\DisplayMapFunction;
28
use Maps\Map\MapOutputBuilder;
29
use Maps\ParserHooks\CoordinatesFunction;
30
use Maps\ParserHooks\DistanceFunction;
31
use Maps\ParserHooks\FindDestinationFunction;
32
use Maps\ParserHooks\GeocodeFunction;
33
use Maps\ParserHooks\GeoDistanceFunction;
34
use Maps\ParserHooks\MapsDocFunction;
35
use Maps\Presentation\CoordinateFormatter;
36
use Maps\WikitextParsers\CircleParser;
37
use Maps\WikitextParsers\DistanceParser;
38
use Maps\WikitextParsers\ImageOverlayParser;
39
use Maps\WikitextParsers\LineParser;
40
use Maps\WikitextParsers\LocationParser;
41
use Maps\WikitextParsers\PolygonParser;
42
use Maps\WikitextParsers\RectangleParser;
43
use Maps\WikitextParsers\WmsOverlayParser;
44
use MediaWiki\MediaWikiServices;
45
use ParamProcessor\ParamDefinitionFactory;
46
use Parser;
47
use ParserHook;
48
use RepoGroup;
49
use SimpleCache\Cache\Cache;
50
use SimpleCache\Cache\MediaWikiCache;
51
use SMW\ApplicationFactory;
52
use Title;
53
54
/**
55
 * @licence GNU GPL v2+
56
 * @author Jeroen De Dauw < [email protected] >
57
 */
58
class MapsFactory {
59
60
	protected static $globalInstance = null;
61
62
	private $settings;
63
	private $mediaWikiServices;
64
65
	private $leafletService;
66
	private $googleService;
67
68 4
	private function __construct( array $settings, MediaWikiServices $mediaWikiServices ) {
69 4
		$this->settings = $settings;
70 4
		$this->mediaWikiServices = $mediaWikiServices;
71 4
	}
72
73
	/**
74
	 * Only for legacy code where dependency injection is not possible
75
	 */
76 120
	public static function globalInstance(): self {
77 120
		if ( self::$globalInstance === null ) {
78
			self::$globalInstance = self::newDefault();
79
		}
80
81 120
		return self::$globalInstance;
82
	}
83
84 4
	protected static function newDefault(): self {
85 4
		return new static( $GLOBALS, MediaWikiServices::getInstance() );
86
	}
87
88 30
	public function newLocationParser(): LocationParser {
89 30
		return LocationParser::newInstance(
90 30
			$this->getGeocoder(),
91 30
			$this->getFileUrlFinder()
92
		);
93
	}
94
95 86
	public function getGeocoder(): Geocoder {
96 86
		$geocoder = new CoordinateFriendlyGeocoder( $this->newCoreGeocoder() );
97
98 86
		if ( $this->settings['egMapsEnableGeoCache'] ) {
99 86
			return new CachingGeocoder(
100 86
				$geocoder,
101 86
				$this->getMediaWikiCache(),
102 86
				$this->settings['egMapsGeoCacheTtl']
103
			);
104
		}
105
106
		return $geocoder;
107
	}
108
109 86
	private function newCoreGeocoder(): Geocoder {
110 86
		switch ( $this->settings['egMapsDefaultGeoService'] ) {
111 86
			case 'geonames':
112
				if ( $this->settings['egMapsGeoNamesUser'] === '' ) {
113
					return $this->newGoogleGeocoder();
114
				}
115
116
				return new GeoNamesGeocoder(
117
					$this->newFileFetcher(),
118
					$this->settings['egMapsGeoNamesUser']
119
				);
120 86
			case 'google':
121
				return $this->newGoogleGeocoder();
122 86
			case 'nominatim':
123 86
				return new NominatimGeocoder(
124 86
					$this->newFileFetcher()
125
				);
126
			default:
127
				return new NullGeocoder();
128
		}
129
	}
130
131
	private function newGoogleGeocoder(): Geocoder {
132
		return new GoogleGeocoder(
133
			$this->newFileFetcher(),
134
			$this->settings['egMapsGMaps3ApiKey'],
135
			$this->settings['egMapsGMaps3ApiVersion']
136
		);
137
	}
138
139 3
	public function getFileFetcher(): FileFetcher {
140 3
		return $this->newFileFetcher();
141
	}
142
143 86
	private function newFileFetcher(): FileFetcher {
144 86
		return new MapsFileFetcher();
145
	}
146
147 3
	public function getGeoJsonFileFetcher(): FileFetcher {
148 3
		if ( $this->settings['egMapsGeoJsonCacheTtl'] === 0 ) {
149 3
			return $this->getFileFetcher();
150
		}
151
152
		return ( new CacheFactory() )->newJeroenSimpleCacheFetcher(
153
			$this->getFileFetcher(),
154
			$this->getMediaWikiSimpleCache( $this->settings['egMapsGeoJsonCacheTtl'] )
155
		);
156
	}
157
158
	private function getMediaWikiSimpleCache( int $ttlInSeconds ): Cache {
159
		return new MediaWikiCache(
160
			$this->getMediaWikiCache(),
161
			$ttlInSeconds
162
		);
163
	}
164
165 86
	private function getMediaWikiCache(): \BagOStuff {
166 86
		return wfGetCache( $this->settings['egMapsGeoCacheType'] );
167
	}
168
169 3
	public function getPageContentFetcher(): PageContentFetcher {
170 3
		return new PageContentFetcher(
171 3
			$this->mediaWikiServices->getTitleParser(),
172 3
			$this->mediaWikiServices->getRevisionLookup()
173
		);
174
	}
175
176 20
	public function getCoordinateFormatter(): CoordinateFormatter {
177 20
		return new CoordinateFormatter();
178
	}
179
180 89
	public function getFileUrlFinder(): FileUrlFinder {
181 89
		return new MediaWikiFileUrlFinder();
182
	}
183
184 27
	public function getMappingServices(): MappingServices {
185 27
		return new MappingServices(
186 27
			$this->settings['egMapsAvailableServices'],
187 27
			$this->settings['egMapsDefaultService'],
188 27
			$this->getGoogleMapsService(),
189 27
			$this->getLeafletService()
190
		);
191
	}
192
193 27
	private function getGoogleMapsService(): GoogleMapsService {
194 27
		if ( $this->googleService === null ) {
195 2
			$this->googleService = new GoogleMapsService();
196
		}
197
198 27
		return $this->googleService;
199
	}
200
201 27
	private function getLeafletService(): LeafletService {
202 27
		if ( $this->leafletService === null ) {
203 2
			$this->leafletService = new LeafletService(
204 2
				$this->getImageRepository()
205
			);
206
		}
207
208 27
		return $this->leafletService;
209
	}
210
211 27
	public function getDisplayMapFunction(): DisplayMapFunction {
212 27
		return new DisplayMapFunction(
213 27
			$this->getMappingServices()
214
		);
215
	}
216
217 93
	public function getParamDefinitionFactory(): ParamDefinitionFactory {
218 93
		$factory = ParamDefinitionFactory::newDefault();
219
220 93
		$factory->registerType( 'coordinate', [ 'string-parser' => LatLongParser::class ] );
221 93
		$factory->registerType( 'mapslocation', [ 'string-parser' => LocationParser::class ] );
222 93
		$factory->registerType( 'mapsline', [ 'string-parser' => LineParser::class ] );
223 93
		$factory->registerType( 'mapscircle', [ 'string-parser' => CircleParser::class ] );
224 93
		$factory->registerType( 'mapsrectangle', [ 'string-parser' => RectangleParser::class ] );
225 93
		$factory->registerType( 'mapspolygon', [ 'string-parser' => PolygonParser::class ] );
226 93
		$factory->registerType( 'distance', [ 'string-parser' => DistanceParser::class ] );
227 93
		$factory->registerType( 'wmsoverlay', [ 'string-parser' => WmsOverlayParser::class ] );
228 93
		$factory->registerType( 'mapsimageoverlay', [ 'string-parser' => ImageOverlayParser::class ] );
229
230 93
		return $factory;
231
	}
232
233 3
	public function newGeoJsonFetcher( FileFetcher $fileFetcher = null ): GeoJsonFetcher {
234 3
		return new GeoJsonFetcher(
235 3
			$fileFetcher ?? $this->getGeoJsonFileFetcher(),
236 3
			$this->mediaWikiServices->getTitleParser(),
237 3
			$this->mediaWikiServices->getRevisionLookup()
238
		);
239
	}
240
241 4
	public function smwIntegrationIsEnabled(): bool {
242 4
		return !$this->settings['egMapsDisableSmwIntegration'] && defined( 'SMW_VERSION' );
243
	}
244
245
	public function newSemanticMapsSetup( &$mwGlobals ): SemanticMapsSetup {
246
		return SemanticMapsSetup::newFromMediaWikiGlobals( $mwGlobals, $this->getMappingServices() );
247
	}
248
249 4
	public function newSemanticGeoJsonStore( \ParserOutput $parserOutput, Title $subjectPage ): GeoJsonStore {
250 4
		return new SemanticGeoJsonStore(
251 4
			$this->getSmwFactory()->newParserData( $subjectPage, $parserOutput ),
252
			$subjectPage,
253 4
			$this->getSmwFactory()->getEventDispatcher(),
254 4
			new SubObjectBuilder( $subjectPage )
255
		);
256
	}
257
258 4
	private function getSmwFactory(): ApplicationFactory {
259 4
		return ApplicationFactory::getInstance();
260
	}
261
262
	public function getImageRepository(): ImageRepository {
263
		return new MwImageRepository(
264
			$this->getRepoGroup()
265
		);
266
	}
267
268
	private function getRepoGroup(): RepoGroup {
269
		return RepoGroup::singleton();
270
	}
271
272
	public function getMapOutputBuilder(): MapOutputBuilder {
273
		return new MapOutputBuilder(
274
//			$this->getMappingServices(),
275
//			$this->getParamDefinitionFactory()
276
		);
277
	}
278
279
	public function newCargoOutputBuilder(): CargoOutputBuilder {
280
		return new CargoOutputBuilder(
281
			$this->getMapOutputBuilder(),
282
			$this->getMappingServices(),
283
			$this->getParamDefinitionFactory(),
284
			$this->getImageRepository()
285
		);
286
	}
287
288 1
	public function newParserHookSetup( Parser $parser ): ParserHookSetup {
289 1
		return new ParserHookSetup( $parser );
290
	}
291
292
	/**
293
	 * @return ParserHook[]
294
	 */
295 1
	public function newNonMapParserHooks(): array {
296
		$hooks = [
297 1
			new DistanceFunction(),
298 1
			new FindDestinationFunction(),
299 1
			new GeocodeFunction(),
300 1
			new GeoDistanceFunction(),
301 1
			new MapsDocFunction(),
302
		];
303
304 1
		if ( $this->settings['egMapsEnableCoordinateFunction'] ) {
305 1
			$hooks[] = new CoordinatesFunction();
306
		}
307
308 1
		return $hooks;
309
	}
310
311
}
312