Jump to content

Extension:CommunityConfiguration/Technical documentation

From mediawiki.org

Getting started

[edit]

Registering a new provider

[edit]

Community configuration providers are a formal description of how a set of configuration options should be handled by the extension. They consist of three main component declarations: store, validator and an optional form. The following example shows how to add a provider using extension.json attributes:

"attributes": {
		"CommunityConfiguration": {
			"Providers": {
				"MyProvider": {
					"store": {
						"type": "wikipage",
						"args": [
							"MediaWiki:ExampleConfig.json"
						]
					},
					"validator": {
						"type": "jsonschema",
						"args": [
							"CommunityConfigurationExample\\Schemas\\ExampleSchema"
						]
					},
					"type": "mw-config"
				}
			}
		}
	},

There are other mechanisms for registering a new configuration provider, through MW Configuration setting $wgCommunityConfigurationProviders or using the CommunityConfigurationProvider_initListHook hook, CommunityConfigurationProvider_initListHook.


Creating a JSON schema with PHP

[edit]

The extensions provides a JsonSchema interface to facilitate creating JSON schema document representations with a PHP class. This also restricts the JSON schema features available to those Community Configuration can handle. Below a minimal example of an schema class:

<?php

namespace CommunityConfigurationExample\Schemas;

use MediaWiki\Extension\CommunityConfiguration\Schema\JsonSchema;

class ExampleSchema implements JsonSchema {
	public const ExampleConfigOption = [
		self::TYPE => self::TYPE_STRING
	];
}

Public class properties are collected as top level keys of an object. At this stage, Community Configuration can only work with type object for the top level data structure. Hence there's no support for top level type array. The ExampleSchema class would be expanded to the following JSON schema in json format:

{
	"$schema": "https://json-schema.org/draft-04/schema#"
	"$id": "CommunityConfigurationExample/Schemas/ExampleSchema/1.0.0",
	"type": "object",
	"properties": {
		"ExampleConfigOption": {
			"type": "string"
		}
	},
	"additionalProperties": false
}

Creating a new config page

[edit]

The configuration data for a given set of options under a provider is stored as wiki json pages in the MediaWiki namespace. Whenever you create a new provider using the "type": "wikipage" for its store, you'll need to create the page on your target wiki and add a valid configuration for the first time. This action requires some privileged rights, currently, any of 'administrator', 'interface administrator' (see more in docs/CC-user-rights-tbd).

This process is tedious and not ideal, further improvements are being discussed in task T351517

PHP schemas

[edit]

CommunityConfiguration is designed to work with PHP files as the source for defining json-schema compliant documents. This approach is also used in other MediaWiki software components such as MainConfigSchema. The support for PHP schemas is built ad-hoc in the extension and has limitations compared to the full json-schema specification.

Limitations

[edit]
  • Limited support for json-schema version draft-04
  • Root schema must be of "type": "object"
  • No support for multiple types in any schema definition
  • additionalProperties is set to false for root properties

JSON-schema vocabulary

[edit]

The following json-schema keywords are supported:

Extended vocabulary

[edit]
  • control

Building the schema

[edit]

Internally, the CommunityConfiguration extension compiles each of the PHP files into an actual JSON schema (represented as PHP arrays). By default, the compiled schema is used in several other places:

  • the JSON validation library[1] to validate the configuration against the schema
  • the frontend, to generate the default editing form

This is the default behaviour, which can be adjusted as-needed. Validation library can be changed by setting a different validator. Editing form can be changed by setting a different editor capability.

MediaWiki Core is ultimately responsible for building the schema. CommunityConfiguration triggers the build via JsonSchemaBuilder::getRootSchema, which internally calls ReflectionSchemaSource::loadAsSchema from Core.

References

[edit]

A schema might choose to reference a different schema using the $ref keyword. References are identified via a PHP associative array of the following format: [ 'class' => CLASSNAME, 'field' => 'Constant' ]. CLASSNAME is a fully-qualified name of a PHP class, which must meet the requirements for a PHP schema. Constant is a name of a PHP constant within that class, which is the referenced subschema. It is currently not possible to reference a full class.

During the schema building process, ReflectionSchemaSource inlines all references. The result is a flat JSON schema (with all references replaced with their actual content). Using the built schema, it is impossible to determine whether references were used or not.

Note the behaviour of CommunityConfiguration is different than the standard JSON schema references. Normally, JSON Schema's $ref keyword is based on JSON Pointer URIs, and users access the subschema via the pointer URI. CommunityConfiguration inlines all references before making use of the schema, which is done to make processing the schema a bit easier.

Example

[edit]

With the following declarations:

class ExampleSchema extends JsonSchema {

	public const ExamplePageTitle = [
		self::REF => [
			'class' => MediaWikiDefinitions::class, 'field' => 'PageTitle'
		]
	];
}

class MediaWikiDefinitions extends JsonSchema {
	public const PageTitle = [
		self::TYPE => self::TYPE_STRING,
		self::DEFAULT => '',
	];
}

parsing ExampleSchema results in the following result:

[
    "$schema" => "https://json-schema.org/draft-04/schema#",
    "$id" => "CommunityConfigurationExample/Schemas/ExampleSchema",
    "additionalProperties" => false,
    "type" => "object",
    "properties" => [
      "ExamplePageTitle" => [
        "type" => "string",
        "default" => "",
      ],
    ],
]

If needed, the parsing can be triggered via a shell.php session using \MediaWiki\MediaWikiServices::getInstance()->get('CommunityConfiguration.ProviderFactory')->newProvider('ProviderName')->getValidator()->getSchemaBuilder()->getRootSchema() (replacing ProviderName with the name of the respective provider).

Versioning

[edit]

Schema definitions need to change occasionally due to new product or technical requirements. CommunityConfiguration provides a way for developers to migrate between schema versions. All schemas extending the JsonSchema class have a public constVERSION = '1.0.0' that can be override for bumping the schema version, eg: public constVERSION = '1.0.1'. Learn more about migrations in the section below.

Migrations

[edit]

In order for CommunityConfiguration to ease with a schema version migration a convenience maintenance script CommunityConfiguration/maintenance/migrateConfig.php is provided. Find the steps to prepare for a migration below:


Backup the current schema

[edit]

In order to access older schema versions, create a copy of the current schema version in some directory in your extension. The schema backup file name should contain its version number suffixed with underscore separators and the class name should also be updated to avoid duplicating the already declared. For example:

Schemas
├── Migrations
│   └── MySchema_1_0_0.php
└── MySchema.php

Link the older schema to the new one using: public const SCHEMA_NEXT_VERSION = '2.0.0';

Bump the schema version

[edit]

Once the new schema version definitions have been added, removed or changed, set a higher version number in the schema file, MySchema.php. Link the new schema version to the older one using SCHEMA_PREVIOUS_VERSION. For example:

class MySchema extends JsonSchema {

	public const VERSION = '2.0.0';
	public const SCHEMA_PREVIOUS_VERSION = '1.0.0';
	public const SCHEMA_CONVERTER = MySchemaConverter_2_0_0::class;
    
    // Add, remove or change definitions
    
    public const NewDefinition = [
        self::TYPE => self::TYPE_STRING,
		self::DEFAULT => '',
    ]
}

Create a converter

[edit]

In order to be able to transform some configuration data format from one schema version to another, the extension provides conventional methods in the ISchemaConverter interface. Create a PHP class implementing such interface and suffixing the new version number on its file name, for example:

Schemas
├── Converters
│   └── MySchemaConverter_2_0_0.php
├── Migrations
│   └── MySchema_1_0_0.php
└── MySchema.php

Implement interface methods upgradeFromOlder and downgradeFromNewer, for example:

class MySchemaConverter_2_0_0 implements ISchemaConverter {

	public function upgradeFromOlder( stdClass $data ): stdClass {
		$data->NewDefinition = '';
		return $data;
	}

	public function downgradeFromNewer( stdClass $data ): stdClass {
		unset( $data->NewDefinition );
		return $data;
	}
}

Run the migration

[edit]

In order to apply the migration to the existing config use migrateConfig maintenance script in the extension pointing to the provider using the target schema.

> php extensions/CommunityConfiguration/maintenance/migrateConfig.php MyProvider

Glossary

[edit]
  • schema: polysemic, it can refer to a full configuration specification in a PHP file, eg: MySchema.php or to the specification of a property at any level in the schema, eg: { "type": "string" }
  • subschema: used to disambiguate schema, refers to the specification of a property at any level in the schema as opposed to the full schema.
  • root schema: used to disambiguate schema, refers to the top level specification of a full schema. In CommunityConfiguration this is restricted to be "type": "object", see [Extension:CommunityConfiguration/Technical_documentation#tbd].
  • property: refers to the schema defined under the key "properties" in any schema.
  • root property: refers to the schema defined under the key "properties" in the root schema.

References

[edit]
  1. As of July 2024, jsonrainbow/json-schema is used.