Current File : /home/jvzmxxx/wiki1/extensions/Wikibase/client/includes/RecentChanges/ExternalChangeFactory.php
<?php

namespace Wikibase\Client\RecentChanges;

use InvalidArgumentException;
use Language;
use RecentChange;
use UnexpectedValueException;
use Wikibase\DataModel\Entity\ItemId;

/**
 * @since 0.5
 *
 * @license GPL-2.0+
 * @author Katie Filbert < aude.wiki@gmail.com >
 * @author Daniel Kinzler
 */
class ExternalChangeFactory {

	/**
	 * @var string
	 */
	private $repoSiteId;

	/**
	 * @var Language
	 */
	private $summaryLanguage;

	/**
	 * @param string $repoSiteId
	 * @param Language $summaryLanguage Language to use when generating edit summaries
	 */
	public function __construct( $repoSiteId, Language $summaryLanguage ) {
		$this->repoSiteId = $repoSiteId;
		$this->summaryLanguage = $summaryLanguage;
	}

	/**
	 * @since 0.5
	 *
	 * @param RecentChange $recentChange
	 *
	 * @throws UnexpectedValueException
	 * @return ExternalChange
	 */
	public function newFromRecentChange( RecentChange $recentChange ) {
		$rc_params = $recentChange->parseParams();

		if ( !is_array( $rc_params ) || !array_key_exists( 'wikibase-repo-change', $rc_params ) ) {
			throw new UnexpectedValueException( 'Not a Wikibase change' );
		}

		$changeParams = $this->extractChangeData( $rc_params );

		// If a pre-formatted comment exists, pass it on.
		$changeHtml = isset( $rc_params['comment-html'] ) ? $rc_params['comment-html'] : null;

		$itemId = $this->extractItemId( $changeParams['object_id'] );
		$changeType = $this->extractChangeType( $changeParams['type'] );
		$rev = $this->newRevisionData( $recentChange, $changeParams, $changeHtml );

		return new ExternalChange( $itemId, $rev, $changeType );
	}

	/**
	 * @param RecentChange $recentChange
	 * @param array $changeParams
	 * @param string|null $commentHtml Pre-formatted comment HTML
	 *
	 * @return RevisionData
	 */
	private function newRevisionData( RecentChange $recentChange, array $changeParams, $commentHtml = null ) {
		$repoId = isset( $changeParams['site_id'] )
			? $changeParams['site_id'] : $this->repoSiteId;

		$comment = $recentChange->getAttribute( 'rc_comment' );

		if ( $comment === '' || $comment === null ) {
			$comment = $this->generateComment( $changeParams );
		}

		return new RevisionData(
			$recentChange->getAttribute( 'rc_user_text' ),
			$recentChange->getAttribute( 'rc_timestamp' ),
			$comment,
			$commentHtml,
			$repoId,
			$changeParams
		);
	}

	/**
	 * @param array $rc_params
	 *
	 * @throws UnexpectedValueException
	 * @return array
	 */
	private function extractChangeData( array $rc_params ) {
		$changeParams = $rc_params['wikibase-repo-change'];

		$this->validateChangeData( $changeParams );

		return $changeParams;
	}

	/**
	 * @param mixed $changeParams
	 *
	 * @throws UnexpectedValueException
	 * @return bool
	 */
	private function validateChangeData( $changeParams ) {
		if ( !is_array( $changeParams ) ) {
			throw new UnexpectedValueException( 'Invalid Wikibase change' );
		}

		$keys = array( 'type', 'page_id', 'rev_id', 'parent_id', 'object_id' );

		foreach ( $keys as $key ) {
			if ( !array_key_exists( $key, $changeParams ) ) {
				throw new UnexpectedValueException( "$key key missing in change data" );
			}
		}

		return true;
	}

	/**
	 * @see EntityChange::getAction
	 *
	 * @param string $type
	 *
	 * @throws UnexpectedValueException
	 * @return string
	 */
	private function extractChangeType( $type ) {
		if ( !is_string( $type ) ) {
			throw new UnexpectedValueException( '$type must be a string.' );
		}

		list( , $changeType ) = explode( '~', $type, 2 );

		return $changeType;
	}

	/**
	 * @param string $prefixedId
	 *
	 * @throws UnexpectedValueException
	 * @return ItemId
	 */
	private function extractItemId( $prefixedId ) {
		try {
			return new ItemId( $prefixedId );
		} catch ( InvalidArgumentException $ex ) {
			throw new UnexpectedValueException( 'Invalid $itemId found for change.' );
		}
	}

	/**
	 * This method transforms the comments field into rc_params into an appropriate
	 * comment value for ExternalChange.
	 *
	 * $comment can be a string or an array with some additional data.
	 *
	 * String comments are either 'wikibase-comment-update' (legacy) or have
	 * comments from the repo, such as '/ wbsetclaim-update:2||1 / [[Property:P213]]: [[Q850]]'.
	 *
	 * We don't yet parse repo comments in the client, so for now, we use the
	 * generic 'wikibase-comment-update' for these.
	 *
	 * Comment arrays may contain a message key that provide autocomments for stuff
	 * like log actions (item deletion) or edits that have no meaningful summary
	 * to use in the client.
	 *
	 *  - 'wikibase-comment-unlinked' (when the sitelink to the given page is removed on the repo)
	 *  - 'wikibase-comment-add' (when the item is created, with sitelink to the given page)
	 *  - 'wikibase-comment-remove' (when the item is deleted, the page becomes unconnected)
	 *  - 'wikibase-comment-restore' (when the item is undeleted and reconnected to the page)
	 *  - 'wikibase-comment-sitelink-add' (and other sitelink messages, unused)
	 *  - 'wikibase-comment-update' (legacy, generic, item updated commment)
	 *
	 * @param array|string $comment
	 * @param string $type
	 *
	 * @return string
	 */
	private function parseAutoComment( $comment, $type ) {
		$newComment = array(
			'key' => 'wikibase-comment-update'
		);

		if ( is_array( $comment ) ) {
			if ( $type === 'wikibase-item~add' ) {
				// @todo: provide a link to the entity
				$newComment['key'] = 'wikibase-comment-linked';
			} elseif ( array_key_exists( 'sitelink', $comment ) ) {
				// @fixme site link change message
				$newComment['key'] = 'wikibase-comment-update';
			} else {
				$newComment['key'] = $comment['message'];
			}
		}

		return $newComment;
	}

	/**
	 * @param array $comment
	 *
	 * @return string
	 */
	private function formatComment( array $comment ) {
		$commentMsg = wfMessage( $comment['key'] )->inLanguage( $this->summaryLanguage );

		if ( isset( $comment['numparams'] ) ) {
			$commentMsg->numParams( $comment['numparams'] );
		}

		return $commentMsg->text();
	}

	/**
	 * @param array $changeParams
	 *
	 * @return string
	 */
	private function generateComment( array $changeParams ) {
		// NOTE: We want to get rid of the comment and composite-comment fields in $changeParams
		// in the future, see https://phabricator.wikimedia.org/T101836#1414639 part 3.
		if ( array_key_exists( 'composite-comment', $changeParams ) ) {
			$comment['key'] = 'wikibase-comment-multi';
			$comment['numparams'] = $this->countCompositeComments( $changeParams['composite-comment'] );

			return $this->formatComment( $comment );
		} elseif ( array_key_exists( 'comment', $changeParams ) ) {
			$comment = $this->parseAutoComment( $changeParams['comment'], $changeParams['type'] );

			return $this->formatComment( $comment );
		} else {
			// no override
			return false;
		}
	}

	/**
	 * normalizes for extra empty comment in rc_params (see bug T47812)
	 *
	 * @param array $comments
	 *
	 * @return int
	 */
	private function countCompositeComments( array $comments ) {
		$compositeComments = array_filter( $comments );

		return count( $compositeComments );
	}

}