wikimedia/mediawiki-extensions-Wikibase

View on GitHub
repo/includes/StatementGrouperBuilder.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

namespace Wikibase\Repo;

use InvalidArgumentException;
use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup;
use Wikibase\DataModel\Services\Statement\Filter\DataTypeStatementFilter;
use Wikibase\DataModel\Services\Statement\Filter\NullStatementFilter;
use Wikibase\DataModel\Services\Statement\Filter\PropertySetStatementFilter;
use Wikibase\DataModel\Services\Statement\Grouper\FilteringStatementGrouper;
use Wikibase\DataModel\Services\Statement\Grouper\NullStatementGrouper;
use Wikibase\DataModel\Services\Statement\Grouper\StatementGrouper;
use Wikibase\DataModel\Services\Statement\StatementGuidParser;
use Wikibase\DataModel\Statement\StatementFilter;

/**
 * Factory for a StatementGrouper. The grouper is instantiated based on a specification array that
 * has the following form:
 *
 * [
 *     'item' => [
 *         'statements' => null,
 *         'example' => [
 *             'type' => 'propertySet',
 *             'propertyIds' => [ 'P1' ],
 *         ],
 *         'identifiers' => [
 *             'type' => 'dataType',
 *             'dataTypes' => [ 'external-id' ],
 *         ],
 *     ],
 *     'property' => [
 *     ],
 * ],
 *
 * @license GPL-2.0-or-later
 * @author Daniel Kinzler
 * @author Thiemo Kreuz
 */
class StatementGrouperBuilder {

    /**
     * @var array[]
     */
    private $specifications;

    /**
     * @var PropertyDataTypeLookup
     */
    private $dataTypeLookup;

    /**
     * @var StatementGuidParser
     */
    private $statementGuidParser;

    /**
     * @param array[] $specifications See the class level documentation for details.
     * @param PropertyDataTypeLookup $dataTypeLookup
     * @param StatementGuidParser $statementGuidParser
     */
    public function __construct(
        array $specifications,
        PropertyDataTypeLookup $dataTypeLookup,
        StatementGuidParser $statementGuidParser
    ) {
        $this->specifications = $specifications;
        $this->dataTypeLookup = $dataTypeLookup;
        $this->statementGuidParser = $statementGuidParser;
    }

    /**
     * @throws InvalidArgumentException
     * @return StatementGrouper
     */
    public function getStatementGrouper() {
        $groupers = [];

        foreach ( $this->specifications as $entityType => $filterSpecs ) {
            $groupers[$entityType] = $filterSpecs === null
                ? new NullStatementGrouper()
                : $this->newFilteringStatementGrouper( $filterSpecs );
        }

        return new DispatchingEntityTypeStatementGrouper( $this->statementGuidParser, $groupers );
    }

    /**
     * @param array[] $filterSpecs
     *
     * @throws InvalidArgumentException
     * @return FilteringStatementGrouper
     */
    private function newFilteringStatementGrouper( array $filterSpecs ) {
        $filters = [];

        foreach ( $filterSpecs as $groupIdentifier => $spec ) {
            $filters[$groupIdentifier] = $spec === null
                ? null
                : $this->newStatementFilter( $spec );
        }

        return new FilteringStatementGrouper( $filters );
    }

    /**
     * @param array $spec
     *
     * @throws InvalidArgumentException
     * @return StatementFilter
     */
    private function newStatementFilter( array $spec ) {
        $this->requireField( $spec, 'type' );

        switch ( $spec['type'] ) {
            case null:
                return new NullStatementFilter();
            case DataTypeStatementFilter::FILTER_TYPE:
                $this->requireField( $spec, 'dataTypes' );
                return new DataTypeStatementFilter( $this->dataTypeLookup, $spec['dataTypes'] );
            case PropertySetStatementFilter::FILTER_TYPE:
                $this->requireField( $spec, 'propertyIds' );
                return new PropertySetStatementFilter( $spec['propertyIds'] );
            // Be aware that this switch statement is a possible violation of the open-closed
            // principle. When the number of filters grows, please try to extract this in a way that
            // it can be injected.
        }

        throw new InvalidArgumentException( 'Unknown filter type: ' . $spec['type'] );
    }

    /**
     * @param array $spec
     * @param string $field
     *
     * @throws InvalidArgumentException
     */
    private function requireField( array $spec, $field ) {
        if ( !array_key_exists( $field, $spec ) ) {
            throw new InvalidArgumentException(
                "Statement group configuration misses required field '$field'"
            );
        }
    }

}