Extensión:JsonConfig
La extensión JsonConfig permite a otras extensiones almacenar sus datos de configuración en forma de blob JSON dentro de una página wiki.
Funcionalidades disponibles y patrones de uso
- Puedes usar JsonConfig para almacenar datos de varias maneras:
- en una sola página de configuración, por ejemplo, una serie de ajustes para su extensión en Config:MyExtSettings (
Config
es el espacio de nombres predeterminado asociado con la extensión JsonConfig); - en un conjunto de páginas con estructura similar que residen en su propio espacio de nombres, por ejemplo, direcciones IP de proxies conocidos o esquemas de registros de eventos nombrados «Proxy:Opera» o esquemas nombrados Schema:AccountCreation
- usarlo solo para páginas cuyo título se ajuste a un patrón regex, p. ej. Config:Proxy:Opera or Config:Opera.proxy. Esto evita llenar un wiki con numerosos espacios de nombres, uno por cada modelo de contenido.
- en una sola página de configuración, por ejemplo, una serie de ajustes para su extensión en Config:MyExtSettings (
- Puedes proporcionar una clase de contenido para la validación de datos (más allá del JSON válido) y su normalización.
- Puedes proporcionar una clase de visualización para personalizar la apariencia del HTML.
- Puedes almacenar datos:
- «uno por wiki», «uno por agrupación (clúster)» o incluso por «familia» (estructura diferente de la clave de caché para el memcached compartido);
- en un wiki público o privado y accesible con credenciales;
- en una agrupación separada, y notificar de los cambios de forma remota.
Uso dentro del wiki
Actual
- Conjuntos de datos tabulares de Commons
- Conjunto de datos en mapas de Commons
- Configuraciones de dashboards Dashiki
- ¿Otros?
En el pasado
- Configuraciones de operador de Wikipedia Zero (véase Extension:ZeroBanner)
Instalación
- Descarga y extrae los archivos en un directorio denominado «
JsonConfig
» dentro de la carpetaextensions/
.
Developers and code contributors should install the extension from Git instead, using:cd extensions/
git clone https://gerrit.wikimedia.org/r/mediawiki/extensions/JsonConfig - Añade el siguiente código en la parte final de tu archivo LocalSettings.php :
wfLoadExtension( 'JsonConfig' );
- Configúralo según se requiera.
- Hecho – Navega a Special:Version en el wiki para verificar que la extensión se haya instalado correctamente.
Configuración
$wgJsonConfigs
Esta variable define perfiles para cada tipo de página de configuración.
$wgJsonConfigs
es una matriz asociativa de matrices, teniendo cada una de las cuales cero o más de los siguientes parámetros.
Por defecto, JsonConfig usa una clave en forma de cadena de caracteres como identificador del modelo que este perfil representa, pero en caso de que desees reutilizar el mismo identificador de modelo en más de un perfil, puedes invalidarlo mediante el parámetro model
.
parámetro | tipo | por defecto | descripción |
---|---|---|---|
model | string | (clave en $wgJsonConfigs )
|
Identificador del modelo que usar al crear una página nueva. Si no se proporciona ninguno, la clave de matriz de este perfil se convierte en el identificador del modelo. Si se establece el valor a null , se usará el identificador JsonConfig del módulo predefinido. El identificador del modelo también debe estar en la lista de $wgJsonConfigModels excepto para null o 'JsonConfig' .
|
namespace | int | NS_CONFIG (482) | Espacio de nombres en que residirán estas configuraciones, o 'Config:' por defecto |
nsName | string/false | Para espacios de nombres no predeterminados (es decir, distintos de NS_CONFIG 482), se le asigna un nombre canónico (en inglés). Si más de una matriz $wgJsonConfigs usa el mismo espacio de nombres, fija el nombre una sola vez. Si no se encuentra, se dará una advertencia y el espacio de nombres recibirá automáticamente el nombre «ConfigNNN». En caso de que no se almacene localmente esta configuración, se usará nsName como espacio de nombres remoto sin declaración local. Si deseas compartir espacio de nombres con otras páginas que no sean de contenido JsonConfig, fija este valor a | |
nsTalk | string | nsName+_talk
|
Para espacios de nombres no predeterminados, se asigna a sus páginas de discusión un nombre canónico (en inglés). |
pattern | string | (all) | Expresión regular para coincidir con el título de la página en el espacio de nombres dado. Si está vacío, la configuración se aplicará a todas las páginas del espacio de nombres. Para adoptar el antiguo comportamiento de «subespacios», para isSubspace=true , usa el patrón ^/^name:./ , y para isSubspace=false , usa el patrón /^name$/ .
|
isLocal | bool | true | Si el valor es true , esta configuración no se compartirá por toda la agrupación, sino que cada wiki tendrá una configuración local. Si el valor es false , se pretende que esta configuración se comparta entre múltiples wikis, y para hacer que este wiki específico la almacene en local, fija el campo 'store'.Esta bandera afecta a la clave de caché, de forma que una página de configuración con el mismo nombre será almacenada en memcached si el valor es
false , pero será única por wiki si el valor es true . |
cacheExp | int | 24*60*60 | Duración (en segundos) del almacenamiento del valor en caché en memcached |
cacheKey | string | Si se ha establecido el valor, añade esa cadena a la clave de caché. Usa cacheKey para invalidar los valores anteriores en caché: p. ej. cuando realices un cambio incompatible que modificaría los valores en caché y te preocupa la posibilidad de que necesites revertirlo. Esta clave también se puede usar para permitir que todos los wikis en distintos idiomas pertenecientes a la misma familia compartan el mismo valor en caché a la vez que se almacenan en la misma página pero en wikis diferentes. Por ejemplo, Wikipedia podría usar «wp» y Wikiquote «wq».
| |
flaggedRevs | bool | false | Si el valor es true , se intentará recuperar la última revisión que haya sido verificada mediante la extensión de revisiones marcadas (FlaggedRevs); si es null , se comprobará la revisión marcada, y, si está disponible, se usará. Si es false , se usará siempre la última revisión.
|
remote | array | Un objeto con parámetros que describen cómo acceder a la configuración desde otro wiki. Debe estar presente si no se ha inicializado 'store' y si el valor de isLocal es false .
| |
‑ url | string | Punto de acceso distinto del predeterminado de la API desl que obtener la configuración del wiki remoto sólo para este perfil de configuración. Si no se especifica, se usará el valor de $wgJsonConfigApiUri .
| |
‑ username | string | Si se da, se usará para la autenticación del usuario contra el almacenamiento de configuración remoto. | |
‑ password | string | Véase username .
| |
store | array | Inicializa este valor a true o a una matriz para que que el wiki actual aloje estos datos de configuración. Este valor se rellenará automáticamente si está ausente y el valor de isLocal es true .
| |
‑ cacheNewValue | bool | true | Cómo debe cambiar la caché ante cambios de configuración. Si el valor es false , elimina el valor almacenado en caché forzando a otros wikis a volver a pedirlo. true fija el nuevo valor en la caché. Esto es útil sobre todo si el wiki que almacena esta configuración y los wikis que la consumen comparten la misma caché. Ten en cuenta que, en caso de false , si el wiki consumidor pide el nuevo valor demasiado rápido, podría obtenerlo de una base de datos esclava posiblemente obsoleta.
|
‑ notifyUrl | string | Especifica opcionalmente la URL de la API remota a la que se llamará ante un cambio de la configuración. | |
‑ notifyUsername | string | Nombre de usuario opcional para utilizar con notifyUrl
| |
‑ notifyPassword | string | Contraseña opcional para utilizar con notifyUrl
|
$wgJsonConfigModels
Esta variable define qué clase de contenido personalizada manejará qué identificador de modelo (modelID).
Una misma clase de contenido puede manejar más de un identificador de modelo.
Todas las clases de contenido deben derivarse de la clase JCContent
; si el modelID corresponde a null
, entonces la clase por defecto JCContent
manejará el identificador de modelo.
Ejemplo:
$wgJsonConfigModels['Config.MyExtSettings'] = 'MyExt\MyContentClass';
Si implementas una clase separada para renderizar el HTML, puedes especificar el modelo de configuración como una matriz con la clase adicional view
:
$wgJsonConfigModels['Config.MyExtSettings'] = [
'class' => 'MyExt\MyContentClass',
'view' => 'MyExt\MyContentViewClass', // easier to extend JCDefaultObjContentView or JCDefaultContentView
];
Ejemplos
name
y isSubspace
para personalizar qué páginas pertenecían al modelo de contenido dado. Los dos se han eliminado en la versión 1.0.0, siendo reemplazados por el parámetro pattern
, que acepta una expresión regular. Asegúrate de delimitar tus patrones con los símbolos ^ y $, y añade barras oblicuas (estilo PHP)
Hola mundo
El caso más simple es una sola página de configuración sin validación alguna almacenada de forma local en cada wiki. Simplemente añade estas declaraciones a LocalSettings.php
// Content model is 'JsonConfig.MySettings'
// Model class is set to NULL to allow non-validated data
$wgJsonConfigModels['JsonConfig.MySettings'] = null;
$wgJsonConfigs['JsonConfig.MySettings'] = array(
'pattern' => '/^MySettings$/', // Page name in Config namespace
);
Lo anterior habilita el espacio de nombres «Config» en el wiki local, pero no permite crear en ese espacio de nombres más que la página «Config:MySettings». Puedes almacenar en la página datos en forma de JSON bien formado.
Para leer los datos de MySettings en PHP, utiliza un objeto TitleValue
para acceder a la página, y luego solicita su contenido:
use JsonConfig\JCSingleton;
$tv = new TitleValue( NS_CONFIG, 'MySettings' ); // DB Key
$content = JCSingleton::GetContent( $tv );
if ( $content->isValid() ) {
$data = $content->getData();
...
}
Implementar plantillas Wikimedia
Algunas plantillas de proyectos Wikimedia (p. ej., Template:TNT) requieren que JsonConfig tenga soporte para el espacio de nombres Data en Commons para mw.ext.data.get
. Puedes usar la siguiente configuración para implementar ese caso de uso.
wfLoadExtension( 'JsonConfig' );
$wgJsonConfigEnableLuaSupport = true; // required to use JsonConfig in Lua
$wgJsonConfigModels['Tabular.JsonConfig'] = 'JsonConfig\JCTabularContent';
$wgJsonConfigs['Tabular.JsonConfig'] = [
'namespace' => 486,
'nsName' => 'Data',
// page name must end in ".tab", and contain at least one symbol
'pattern' => '/.\.tab$/',
'license' => 'CC0-1.0',
'isLocal' => false,
];
$wgJsonConfigModels['Map.JsonConfig'] = 'JsonConfig\JCMapDataContent';
$wgJsonConfigs['Map.JsonConfig'] = [
'namespace' => 486,
'nsName' => 'Data',
// page name must end in ".map", and contain at least one symbol
'pattern' => '/.\.map$/',
'license' => 'CC0-1.0',
'isLocal' => false,
];
$wgJsonConfigInterwikiPrefix = "commons";
$wgJsonConfigs['Tabular.JsonConfig']['remote'] = [
'url' => 'https://commons.wikimedia.org/w/api.php'
];
$wgJsonConfigs['Map.JsonConfig']['remote'] = [
'url' => 'https://commons.wikimedia.org/w/api.php'
];
Configuraciones múltiples compartidas en una agrupación (clúster)
Digamos que decidimor almacenar las direcciones IP de los proxies de confianza como páginas «Config:Proxy:Ejemplo» en Meta-Wiki y compartir estos datos con la agrupación.
// All wikis must have this configuration:
$wgJsonConfigs['JsonConfig.Proxy'] = [
'pattern' => '/^Proxy\:./', // require at least one letter after the ':'
'isLocal' => false,
];
// The LocalSettings.php for all wikis except Meta-Wiki will set this URL to Meta-Wiki's API endpoint:
$wgJsonConfigs['JsonConfig.Proxy']['remote'] = 'http://meta.wikimedia.org/w/api.php';
// LocalSettings.php for Meta-Wiki will indicate that the data should be stored there
$wgJsonConfigs['JsonConfig.Proxy']['store'] = true;
Si en vez de esto prefieres dedicar un espacio de nombres separado a los proxies, los parámetros cambiarán a:
$wgJsonConfigs['JsonConfig.Proxy'] = [
'namespace' => NNN, // NNN is the number you would reserve for Proxy namespace
'nsName' => 'Proxy', // Canonical namespace name
];
Validación
Most of the time one would also want a custom content class with its own validation.
JSON pages are handled by the content classes which derive from JCContent
.
The content class is responsible for parsing and validating raw text.
JCContent
does not do any validation beyond JSON parsing, but you may choose to derive from it and override JCContent::validate()
.
Better yet, you may derive from the JCObjContent
class which provides a number of validation primitives, and only override JCObjContent::validateContent()
.
// This should be done on all wikis, including Meta-Wiki
$wgJsonConfigModels['JsonConfig.Proxy'] = 'ProxyExt\ProxyContent';
For the sake of this documentation, let's presume that the proxy config page describing Opera Mini servers has this format:
{
"enabled": true,
"comment": "See http://... for updates",
"ips": [
'37.228.104.0/21',
...
]
}
Here is the content class to validate that data.
use JsonConfig\JCObjContent;
use JsonConfig\JCValidators;
class ProxyContent extends JCObjContent {
/**
* Derived classes must implement this method to perform custom validation
* using the check(...) calls
*/
public function validateContent() {
// 'enabled' must be a boolean, true by default.
// JCValidators::* already handle localized error messages
$this->testOptional( 'enabled', true, JCValidators::isBool() );
// an optional field 'comment' of type string
$this->testOptional( 'comment', '', JCValidators::isString() );
// 'ips' must be a list of valid CIDR ranges
// field is not optional when default value would not pass validation
$this->test( 'ips', self::getIpValidator() );
}
private static function getIpValidator() {
// JCValue $value is a value of the field being checked wrapped with the status information.
// $v->getValue() actual value being examined
// $v->isMissing() if the value is not present in the data
// $v->defaultUsed() if the value did not exist and a default was supplied
// array $path the location of this field in the hierarchy - each value is either string or an int
// JCObjContent $self - this object, useful to get access to other fields via $self->getField()
// You may modify the value stored inside, set additional flags, or report an error
// using the $v->error( $key, $path, ... ) function
return function ( JCValue $value, array $path, JCObjContent $self ) {
$isErr = false;
$v = $value->getValue();
if ( is_string( $v ) ) {
// user supplied a single string, treat as an non-assoc array
$v = array( $v );
} else {
// ensure that $v is an non-assoc array, and all of its values are strings
$isErr = !JCUtils::isList( $v ) || !JCUtils::allValuesAreStrings( $v );
}
if ( !$isErr ) {
// @todo: do the rest of the IP validation and set $isErr to true on failure
}
// Error message might be in this form:
// "Parameter \"$1\" must be an array of valid non-restricted (no private networks) CIDR IP blocks"
if ( $isErr ) {
$value->error( 'my-proxyconfig-err-ips', $path );
} else {
$value->setValue( $v );
}
};
}
}
Customizing behavior on the storage wiki
You may also want to customize viewing and page creation on the storage wiki (Meta-Wiki in the above example).
There are two ways to do this: inside your JCContent
-derived class, or via a separate "view" class that derives from JCContentView
.
The second approach is preferable as it cleanly separates the architecture and the view class need only exist in the storage wiki (e.g. Meta-Wiki), not on all the wikis that use the data.
To override default value in JCContent
-derived class, override the constructor and set the $text
value to the new default if it came in as NULL before passing it to the parent constructor.
To override the HTML generation, override JCContent::getHtml()
.
With the recommended way, create a view class that derives from JCContentView
or a more feature-rich JCDefaultContentView
.
For JCContentView
, you will need to implement valueToHtml()
and getDefault()
.
By default, the view is implemented by the JCDefaultContentView
class, which can also be used as a customizable base if you just need minor adjustments to the way it looks.
// Changing model definition from the above - should be done on all wikis, including META
$wgJsonConfigModels['JsonConfig.Proxy'] = [ 'class' => 'ProxyExt\ProxyContent' ];
// Add the view class - should only be done on the storage wiki (e.g. META)
$wgJsonConfigModels['JsonConfig.Proxy']['view'] = 'ProxyExt\ProxyView';
class ProxyView extends JsonConfig\JCDefaultObjContentView {
public function getDefault( $modelId ) {
return <<<JSON
{
"comment": "See http://... for updates",
"ips": [
"N.N.N.N/NN",...
]
}
JSON;
}
}
Best practices
- Extensions that use JsonConfig should add their configurations to the
$wgJsonConfigs
and$wgJsonConfigModels
in the main extension file. - If you share config data among multiple wikis, document the key name used in
$wgJsonConfigs[]
, and initialize the 'store' / 'remote' section inLocalSettings.php
. This is better than introducing a number of global variables that duplicate the config functionality. See for example Wikimedia's configuration of the Graph extension across multiple wikis (although that uses complex multi-wiki setup rather than simple config variables).
Status
Implemented features
- JSON parsing converts JSON text into either an array or an object
- Visualization shows JSON as an easy to view table rather than code, with some extra highlighting. For example if the value is not provided and a default is used, it is shown in gray, or when the value is the same as default, it shows as purple. For example, see this and this.
- Code Editor simplifies JSON editing
- Custom Validation performs complex checks such as checking that the value is in the proper format or that a user ID exists.
- MemCached caching stores json blobs in memcached under custom keys and expiration policies, and resets them on save.
- Flagged Revisions support allows configurations to be marked as "reviewed" before going into production
- Localization of most basic interface elements has been done in many languages, and it would reduce translation work if most common messages would be done just once in one place.
Unimplemented nice-to-haves
These features would be desirable to more than one type of configs:
- Schema validator - Validate against JSON Schema, as most extensions might not need complex validation rules, or might want to combine schema plus extra validation.
- Custom editor - Zero team has been thinking about implementing a more complex editor, possibly based on JSON Schema.
- API query support - Allow config pages to be returned as regular API results in all formats - json/xml/... instead of text blobs:
api.php ? action=query & titles=Config:Proxy:Opera & prop=jsonconfig
- Localization - it would be good to be able to show localized descriptions for each configuration key
External access
The stored configuration data may frequently be needed by some external agent such as JavaScript, bot, or other programs.
JavaScript could use either JSONP to access needed data by calling standard action=query&rvprop=content
API, or we could develop a forwarding service if CORS is unavailable.
Extension authors may choose to add their own API modules to provide domain-specific information.
Lastly, the rvprop=jcddata
Query API parameter would return JSON data as part of the API result, not as a text blob that rvprop=content
would return.
// NOT IMPLEMENTED! Use regular action=query API until we decide how to do it right
var req = {
format: 'json', action: 'query',
titles: 'Proxy:Opera',
prop: 'revisions', rvprop: 'jcdcontent', indexpageids: '',
};
$.ajax({
url: '//meta.wikipedia.org/w/api.php',
data: req, cache: true, dataType: 'jsonp',
success: function(result) { /* handle errors and warnings, process content */ }
});
See also
Esta extensión está siendo usada en uno o más proyectos de Wikimedia. Esto significa probablemente que la extensión es estable y funciona lo suficientemente bien como para ser usada en sitios con gran cantidad de visitas. Puedes buscar el nombre de esta extensión en los archivos CommonSettings.php e InitialiseSettings.php de Wikimedia para ver dónde se instala. Encontrarás la lista completa de extensiones instaladas en un wiki en particular en la página Special:Version del wiki. |
Esta extensión está incluida en los siguientes anfitriones/granjas wiki y/o paquetes: No se trata de una lista oficial. Algunas granjas/hosts wiki y/o paquetes pueden tener disponible esta extensión aunque no estén listados aquí. Siempre compruébelo con su anfitrión o granja wiki para confirmarlo. |