wikimedia/mediawiki-extensions-Wikibase

View on GitHub
lib/includes/ServiceByTypeDispatcher.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

// phpcs:disable MediaWiki.Commenting.FunctionComment.ObjectTypeHintParam
// phpcs:disable MediaWiki.Commenting.FunctionComment.ObjectTypeHintReturn
// phpcs:disable MediaWiki.Commenting.PropertyDocumentation.ObjectTypeHintVar

declare( strict_types=1 );

namespace Wikibase\Lib;

use Wikimedia\Assert\Assert;

/**
 * @license GPL-2.0-or-later
 */
class ServiceByTypeDispatcher {

    /** @var callable[] */
    private $callbacks;

    /**
     * Map of entity types to services that were created by the respective callback
     * @var object[]
     */
    private $services;

    /** @var object */
    private $defaultService;

    /** @var class-string */
    private $type;

    /**
     * @param class-string $type type of the dispatched services, i.e. type of the default service and the return value of the callbacks
     * @param callable[] $callbacks map of entity types to callbacks creating the service to be used
     * @param object $defaultService the service to be used when there is no callback defined for the given entity type
     */
    public function __construct( string $type, array $callbacks, object $defaultService ) {
        Assert::parameterElementType( 'callable', $callbacks, '$callbacks' );
        Assert::parameterKeyType( 'string', $callbacks, '$callbacks' );
        Assert::parameterType( $type, $defaultService, '$defaultService' );

        $this->callbacks = $callbacks;
        $this->defaultService = $defaultService;
        $this->type = $type;
    }

    /**
     * @param string $entityType
     * @param array $callbackArgs arguments to be passed to the service creation callback
     *
     * @return object
     */
    public function getServiceForType( string $entityType, array $callbackArgs = [] ) {
        if ( !array_key_exists( $entityType, $this->callbacks ) ) {
            return $this->defaultService;
        }

        return $this->services[$entityType] ?? $this->createService( $entityType, $callbackArgs );
    }

    private function createService( string $entityType, array $args = [] ) {
        $this->services[$entityType] = $this->callbacks[$entityType]( ...$args );

        Assert::postcondition(
            $this->services[$entityType] instanceof $this->type,
            "callback must return an instance of $this->type"
        );

        return $this->services[$entityType];
    }

}