Current File : /home/jvzmxxx/wiki1/extensions/Flow/includes/SubmissionHandler.php
<?php

namespace Flow;

use DeferredUpdates;
use Flow\Block\AbstractBlock;
use Flow\Block\Block;
use Flow\Data\BufferedCache;
use Flow\Data\ManagerGroup;
use Flow\Exception\FailCommitException;
use Flow\Exception\InvalidDataException;
use Flow\Exception\InvalidActionException;
use Flow\Model\Workflow;
use IContextSource;
use SplQueue;

class SubmissionHandler {

	/**
	 * @var ManagerGroup $storage
	 */
	protected $storage;

	/**
	 * @var DbFactory $dbFactory
	 */
	protected $dbFactory;

	/**
	 * @var BufferedCache $bufferedCache
	 */
	protected $bufferedCache;

	/**
	 * @var SplQueue Updates to add to DeferredUpdates post-commit
	 */
	protected $deferredQueue;

	public function __construct(
		ManagerGroup $storage,
		DbFactory $dbFactory,
		BufferedCache $bufferedCache,
		SplQueue $deferredQueue
	) {
		$this->storage = $storage;
		$this->dbFactory = $dbFactory;
		$this->bufferedCache = $bufferedCache;
		$this->deferredQueue = $deferredQueue;
	}

	/**
	 * @param Workflow $workflow
	 * @param IContextSource $context
	 * @param AbstractBlock[] $blocks
	 * @param string $action
	 * @param array $parameters
	 * @return AbstractBlock[]
	 * @throws InvalidActionException
	 * @throws InvalidDataException
	 */
	public function handleSubmit(
		Workflow $workflow,
		IContextSource $context,
		array $blocks,
		$action,
		array $parameters
	) {
		// since this is a submit force dbFactory to always return master
		$this->dbFactory->forceMaster();

		/** @var Block[] $interestedBlocks */
		$interestedBlocks = array();
		foreach ( $blocks as $block ) {
			// This is just a check whether the block understands the action,
			// Doesn't consider permissions
			if ( $block->canSubmit( $action ) ) {
				$block->init( $context, $action );
				$interestedBlocks[] = $block;
			}
		}

		if ( !$interestedBlocks ) {
			if ( !$blocks ) {
				throw new InvalidDataException( 'No Blocks?!?', 'fail-load-data' );
			}
			$type = array();
			foreach ( $blocks as $block ) {
				$type[] = get_class( $block );
			}
			// All blocks returned null, nothing knows how to handle this action
			throw new InvalidActionException( "No block accepted the '$action' action: " .  implode( ',', array_unique( $type ) ), 'invalid-action' );
		}

		// Check mediawiki core permissions for title protection, blocked
		// status, etc.
		$errors = $workflow->getPermissionErrors( 'edit', $context->getUser(), 'secure' );
		if ( count( $errors ) ) {
			foreach ( $errors as $errorMsgArgs ) {
				$msg = wfMessage( array_shift( $errorMsgArgs ) );
				if ( $errorMsgArgs ) {
					$msg->params( $errorMsgArgs );
				}
				// I guess this is the "user block" meaning of 'block'.  If
				// so, this is misleading, since it could be protection,
				// etc.  The specific error message (protect, block, etc.)
				// will still be output, though.
				//
				// In theory, something could be relying on the string 'block',
				// since it's exposed to the API, but probably not.
				reset( $interestedBlocks )->addError( 'block', $msg );
			}
			return array();
		}

		$success = true;
		foreach ( $interestedBlocks as $block ) {
			$name = $block->getName();
			$data = isset( $parameters[$name] ) ? $parameters[$name] : array();
			$success &= $block->onSubmit( $data );
		}

		return $success ? $interestedBlocks : array();
	}

	/**
	 * @param Workflow $workflow
	 * @param AbstractBlock[] $blocks
	 * @return array Map from committed block name to an array of metadata returned
	 *  about inserted objects.  This must be non-empty.  An empty block array
	 *  indicates there were errors, in which case this method should not be called.
	 * @throws \Exception
	 */
	public function commit( Workflow $workflow, array $blocks ) {
		$cache = $this->bufferedCache;
		$dbw = $this->dbFactory->getDB( DB_MASTER );

		/** @var OccupationController $occupationController */
		$occupationController = Container::get( 'occupation_controller' );
		$title = $workflow->getOwnerTitle();

		if ( count( $blocks ) === 0 ) {
			// This is a logic error in the code, but we need to preserve
			// consistent state.
			throw new FailCommitException(
				__METHOD__ . ' was called with $blocks set to an empty ' .
				'array or a falsy value.  This indicates the blocks are ' .
				'not able to commit, so ' . __METHOD__ . ' should not be ' .
				'called.',
				'fail-commit'
			);
		}

		try {
			$dbw->startAtomic( __METHOD__ );
			$cache->begin();
			// Create the occupation page/revision if needed
			$occupationController->ensureFlowRevision( new \Article( $title ), $workflow );
			// Create/modify each Flow block as requested
			$results = array();
			foreach ( $blocks as $block ) {
				$results[$block->getName()] = $block->commit();
			}
			$dbw->endAtomic( __METHOD__ );
			$dbw->onTransactionIdle( function () use ( $cache ) {
				// Now commit to cache. If this fails, cache keys should have been
				// invalidated, but still log the failure.
				if ( !$cache->commit() ) {
					wfDebugLog( 'Flow', __METHOD__ .
						': Committed to database but failed applying to cache' );
				}
			} );
		} catch ( \Exception $e ) {
			while ( !$this->deferredQueue->isEmpty() ) {
				$this->deferredQueue->dequeue();
			}
			$dbw->rollback( __METHOD__ );
			$cache->rollback();
			throw $e;
		}

		while ( !$this->deferredQueue->isEmpty() ) {
			DeferredUpdates::addCallableUpdate( $this->deferredQueue->dequeue() );
		}

		$workflow->getArticleTitle()->purgeSquid();

		return $results;
	}
}