wikimedia/mediawiki-extensions-Wikibase

View on GitHub
repo/includes/ChangeOp/ChangeOpAliases.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace Wikibase\Repo\ChangeOp;

use InvalidArgumentException;
use ValueValidators\Result;
use Wikibase\DataModel\Entity\EntityDocument;
use Wikibase\DataModel\Term\AliasesProvider;
use Wikibase\DataModel\Term\AliasGroupList;
use Wikibase\Lib\Summary;
use Wikibase\Repo\Store\EntityPermissionChecker;
use Wikibase\Repo\Validators\TermValidatorFactory;

/**
 * Class for aliases change operation
 *
 * @license GPL-2.0-or-later
 * @author Tobias Gritschacher < tobias.gritschacher@wikimedia.de >
 * @author Daniel Kinzler
 */
class ChangeOpAliases extends ChangeOpBase {

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

    /**
     * @var string[]
     */
    private $aliases;

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

    /**
     * @var TermValidatorFactory
     */
    private $termValidatorFactory;

    /**
     * @param string $languageCode
     * @param string[] $aliases
     * @param string $action should be set|add|remove
     * @param TermValidatorFactory $termValidatorFactory
     *
     * @throws InvalidArgumentException
     */
    public function __construct(
        $languageCode,
        array $aliases,
        $action,
        TermValidatorFactory $termValidatorFactory
    ) {
        if ( !is_string( $languageCode ) ) {
            throw new InvalidArgumentException( 'Language code needs to be a string.' );
        }

        if ( !is_string( $action ) ) {
            throw new InvalidArgumentException( 'Action needs to be a string.' );
        }

        $this->languageCode = $languageCode;
        $this->aliases = $aliases;
        $this->action = $action;
        $this->termValidatorFactory = $termValidatorFactory;
    }

    /**
     * Applies the change to the aliases
     *
     * @param AliasGroupList $aliases
     *
     * @throws ChangeOpException
     */
    private function updateAliases( AliasGroupList $aliases ) {
        if ( $aliases->hasGroupForLanguage( $this->languageCode ) ) {
            $oldAliases = $aliases->getByLanguage( $this->languageCode )->getAliases();
        } else {
            $oldAliases = [];
        }

        if ( $this->action === 'set' || $this->action === '' ) {
            $newAliases = $this->aliases;
        } elseif ( $this->action === 'add' ) {
            $newAliases = array_merge( $oldAliases, $this->aliases );
        } elseif ( $this->action === 'remove' ) {
            $newAliases = array_diff( $oldAliases, $this->aliases );
        } else {
            throw new ChangeOpException( 'Bad action: ' . $this->action );
        }

        $aliases->setAliasesForLanguage( $this->languageCode, $newAliases );
    }

    /** @inheritDoc */
    public function apply( EntityDocument $entity, Summary $summary = null ) {
        if ( !( $entity instanceof AliasesProvider ) ) {
            throw new InvalidArgumentException( '$entity must be a AliasesProvider' );
        }

        $aliases = $entity->getAliasGroups();
        if ( $aliases->hasGroupForLanguage( $this->languageCode ) ) {
            $oldAliases = $aliases->getByLanguage( $this->languageCode )->getAliases();
        } else {
            $oldAliases = [];
        }

        $this->updateSummary( $summary, $this->action, $this->languageCode, $this->aliases );

        $this->updateAliases( $entity->getAliasGroups() );

        if ( $aliases->hasGroupForLanguage( $this->languageCode ) ) {
            $newAliases = $aliases->getByLanguage( $this->languageCode )->getAliases();
        } else {
            $newAliases = [];
        }

        return new ChangeOpAliasesResult(
            $entity->getId(),
            $this->languageCode,
            $oldAliases,
            $newAliases,
            $oldAliases !== $newAliases
        );
    }

    /**
     * @see ChangeOp::validate
     *
     * @param EntityDocument $entity
     *
     * @throws ChangeOpException
     * @return Result
     */
    public function validate( EntityDocument $entity ) {
        $languageValidator = $this->termValidatorFactory->getAliasLanguageValidator();
        $termValidator = $this->termValidatorFactory->getAliasValidator();

        // check that the language is valid
        $result = $languageValidator->validate( $this->languageCode );

        if ( !$result->isValid() ) {
            return $result;
        }

        // It should be possible to remove invalid aliases, but not to add/set new invalid ones
        if ( $this->action === 'set' || $this->action === '' || $this->action === 'add' ) {
            // Check that the new aliases are valid
            foreach ( $this->aliases as $alias ) {
                $result = $termValidator->validate( $alias );

                if ( !$result->isValid() ) {
                    return $result;
                }
            }
        } elseif ( $this->action !== 'remove' ) {
            throw new ChangeOpException( 'Bad action: ' . $this->action );
        }

        //XXX: Do we want to check the updated fingerprint, as we do for labels and descriptions?
        return $result;
    }

    /**
     * @see ChangeOp::getActions
     *
     * @return string[]
     */
    public function getActions() {
        return [ EntityPermissionChecker::ACTION_EDIT_TERMS ];
    }

}