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 ); } }