Skip to content

Expand the MediaWiki:Maps config page beyond Leaflet layers - #927

Merged
JeroenDeDauw merged 3 commits into
masterfrom
feature/expand-config-page
Jul 20, 2026
Merged

Expand the MediaWiki:Maps config page beyond Leaflet layers#927
JeroenDeDauw merged 3 commits into
masterfrom
feature/expand-config-page

Conversation

@JeroenDeDauw

@JeroenDeDauw JeroenDeDauw commented Jul 19, 2026

Copy link
Copy Markdown
Member

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: LeafletConfigValidatorConfigValidator, WikiLeafletConfigSourceWikiPageConfigSource (now reads the whole page), CombiningLeafletConfigLookupEffectiveSettings; 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 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 excluded. egMapsInternatDirectionLabels is not read anywhere in the code, so exposing it would have no effect (candidate for removal).

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); 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, EffectiveSettings merge/fallback/memoization tests, and integration spot checks that a wiki-set value lands end to end (a general.mapWidth in the rendered HTML, a googleMaps default in the map data, a Leaflet layer definition via the wiki). All #925 tests are preserved through the renames.

AI-authored — Claude Code, Opus 4.8 (max); implemented from a detailed brief prepared by a Fable 5 (max) session on @JeroenDeDauw's behalf, executed autonomously with no human steering mid-task; diff not yet human-reviewed; full PHPUnit suite (474 tests) green locally and CI green (all six checks: code style, PHPStan, PHPUnit MW 1.43/1.44/1.45, QUnit); key paths mutation-tested (value types, validator, merge strategy, effective-settings overlay/read-time guard, end-to-end wiki-value routing); reviewed by an independent Opus subagent with no blocking findings.

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 by Opus 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 (the D modifier), with regression tests. The 6 pre-existing phpcs errors in GoogleMapsService/MapPrinter/CoordinateValue are unrelated to this change and were left untouched.

JeroenDeDauw and others added 3 commits July 20, 2026 01:47
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>
@JeroenDeDauw
JeroenDeDauw marked this pull request as ready for review July 20, 2026 13:30
@JeroenDeDauw
JeroenDeDauw merged commit df6d96f into master Jul 20, 2026
8 checks passed
@JeroenDeDauw
JeroenDeDauw deleted the feature/expand-config-page branch July 20, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expand the MediaWiki:Maps config page beyond the Leaflet layer settings

1 participant