wikimedia/mediawiki-extensions-Wikibase

View on GitHub
lib/packages/wikibase/data-model-services/src/Diff/Internal/AliasGroupListPatcher.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace Wikibase\DataModel\Services\Diff\Internal;

use Diff\DiffOp\Diff\Diff;
use Diff\DiffOp\DiffOp;
use Diff\DiffOp\DiffOpAdd;
use Diff\DiffOp\DiffOpChange;
use Diff\DiffOp\DiffOpRemove;
use Diff\Patcher\PatcherException;
use Wikibase\DataModel\Term\AliasGroupList;

/**
 * Package private.
 *
 * @since 3.6
 *
 * @license GPL-2.0-or-later
 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 * @author Thiemo Kreuz
 */
class AliasGroupListPatcher {

    /**
     * @since 3.6
     *
     * @param AliasGroupList $groups
     * @param Diff $patch
     *
     * @throws PatcherException
     */
    public function patchAliasGroupList( AliasGroupList $groups, Diff $patch ) {
        foreach ( $patch as $lang => $diffOp ) {
            $this->patchAliasGroup( $groups, $lang, $diffOp );
        }
    }

    /**
     * @see Diff\Patcher\MapPatcher
     *
     * @param AliasGroupList $groups
     * @param string $lang
     * @param DiffOp $diffOp
     *
     * @throws PatcherException
     */
    private function patchAliasGroup( AliasGroupList $groups, $lang, DiffOp $diffOp ) {
        $hasLang = $groups->hasGroupForLanguage( $lang );

        switch ( true ) {
            case $diffOp instanceof DiffOpAdd:
                if ( !$hasLang ) {
                    $groups->setAliasesForLanguage( $lang, $diffOp->getNewValue() );
                }
                break;

            case $diffOp instanceof DiffOpChange:
                $this->applyAliasGroupChange( $groups, $lang, $diffOp );
                break;

            case $diffOp instanceof DiffOpRemove:
                if ( $hasLang
                    && $groups->getByLanguage( $lang )->getAliases() === $diffOp->getOldValue()
                ) {
                    $groups->removeByLanguage( $lang );
                }
                break;

            case $diffOp instanceof Diff:
                $this->applyAliasGroupDiff( $groups, $lang, $diffOp );
                break;

            default:
                throw new PatcherException( 'Invalid aliases diff' );
        }
    }

    /**
     * @param AliasGroupList $groups
     * @param string $lang
     * @param DiffOpChange $patch
     */
    private function applyAliasGroupChange( AliasGroupList $groups, $lang, DiffOpChange $patch ) {
        if ( $groups->hasGroupForLanguage( $lang )
            && $groups->getByLanguage( $lang )->getAliases() === $patch->getOldValue()
        ) {
            $groups->setAliasesForLanguage( $lang, $patch->getNewValue() );
        }
    }

    /**
     * @param AliasGroupList $groups
     * @param string $lang
     * @param Diff $patch
     */
    private function applyAliasGroupDiff( AliasGroupList $groups, $lang, Diff $patch ) {
        $hasLang = $groups->hasGroupForLanguage( $lang );

        if ( $hasLang || !$this->containsOperationsOnOldValues( $patch ) ) {
            $aliases = $hasLang ? $groups->getByLanguage( $lang )->getAliases() : [];
            $aliases = $this->getPatchedAliases( $aliases, $patch );
            $groups->setAliasesForLanguage( $lang, $aliases );
        }
    }

    /**
     * @param Diff $diff
     *
     * @return bool
     */
    private function containsOperationsOnOldValues( Diff $diff ) {
        return $diff->getChanges() !== []
            || $diff->getRemovals() !== [];
    }

    /**
     * @see ListPatcher
     *
     * @param string[] $aliases
     * @param Diff $patch
     *
     * @throws PatcherException
     * @return string[]
     */
    private function getPatchedAliases( array $aliases, Diff $patch ) {
        foreach ( $patch as $diffOp ) {
            switch ( true ) {
                case $diffOp instanceof DiffOpAdd:
                    $aliases[] = $diffOp->getNewValue();
                    break;

                case $diffOp instanceof DiffOpChange:
                    $key = array_search( $diffOp->getOldValue(), $aliases, true );
                    if ( $key !== false ) {
                        unset( $aliases[$key] );
                        $aliases[] = $diffOp->getNewValue();
                    }
                    break;

                case $diffOp instanceof DiffOpRemove:
                    $key = array_search( $diffOp->getOldValue(), $aliases, true );
                    if ( $key !== false ) {
                        unset( $aliases[$key] );
                    }
                    break;

                default:
                    throw new PatcherException( 'Invalid aliases diff' );
            }
        }

        return $aliases;
    }

}