| Current File : /home/jvzmxxx/wiki1/extensions/Flow/includes/Block/Block.php |
<?php
namespace Flow\Block;
use Flow\Container;
use Flow\Data\ManagerGroup;
use Flow\Exception\InvalidInputException;
use Flow\FlowActions;
use Flow\Model\AbstractRevision;
use Flow\Model\UUID;
use Flow\Model\Workflow;
use Flow\RevisionActionPermissions;
use Flow\SpamFilter\Controller as SpamFilterController;
use IContextSource;
interface Block {
/**
* @param IContextSource $context
* @param string $action
*/
function init( IContextSource $context, $action );
/**
* Perform validation of data model
*
* @param array $data
* @return boolean True if data model is valid
*/
function onSubmit( array $data );
/**
* Write updates to storage
*/
function commit();
/**
* Render the API output of this Block.
* Templating is provided for convenience
*
* @param array $options
* @return array
*/
function renderApi( array $options );
/**
* @return string Unique name among all blocks on an object
*/
function getName();
/**
* @return UUID
*/
function getWorkflowId();
/**
* Returns an array of all error types encountered in this block. The values
* in the returned array can be used to pass to getErrorMessage() or
* getErrorExtra() to respectively fetch the specific error message or
* additional details.
*
* @return array
*/
function getErrors();
/**
* Checks if any errors have occurred in the block (no argument), or if a
* specific error has occurred (argument being the error type)
*
* @param string[optional] $type
* @return bool
*/
function hasErrors( $type = null );
/**
* Returns true if the block can render the requested action, or false
* otherwise.
*
* @param string $action
* @return bool
*/
public function canRender( $action );
}
abstract class AbstractBlock implements Block {
/** @var Workflow */
protected $workflow;
/** @var ManagerGroup */
protected $storage;
/** @var IContextSource */
protected $context;
/** @var array|null */
protected $submitted = null;
/** @var array */
protected $errors = array();
/**
* @var string|null The commitable action being submitted, or null
* for read-only actions.
*/
protected $action;
/** @var RevisionActionPermissions */
protected $permissions;
/**
* A list of supported post actions
* @var array
*/
protected $supportedPostActions = array();
/**
* A list of supported get actions
* @var array
*/
protected $supportedGetActions = array();
/**
* Templates for each view actions
* @var array
*/
protected $templates = array();
public function __construct( Workflow $workflow, ManagerGroup $storage ) {
$this->workflow = $workflow;
$this->storage = $storage;
}
/**
* Called by $this->onSubmit to populate $this->errors based
* on $this->action and $this->submitted.
*/
abstract protected function validate();
/**
* {@inheritDoc}
*/
abstract public function commit();
/**
* @var IContextSource $context
* @var string $action
*/
public function init( IContextSource $context, $action ) {
$this->context = $context;
$this->action = $action;
$this->permissions = new RevisionActionPermissions( Container::get( 'flow_actions' ), $context->getUser() );
}
/**
* @return IContextSource
*/
public function getContext() {
return $this->context;
}
/**
* Returns true if the block can submit the requested action, or false
* otherwise.
*
* @param string $action
* @return bool
*/
public function canSubmit( $action ) {
return in_array( $this->getActionName( $action ), $this->supportedPostActions );
}
/**
* Returns true if the block can render the requested action, or false
* otherwise.
*
* @param string $action
* @return bool
*/
public function canRender( $action ) {
return
// GET actions can be rendered
in_array( $this->getActionName( $action ), $this->supportedGetActions ) ||
// POST actions are usually redirected to 'view' after successfully
// completing the request, but can also be rendered (e.g. to show
// error message after unsuccessful submission)
$this->canSubmit( $action );
}
/**
* Get the template name for a specific action or an array of template
* for all possible view actions in this block
*
* @param string|null
* @return string|array
* @throws InvalidInputException
*/
public function getTemplate( $action = null ) {
if ( $action === null ) {
return $this->templates;
}
if ( !isset( $this->templates[$action] ) ) {
throw new InvalidInputException( 'Template is not defined for action: ' . $action, 'invalid-input' );
}
return $this->templates[$action];
}
/**
* @param array $data
* @return bool|null true when accepted, false when not accepted.
* null when this action does not support submission.
*/
public function onSubmit( array $data ) {
if ( !$this->canSubmit( $this->action ) ) {
return null;
}
$this->submitted = $data;
$this->validate();
return !$this->hasErrors();
}
public function wasSubmitted() {
return $this->submitted !== null;
}
/**
* Checks if any errors have occurred in the block (no argument), or if a
* specific error has occurred (argument being the error type)
*
* @param string[optional] $type
* @return bool
*/
public function hasErrors( $type = null ) {
if ( $type === null ) {
return (bool) $this->errors;
}
return isset( $this->errors[$type] );
}
/**
* Returns an array of all error types encountered in this block. The values
* in the returned array can be used to pass to getErrorMessage() or
* getErrorExtra() to respectively fetch the specific error message or
* additional details.
*
* @return array
*/
public function getErrors() {
return array_keys( $this->errors );
}
/**
* @param $type
* @return \Message
*/
public function getErrorMessage( $type ) {
return isset( $this->errors[$type]['message'] ) ? $this->errors[$type]['message'] : null;
}
/**
* @param $type
* @return mixed
*/
public function getErrorExtra( $type ) {
return isset( $this->errors[$type]['extra'] ) ? $this->errors[$type]['extra'] : null;
}
/**
* @param string $type
* @param \Message $message
* @param mixed[optional] $extra
*/
public function addError( $type, \Message $message, $extra = null ) {
$this->errors[$type] = array(
'message' => $message,
'extra' => $extra,
);
}
public function getWorkflow() {
return $this->workflow;
}
public function getWorkflowId() {
return $this->workflow->getId();
}
public function getStorage() {
return $this->storage;
}
/**
* Given a certain action name, this returns the valid action name. This is
* meant for BC compatibility with renamed actions.
*
* @param string $action
* @return string
*/
public function getActionName( $action ) {
// BC for renamed actions
/** @var FlowActions $actions */
$actions = Container::get( 'flow_actions' );
$alias = $actions->getValue( $action );
if ( is_string( $alias ) ) {
// All proper actions return arrays, but aliases return a string
$action = $alias;
}
return $action;
}
/**
* Run through AbuseFilter and friends.
* @todo Having to call spamFilter in each place that creates a revision
* is error-prone.
*
* @param AbstractRevision|null $old null when $new is first revision
* @param AbstractRevision $new
* @return boolean True when content is allowed by spam filter
*/
protected function checkSpamFilters( AbstractRevision $old = null, AbstractRevision $new ) {
/** @var SpamFilterController $spamFilter */
$spamFilter = Container::get( 'controller.spamfilter' );
$status = $spamFilter->validate( $this->context, $new, $old, $this->workflow->getArticleTitle() );
if ( $status->isOK() ) {
return true;
}
$message = $status->getMessage();
$details = $status->getValue();
$this->addError( 'spamfilter', $message, array(
'messageKey' => $message->getKey(),
'details' => $details,
) );
return false;
}
/**
* @return string The new edit token
*/
public function getEditToken() {
return $this->context->getUser()->getEditToken();
}
/**
* @param \OutputPage $out
*/
public function setPageTitle( \OutputPage $out ) {
if ( $out->getPageTitle() ) {
// Don't override page title if another block has already set it.
// If this should *really* be done, the specific block extending
// this AbstractBlock should just implement this itself ;)
return;
}
$out->setPageTitle( $this->workflow->getArticleTitle()->getFullText() );
}
}