wikimedia/mediawiki-extensions-Wikibase

View on GitHub
lib/packages/wikibase/changes/src/EntityDiffChangedAspectsFactory.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php

namespace Wikibase\Lib\Changes;

use Diff\DiffOp\Diff\Diff;
use Diff\DiffOp\DiffOp;
use Diff\DiffOp\DiffOpAdd;
use Diff\DiffOp\DiffOpChange;
use Diff\DiffOp\DiffOpRemove;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Wikibase\DataModel\Services\Diff\EntityDiff;
use Wikibase\DataModel\Services\Diff\ItemDiff;
use Wikibase\DataModel\Statement\Statement;

/**
 * @license GPL-2.0-or-later
 * @author Marius Hoch
 */
class EntityDiffChangedAspectsFactory {

    /** @var LoggerInterface */
    private $logger;

    public function __construct( ?LoggerInterface $logger = null ) {
        $this->logger = $logger ?: new NullLogger();
    }

    /**
     * @param Diff $entityDiff
     *
     * @return EntityDiffChangedAspects
     */
    public function newFromEntityDiff( Diff $entityDiff ) {
        $labelChanges = [];
        $descriptionChanges = [];
        $statementChanges = [];
        $siteLinkChanges = [];
        $otherChanges = false;

        $remainingDiffOps = count( $entityDiff ); // this is a "deep" count!

        if ( $entityDiff instanceof ItemDiff && !$entityDiff->getSiteLinkDiff()->isEmpty() ) {
            $siteLinkDiff = $entityDiff->getSiteLinkDiff();

            $remainingDiffOps -= count( $siteLinkDiff );
            $siteLinkChanges = $this->getChangedSiteLinks( $siteLinkDiff );
        }

        if ( $entityDiff instanceof EntityDiff ) {
            $labelsDiff = $entityDiff->getLabelsDiff();
            if ( $labelsDiff ) {
                $remainingDiffOps -= count( $labelsDiff );
                $labelChanges = $this->getChangedLabels( $labelsDiff );
            }

            $descriptionsDiff = $entityDiff->getDescriptionsDiff();
            if ( $descriptionsDiff ) {
                $remainingDiffOps -= count( $descriptionsDiff );
                $descriptionChanges = $this->getChangedDescriptions( $descriptionsDiff );
            }

            $claimsDiff = $entityDiff->getClaimsDiff();
            if ( $claimsDiff ) {
                $remainingDiffOps -= count( $claimsDiff );
                $statementChanges = $this->getChangedStatements( $claimsDiff );
            }
        }

        if ( $remainingDiffOps > 0 ) {
            $otherChanges = true;
        }

        return new EntityDiffChangedAspects(
            $labelChanges,
            $descriptionChanges,
            $statementChanges,
            $siteLinkChanges,
            $otherChanges
        );
    }

    /**
     * @param Diff $siteLinkDiff
     *
     * @return array[]
     */
    private function getChangedSiteLinks( Diff $siteLinkDiff ) {
        $siteLinkChanges = [];

        foreach ( $siteLinkDiff as $siteId => $diffPerSite ) {
            $siteLinkChanges[$siteId] = $this->getSiteLinkChangePerSite( $diffPerSite );
        }

        return $siteLinkChanges;
    }

    /**
     * @param DiffOp $siteLinkDiffOp
     *
     * @return array ( string|null $oldPageName, string|null $newPageName, bool $badgesChanged )
     * @phan-return array{0:?string,1:?string,2:bool}
     */
    private function getSiteLinkChangePerSite( DiffOp $siteLinkDiffOp ) {
        if ( !$siteLinkDiffOp instanceof Diff ) {
            return [ null, null, false ];
        }

        $removals = $siteLinkDiffOp->getRemovedValues();
        $additions = $siteLinkDiffOp->getAddedValues();
        $changes = $siteLinkDiffOp->getChanges();

        $oldValue = ( array_key_exists( 'name', $removals ) ) ? $removals['name'] : null;
        $newValue = ( array_key_exists( 'name', $additions ) ) ? $additions['name'] : null;

        if ( array_key_exists( 'name', $changes ) ) {
            $oldValue = $changes['name']->getOldValue();
            $newValue = $changes['name']->getNewValue();
        }

        return [ $oldValue, $newValue, $siteLinkDiffOp->offsetExists( 'badges' ) ];
    }

    /**
     * @param Diff $labelsDiff
     *
     * @return string[]
     */
    private function getChangedLabels( Diff $labelsDiff ) {
        return array_keys( iterator_to_array( $labelsDiff ) );
    }

    /**
     * @param Diff $descriptionsDiff
     *
     * @return string[]
     */
    private function getChangedDescriptions( Diff $descriptionsDiff ) {
        return array_keys( iterator_to_array( $descriptionsDiff ) );
    }

    /**
     * @param Diff $claimsDiff
     *
     * @return string[]
     */
    private function getChangedStatements( Diff $claimsDiff ) {
        $changedStatements = [];

        foreach ( $claimsDiff as $pid => $diffOp ) {
            /** @var Statement $statement */
            if ( $diffOp instanceof DiffOpAdd ) {
                $statement = $diffOp->getNewValue();
            } elseif ( $diffOp instanceof DiffOpRemove ) {
                $statement = $diffOp->getOldValue();
            } elseif ( $diffOp instanceof DiffOpChange ) {
                $statement = $diffOp->getOldValue();
                /** @var $newStatement Statement */
                $newStatement = $diffOp->getNewValue();

                $changedStatements[] = $newStatement->getPropertyId()->getSerialization();
            } else {
                $this->logger->warning( 'Unknown DiffOp type {class}', [
                    'class' => get_class( $diffOp ),
                ] );
                continue;
            }

            '@phan-var Statement $statement';
            $changedStatements[] = $statement->getPropertyId()->getSerialization();
        }

        return array_values( array_unique( $changedStatements ) );
    }

    /**
     * @return EntityDiffChangedAspects
     */
    public function newEmpty() {
        return $this->newFromEntityDiff( new Diff() );
    }
}