Expand the MediaWiki:Maps config page beyond Leaflet layers - #927
Merged
Conversation
Fixes #926 Follows-up to #925 Generalizes the MediaWiki:Maps config page (added in #925 for Leaflet layers) to expose most Maps settings, driven by a single declarative schema so that exposing a setting is one schema entry rather than bespoke code. ## Design Maps\Config\ConfigSchema lists every exposed setting as a ConfigSetting: page group + key, the egMaps*/smgQP* setting it overrides, its value type, and its merge strategy. It drives both save-time validation and read-time application: * ConfigValidator walks the schema on save (EditFilter hook), rejecting unknown groups/keys and per-value type errors. * EffectiveSettings is the one effective-settings lookup wrapping the PHP settings with the schema-translated wiki overlay. It reads the page lazily at parse time, memoizes the result, falls back to the PHP settings on any Throwable or when disabled, and ignores wiki values that fail their type validation. All exposed-setting consumption sites read through it instead of $GLOBALS. Value types are small reusable objects: boolean, integer, string, enum, enum list, string list, dimension, positive-number map, pattern, plus the layer-definitions and availability specials. Wiki values replace the PHP value, except layerDefinitions, availableLayers and availableOverlays, which merge per name via a MergeStrategy attribute of those entries. The #925 Leaflet-specific classes were reshaped into this general concept: LeafletConfigValidator -> ConfigValidator, WikiLeafletConfigSource -> WikiPageConfigSource (now reads the whole page), CombiningLeafletConfigLookup -> EffectiveSettings; LeafletConfig/LeafletConfigLookup dissolved into LeafletService reading the effective settings directly. LeafletLayerContract and AttributionSanitizer are unchanged. ## Exposed and excluded Groups: general, coordinates, geocoding, semanticMediaWiki, leaflet, googleMaps (see the README for the full key list). Secrets/API keys, script-injection primitives, the caches and setup-time switches stay PHP-only, as decided in the issue. Two settings from the issue's list are deviated from: * defaultService is excluded. egMapsDefaultService is consumed when MappingServices is constructed and when SMW result-format aliases are registered, both during extension setup before the config page can be read. Routing it would force a wiki read at setup, defeating the lazy design, so it stays PHP-only. * internationalDirectionLabels is excluded. egMapsInternatDirectionLabels is not read anywhere in the code, so exposing it would have no effect. distanceUnit is validated as a plain string rather than against the effective units: an unknown default unit self-heals to the first available unit at runtime and cannot hard-fail. ## Security mapWidth/mapHeight use a strict dimension pattern (they reach inline styles), googleMaps.language a strict pattern (it reaches the Google API URL), and distance unit names are restricted to alphanumerics (they reach a regex and rendered output). Layer definitions keep the #925 hardening unchanged. ## Tests Table-driven unit tests per value type, schema and validator tests, EffectiveSettings merge, fallback and memoization tests, and integration spot checks that a wiki-set value lands end to end. All #925 tests are preserved through the renames. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dimension, distance-unit-name and Google Maps language patterns anchored with $, which matches just before a trailing newline. Add the D modifier so a value with a trailing newline is rejected, keeping these strict patterns fully strict before their style, URL and regex sinks. Harmless in practice since the sinks escape or encode, found in review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Several page keys are deliberately renamed from their PHP settings (e.g. pagesWithMapsCategory for egMapsEnableCategory), so the reference list should not claim the names are the same. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #926
Follows-up to #925
Generalizes the MediaWiki:Maps config page (added in #925 for Leaflet layers) to expose most Maps settings, driven by a single declarative schema so that exposing a setting is one schema entry rather than bespoke code.
Design
Maps\Config\ConfigSchemalists every exposed setting as aConfigSetting: page group + key, theegMaps*/smgQP*setting it overrides, its value type, and its merge strategy. It drives both save-time validation and read-time application:ConfigValidatorwalks the schema on save (EditFilterhook), rejecting unknown groups/keys and per-value type errors.EffectiveSettingsis the one effective-settings lookup wrapping the PHP settings with the schema-translated wiki overlay. It reads the page lazily at parse time, memoizes the result, falls back to the PHP settings on anyThrowableor when disabled, and ignores wiki values that fail their type validation. All exposed-setting consumption sites read through it instead of$GLOBALS.Value types are small reusable objects: boolean, integer, string, enum, enum list, string list, dimension, positive-number map, pattern, plus the layer-definitions and availability specials. Wiki values replace the PHP value, except
layerDefinitions,availableLayersandavailableOverlays, which merge per name via aMergeStrategyattribute of those entries.The #925 Leaflet-specific classes were reshaped into this general concept:
LeafletConfigValidator→ConfigValidator,WikiLeafletConfigSource→WikiPageConfigSource(now reads the whole page),CombiningLeafletConfigLookup→EffectiveSettings;LeafletConfig/LeafletConfigLookupdissolved intoLeafletServicereading the effective settings directly.LeafletLayerContractandAttributionSanitizerare unchanged.Exposed and excluded
Groups:
general,coordinates,geocoding,semanticMediaWiki,leaflet,googleMaps(see the README for the full key list). Secrets/API keys, script-injection primitives, the caches and setup-time switches stay PHP-only, as decided in the issue.Two settings from the issue's list are deviated from:
defaultServiceexcluded.egMapsDefaultServiceis consumed whenMappingServicesis constructed and when SMW result-format aliases are registered, both during extension setup before the config page can be read. Routing it would force a wiki read at setup, defeating the lazy design, so it stays PHP-only.internationalDirectionLabelsexcluded.egMapsInternatDirectionLabelsis not read anywhere in the code, so exposing it would have no effect (candidate for removal).distanceUnitis validated as a plain string rather than against the effective units: an unknown default unit self-heals to the first available unit at runtime and cannot hard-fail.Security
mapWidth/mapHeightuse a strict dimension pattern (they reach inline styles),googleMaps.languagea strict pattern (it reaches the Google API URL), and distance unit names are restricted to alphanumerics (they reach a regex and rendered output); all three reject a trailing newline. Layer definitions keep the #925 hardening unchanged.Tests
Table-driven unit tests per value type, schema and validator tests,
EffectiveSettingsmerge/fallback/memoization tests, and integration spot checks that a wiki-set value lands end to end (ageneral.mapWidthin the rendered HTML, agoogleMapsdefault in the map data, a Leaflet layer definition via the wiki). All #925 tests are preserved through the renames.Production notes
Design and the implementation brief (schema shape, exposed/excluded split, per-setting security requirements) by a
Fable 5 (max)session; implementation, tests and docs byOpus 4.8 (max). An independent Opus code-review subagent found no blocking or major issues; its one actionable nit — the three security patterns matching just before a trailing newline — is fixed in the second commit (theDmodifier), with regression tests. The 6 pre-existing phpcs errors inGoogleMapsService/MapPrinter/CoordinateValueare unrelated to this change and were left untouched.