wikimedia/mediawiki-extensions-Wikibase

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

Summary

Maintainability
D
1 day
Test Coverage
<?php

namespace Wikibase\Repo\ChangeOp;

use InvalidArgumentException;
use ValueValidators\Result;
use Wikibase\DataModel\Entity\EntityDocument;
use Wikibase\DataModel\Entity\EntityId;
use Wikibase\DataModel\Term\DescriptionsProvider;
use Wikibase\DataModel\Term\LabelsProvider;
use Wikibase\DataModel\Term\Term;
use Wikibase\DataModel\Term\TermList;
use Wikibase\Lib\Summary;
use Wikibase\Repo\Store\EntityPermissionChecker;
use Wikibase\Repo\Validators\TermValidatorFactory;

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

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

    /**
     * @var string|null
     */
    private $description;

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

    /**
     * @param string $languageCode
     * @param string|null $description
     * @param TermValidatorFactory $termValidatorFactory
     *
     * @throws InvalidArgumentException
     */
    public function __construct(
        $languageCode,
        $description,
        TermValidatorFactory $termValidatorFactory
    ) {
        if ( !is_string( $languageCode ) ) {
            throw new InvalidArgumentException( 'Language code needs to be a string.' );
        }

        $this->languageCode = $languageCode;
        $this->description = $description;
        $this->termValidatorFactory = $termValidatorFactory;
    }

    /**
     * Applies the change to the descriptions
     *
     * @param TermList $descriptions
     */
    private function updateDescriptions( TermList $descriptions ) {
        if ( $this->description === null ) {
            $descriptions->removeByLanguage( $this->languageCode );
        } else {
            $descriptions->setTextForLanguage( $this->languageCode, $this->description );
        }
    }

    /**
     * @param EntityId|null $entityId
     * @param Term|null $oldDescription
     * @param Term|null $newDescription
     * @return ChangeOpDescriptionResult
     */
    private function buildResult( EntityId $entityId = null, Term $oldDescription = null, Term $newDescription = null ) {

        $isEntityChanged = false;
        $oldDescriptionText = $oldDescription ? $oldDescription->getText() : '';
        $newDescriptionText = $newDescription ? $newDescription->getText() : '';

        if ( $newDescription ) {
            $isEntityChanged = !$newDescription->equals( $oldDescription );
        } elseif ( $oldDescription ) {
            // $newDescription is null, but $oldDescription is not so entity has changed for sure
            $isEntityChanged = true;
        }

        return new ChangeOpDescriptionResult( $entityId, $this->languageCode, $oldDescriptionText, $newDescriptionText, $isEntityChanged );
    }

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

        $descriptions = $entity->getDescriptions();

        if ( $descriptions->hasTermForLanguage( $this->languageCode ) ) {
            if ( $this->description === null ) {
                $removedDescription = $descriptions->getByLanguage( $this->languageCode )->getText();
                $this->updateSummary( $summary, 'remove', $this->languageCode, $removedDescription );
            } else {
                $this->updateSummary( $summary, 'set', $this->languageCode, $this->description );
            }

            $oldDescription = $descriptions->getByLanguage( $this->languageCode );
        } else {
            $oldDescription = null;
            $this->updateSummary( $summary, 'add', $this->languageCode, $this->description );
        }

        $this->updateDescriptions( $descriptions );

        if ( $descriptions->hasTermForLanguage( $this->languageCode ) ) {
            $newDescription = $descriptions->getByLanguage( $this->languageCode );
        } else {
            $newDescription = null;
        }

        return $this->buildResult( $entity->getId(), $oldDescription, $newDescription );
    }

    /**
     * @see ChangeOp::validate
     *
     * @param EntityDocument $entity
     *
     * @throws InvalidArgumentException
     * @return Result
     */
    public function validate( EntityDocument $entity ) {
        if ( !( $entity instanceof DescriptionsProvider ) ) {
            throw new InvalidArgumentException( '$entity must be a DescriptionsProvider' );
        }

        $languageValidator = $this->termValidatorFactory->getDescriptionLanguageValidator();
        $termValidator = $this->termValidatorFactory->getDescriptionValidator();

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

        if ( $result->isValid() && $this->description !== null ) {
            // Check that the new description is valid
            $result = $termValidator->validate( $this->description );
        }

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

        if ( $entity instanceof LabelsProvider ) {
            $validator = $this->termValidatorFactory->getLabelDescriptionNotEqualValidator();

            // Check if the new fingerprint of the entity is valid
            $descriptions = clone $entity->getDescriptions();
            $this->updateDescriptions( $descriptions );

            // Noop action, don't try to validate it yet -- T222621
            if ( $descriptions->toTextArray() === $entity->getDescriptions()->toTextArray() ) {
                return $result;
            }

            $result = $validator->validateLabelAndDescription(
                $entity->getLabels(),
                $descriptions,
                [ $this->languageCode ]
            );
        }

        return $result;
    }

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

}