Current File : /home/jvzmxxx/wiki1/extensions/Wikibase/repo/includes/Store/Sql/EntityPerPageBuilder.php
<?php

namespace Wikibase\Repo\Store\SQL;

use ResultWrapper;
use Wikibase\DataModel\Entity\EntityId;
use Wikibase\DataModel\Entity\EntityIdParser;
use Wikibase\DataModel\Entity\EntityIdParsingException;
use Wikibase\Lib\Reporting\MessageReporter;
use Wikibase\Repo\EntityNamespaceLookup;
use Wikibase\Repo\Store\EntityPerPage;

/**
 * Utility class for rebuilding the wb_entity_per_page table.
 *
 * @since 0.4
 *
 * @license GPL-2.0+
 * @author Katie Filbert < aude.wiki@gmail.com >
 */
class EntityPerPageBuilder {

	/**
	 * @var EntityPerPage
	 */
	private $entityPerPageTable;

	/**
	 * @var EntityIdParser
	 */
	private $entityIdParser;

	/**
	 * @var MessageReporter
	 */
	private $reporter;

	/**
	 * The batch size, giving the number of rows to be updated in each database transaction.
	 *
	 * @var int
	 */
	private $batchSize = 100;

	/**
	 * Rebuild the entire table
	 *
	 * @var bool
	 */
	private $rebuildAll = false;

	/**
	 * @var EntityNamespaceLookup
	 */
	private $entityNamespaceLookup;

	/**
	 * @var array
	 */
	private $contentModels;

	/**
	 * @param EntityPerPage $entityPerPageTable
	 * @param EntityIdParser $entityIdParser
	 * @param EntityNamespaceLookup $entityNamespaceLookup
	 * @param array $contentModels
	 */
	public function __construct(
		EntityPerPage $entityPerPageTable,
		EntityIdParser $entityIdParser,
		EntityNamespaceLookup $entityNamespaceLookup,
		array $contentModels
	) {
		$this->entityPerPageTable = $entityPerPageTable;
		$this->entityIdParser = $entityIdParser;
		$this->contentModels = $contentModels;
		$this->entityNamespaceLookup = $entityNamespaceLookup;
		$this->contentModels = $contentModels;
	}

	/**
	 * @param int $batchSize
	 */
	public function setBatchSize( $batchSize ) {
		$this->batchSize = $batchSize;
	}

	/**
	 * @since 0.4
	 *
	 * @param bool $rebuildAll
	 */
	public function setRebuildAll( $rebuildAll ) {
		$this->rebuildAll = $rebuildAll;
	}

	/**
	 * Sets the reporter to use for reporting preogress.
	 *
	 * @param MessageReporter $reporter
	 */
	public function setReporter( MessageReporter $reporter ) {
		$this->reporter = $reporter;
	}

	/**
	 * @since 0.4
	 */
	public function rebuild() {
		$dbw = wfGetDB( DB_MASTER );

		$lastPageSeen = 0;
		$numPages = 1;

		$this->report( 'Start rebuild...' );

		while ( $numPages > 0 ) {
			wfWaitForSlaves();

			$pages = $dbw->select(
				array( 'page', 'redirect', 'wb_entity_per_page' ),
				array( 'page_title', 'page_id', 'rd_title' ),
				$this->getQueryConds( $lastPageSeen ),
				__METHOD__,
				array( 'LIMIT' => $this->batchSize, 'ORDER BY' => 'page_id' ),
				array(
					'redirect' => array( 'LEFT JOIN', 'rd_from = page_id' ),
					'wb_entity_per_page' => array( 'LEFT JOIN', 'page_id = epp_page_id' )
				)
			);

			$numPages = $pages->numRows();

			if ( $numPages > 0 ) {
				$lastPageSeen = $this->rebuildPages( $pages );

				$this->report( "Processed $numPages pages up to $lastPageSeen." );
			}
		}

		$this->report( "Rebuild done." );

		return true;
	}

	/**
	 * Construct query conditions
	 *
	 * @since 0.4
	 *
	 * @param int $lastPageSeen
	 *
	 * @return array
	 */
	protected function getQueryConds( $lastPageSeen ) {
		global $wgContentHandlerUseDB;

		$conds = array(
			'page_namespace' => $this->entityNamespaceLookup->getEntityNamespaces(),
			'page_id > ' . (int) $lastPageSeen,
		);

		if ( $wgContentHandlerUseDB ) {
			$conds['page_content_model'] = $this->contentModels;
		}

		if ( $this->rebuildAll === false ) {
			$conds[] = 'epp_page_id IS NULL';
		}

		return $conds;
	}

	/**
	 * @param string $idString
	 *
	 * @return EntityId|null
	 */
	private function tryParseId( $idString ) {
		try {
			return $this->entityIdParser->parse( $idString );
		} catch ( EntityIdParsingException $e ) {
			wfDebugLog( __CLASS__, 'Invalid entity id ' . $idString );
		}

		return null;
	}

	/**
	 * Rebuilds EntityPerPageTable for specified pages
	 *
	 * @since 0.4
	 *
	 * @param ResultWrapper $pages
	 *
	 * @return int
	 */
	protected function rebuildPages( $pages ) {
		$lastPageSeen = 0;

		foreach ( $pages as $pageRow ) {
			$this->updateEntry( $pageRow );

			$lastPageSeen = $pageRow->page_id;
		}

		return $lastPageSeen;
	}

	/**
	 * @param object $pageRow
	 */
	private function updateEntry( $pageRow ) {
		// Derive the entity id from the page title
		$entityId = $this->tryParseId( $pageRow->page_title );

		if ( !$entityId ) {
			return;
		}

		// Derive the target id from the redirect target title
		$targetId = $pageRow->rd_title === null ? null : $this->tryParseId( $pageRow->rd_title );

		if ( $this->rebuildAll === true ) {
			$this->entityPerPageTable->deleteEntity( $entityId );
		}

		$pageId = (int)$pageRow->page_id;

		if ( $targetId ) {
			$this->entityPerPageTable->addRedirectPage( $entityId, $pageId, $targetId );
		} else {
			$this->entityPerPageTable->addEntityPage( $entityId, $pageId );
		}
	}

	/**
	 * reports a message
	 *
	 * @since 0.4
	 *
	 * @param string $msg
	 */
	protected function report( $msg ) {
		if ( $this->reporter ) {
			$this->reporter->reportMessage( $msg );
		}
	}

}