wiki.techinc.nl/includes/Revision/SlotRoleRegistry.php
Thiemo Kreuz 8fb3666148 Remove comments documenting constructors as "constructors"
Such comments are cruft and do not add anything that's not already
obvious from the code.

Change-Id: I42068b0c6c904bc4ee38f1700e0ea14c3d659a25
2019-01-08 10:11:36 +00:00

234 lines
7.5 KiB
PHP

<?php
/**
* This file is part of MediaWiki.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Revision;
use InvalidArgumentException;
use LogicException;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Storage\NameTableStore;
use Wikimedia\Assert\Assert;
/**
* A registry service for SlotRoleHandlers, used to define which slot roles are available on
* which page.
*
* Extensions may use the SlotRoleRegistry to register the slots they define.
*
* In the context of the SlotRoleRegistry, it is useful to distinguish between "defined" and "known"
* slot roles: A slot role is "defined" if defineRole() or defineRoleWithModel() was called for
* that role. A slot role is "known" if the NameTableStore provided to the constructor as the
* $roleNamesStore parameter has an ID associated with that role, which essentially means that
* the role at some point has been used on the wiki. Roles that are not "defined" but are
* "known" typically belong to extensions that used to be installed on the wiki, but no longer are.
* Such slots should be considered ok for display and administrative operations, but only "defined"
* slots should be supported for editing.
*
* @since 1.33
*/
class SlotRoleRegistry {
/**
* @var NameTableStore
*/
private $roleNamesStore;
/**
* @var callable[]
*/
private $instantiators = [];
/**
* @var SlotRoleHandler[]
*/
private $handlers;
/**
* @param NameTableStore $roleNamesStore
*/
public function __construct( NameTableStore $roleNamesStore ) {
$this->roleNamesStore = $roleNamesStore;
}
/**
* Defines a slot role.
*
* For use by extensions that wish to define roles beyond the main slot role.
*
* @see defineRoleWithModel()
*
* @param string $role The role name of the slot to define. This should follow the
* same convention as message keys:
* @param callable $instantiator called with $role as a parameter;
* Signature: function ( string $role ): SlotRoleHandler
*/
public function defineRole( $role, callable $instantiator ) {
if ( $this->isDefinedRole( $role ) ) {
throw new LogicException( "Role $role is already defined" );
}
$this->instantiators[$role] = $instantiator;
}
/**
* Defines a slot role that allows only the given content model, and has no special
* behavior.
*
* For use by extensions that wish to define roles beyond the main slot role, but have
* no need to implement any special behavior for that slot.
*
* @see defineRole()
*
* @param string $role The role name of the slot to define, see defineRole()
* for more information.
* @param string $model A content model name, see ContentHandler
* @param array $layout See SlotRoleHandler getOutputLayoutHints
*/
public function defineRoleWithModel( $role, $model, $layout = [] ) {
$this->defineRole(
$role,
function ( $role ) use ( $model, $layout ) {
return new SlotRoleHandler( $role, $model, $layout );
}
);
}
/**
* Gets the SlotRoleHandler that should be used when processing content of the given role.
*
* @param string $role
*
* @throws InvalidArgumentException If $role is not a known slot role.
* @return SlotRoleHandler The handler to be used for $role. This may be a
* FallbackSlotRoleHandler if the slot is "known" but not "defined".
*/
public function getRoleHandler( $role ) {
if ( !isset( $this->handlers[$role] ) ) {
if ( !$this->isDefinedRole( $role ) ) {
if ( $this->isKnownRole( $role ) ) {
// The role has no handler defined, but is represented in the database.
// This may happen e.g. when the extension that defined the role was uninstalled.
wfWarn( __METHOD__ . ": known but undefined slot role $role" );
$this->handlers[$role] = new FallbackSlotRoleHandler( $role );
} else {
// The role doesn't have a handler defined, and is not represented in
// the database. Something must be quite wrong.
throw new InvalidArgumentException( "Unknown role $role" );
}
} else {
$handler = call_user_func( $this->instantiators[$role], $role );
Assert::postcondition(
$handler instanceof SlotRoleHandler,
"Instantiator for $role role must return a SlotRoleHandler"
);
$this->handlers[$role] = $handler;
}
}
return $this->handlers[$role];
}
/**
* Returns the list of roles allowed when creating a new revision on the given page.
* The choice should not depend on external state, such as the page content.
* Note that existing revisions of that page are not guaranteed to comply with this list.
*
* All implementations of this method are required to return at least all "required" roles.
*
* @param LinkTarget $title
*
* @return string[]
*/
public function getAllowedRoles( LinkTarget $title ) {
// TODO: allow this to be overwritten per namespace (or page type)
// TODO: decide how to control which slots are offered for editing per default (T209927)
return $this->getDefinedRoles();
}
/**
* Returns the list of roles required when creating a new revision on the given page.
* The should not depend on external state, such as the page content.
* Note that existing revisions of that page are not guaranteed to comply with this list.
*
* All required roles are implicitly considered "allowed", so any roles
* returned by this method will also be returned by getAllowedRoles().
*
* @param LinkTarget $title
*
* @return string[]
*/
public function getRequiredRoles( LinkTarget $title ) {
// TODO: allow this to be overwritten per namespace (or page type)
return [ 'main' ];
}
/**
* Returns the list of roles defined by calling defineRole().
*
* This list should be used when enumerating slot roles that can be used for editing.
*
* @return string[]
*/
public function getDefinedRoles() {
return array_keys( $this->instantiators );
}
/**
* Returns the list of known roles, including the ones returned by getDefinedRoles(),
* and roles that exist according to the NameTableStore provided to the constructor.
*
* This list should be used when enumerating slot roles that can be used in queries or
* for display.
*
* @return string[]
*/
public function getKnownRoles() {
return array_unique( array_merge(
$this->getDefinedRoles(),
$this->roleNamesStore->getMap()
) );
}
/**
* Whether the given role is defined, that is, it was defined by calling defineRole().
*
* @param string $role
* @return bool
*/
public function isDefinedRole( $role ) {
return in_array( $role, $this->getDefinedRoles(), true );
}
/**
* Whether the given role is known, that is, it's either defined or exist according to
* the NameTableStore provided to the constructor.
*
* @param string $role
* @return bool
*/
public function isKnownRole( $role ) {
return in_array( $role, $this->getKnownRoles(), true );
}
}