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

namespace Flow\Formatter;

use Flow\FlowActions;
use Flow\Data\ManagerGroup;
use Flow\Model\AbstractRevision;
use Flow\Model\UUID;
use Flow\Repository\TreeRepository;

abstract class HistoryQuery extends AbstractQuery {
	// This requests extra to take into account that we will filter some out,
	// to try to reduce the number of rounds (preferably to 1).
	// If you raise this, also increase history_index_limit and bump the
	// key of the indexes using history_index_limit
	//
	// This magic number is based on new-post/new-topic being about 26% of post revisions.
	// (queried from production), since that is the only thing currently excluded.
	const POST_OVERFETCH_FACTOR = 1.36;

	/**
	 * @var FlowActions
	 */
	protected $actions;

	/**
	 * @param ManagerGroup $storage
	 * @param TreeRepository $treeRepo
	 * @param FlowActions $actions
	 */
	public function __construct(
		ManagerGroup $storage,
		TreeRepository $treeRepo,
		FlowActions $actions )
	{
		parent::__construct( $storage, $treeRepo );
		$this->actions = $actions;
	}

	/**
	 * @param AbstractRevision $revision
	 * @return bool
	 */
	protected function includeInHistory( AbstractRevision $revision ) {
		// If you add exclude_from_history to a new type, use doInternalQueries on additional
		// queries as needed.
		return !$this->actions->getValue( $revision->getChangeType(), 'exclude_from_history' );
	}

	/**
	 * Gets query options that are common to all history queries
	 *
	 * @param string $direction 'fwd' or 'rev'.  'fwd' means to get items older than
	 *  the offset.  'rev' means to get items newer.  Either way, an individual page is
	 *  eventually returned and displayed in descending order.
	 * @param int $limit Maximum number of items
	 * @param UUID $offset UUID to use as offset (optional)
	 * @return array Associative array of options for query
	 */
	protected function getOptions( $direction, $limit, UUID $offset = null) {
		return array(
			'sort' => 'rev_id',
			'order' => $direction === 'fwd' ? 'DESC' : 'ASC',
			'limit' => $limit,
			'offset-id' => $offset,
			'offset-dir' => $direction,
			'offset-include' => false,
		);
	}

	/**
	 * Internally re-query as needed to handle items excluded from history
	 *
	 * Re-queries until there are no more entries or after filtering, there are the
	 * desired number of results.
	 *
	 * This respects the given order (ASC or DESC), but the reversing for 'rev' is in
	 * getResults.
	 *
	 * @param string $storageClass Storage class ID
	 * @param array $attributes Query attriutes
	 * @param array $options Query options, including offset-id and limit
	 * @param int $overfetchFactor Factor to overfetch by to anticipate excludes
	 * @return array() Array of history rows
	 */
	protected function doInternalQueries( $storageClass, $attributes, $options, $overfetchFactor ) {
		$result = array();

		$limit = $options['limit'];
		$internalOffset = $options['offset-id'];

		do {
			$remainingNeeded = $limit - count( $result );

			// The special cases here are to try reduce dribbling out of final requests (50, 25, 10, 5...).
			if ( $remainingNeeded < 50 ) {
				$overfetchFactor *= 2;
			}

			$beforeFilteringCountWanted = max( 10, intval( $overfetchFactor * $remainingNeeded ) );

			// Over-fetch by 1 item so we can figure out when to stop re-querying.
			$options['limit'] = $beforeFilteringCountWanted + 1;

			$options['offset-id'] = $internalOffset;

			$resultBeforeFiltering = $this->storage->find( $storageClass, $attributes, $options );

			// We over-fetched, now get rid of redundant value for our "real" data
			$internalOverfetched = null;
			if ( count( $resultBeforeFiltering ) > $beforeFilteringCountWanted ) {
				$internalOverfetched = array_pop( $resultBeforeFiltering );
			}

			$resultAfterFiltering = array_filter( $resultBeforeFiltering, array( $this, 'includeInHistory' ) );

			if ( count( $resultBeforeFiltering ) >= 1 ) {
				$internalOffset = end( $resultBeforeFiltering )->getRevisionId();
			}

			$trimmedResultAfterFiltering = array_slice( $resultAfterFiltering, 0, $remainingNeeded );
			$result = array_merge( $result, $trimmedResultAfterFiltering );
		} while( count( $result ) < $limit && $internalOverfetched !== null );

		return $result;
	}

}