wikimedia/mediawiki-extensions-Wikibase

View on GitHub
repo/rest-api/src/RouteHandlers/GetPropertyLabelWithFallbackRouteHandler.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php declare( strict_types = 1 );

namespace Wikibase\Repo\RestApi\RouteHandlers;

use MediaWiki\MediaWikiServices;
use MediaWiki\Rest\RequestInterface;
use MediaWiki\Rest\Response;
use MediaWiki\Rest\ResponseInterface;
use MediaWiki\Rest\SimpleHandler;
use MediaWiki\Rest\StringStream;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\GetPropertyLabelWithFallback;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\GetPropertyLabelWithFallbackRequest;
use Wikibase\Repo\RestApi\Application\UseCases\GetPropertyLabelWithFallback\GetPropertyLabelWithFallbackResponse;
use Wikibase\Repo\RestApi\Application\UseCases\UseCaseError;
use Wikibase\Repo\RestApi\RouteHandlers\Middleware\AuthenticationMiddleware;
use Wikibase\Repo\RestApi\RouteHandlers\Middleware\MiddlewareHandler;
use Wikibase\Repo\RestApi\RouteHandlers\Middleware\UserAgentCheckMiddleware;
use Wikibase\Repo\RestApi\WbRestApi;
use Wikimedia\ParamValidator\ParamValidator;
use function json_encode;

/**
 * @license GPL-2.0-or-later
 */
class GetPropertyLabelWithFallbackRouteHandler extends SimpleHandler {

    private const PROPERTY_ID_PATH_PARAM = 'property_id';
    private const LANGUAGE_CODE_PATH_PARAM = 'language_code';

    private GetPropertyLabelWithFallback $useCase;
    private MiddlewareHandler $middlewareHandler;
    private ResponseFactory $responseFactory;

    public function __construct(
        GetPropertyLabelWithFallback $useCase,
        MiddlewareHandler $middlewareHandler,
        ResponseFactory $responseFactory
    ) {
        $this->useCase = $useCase;
        $this->middlewareHandler = $middlewareHandler;
        $this->responseFactory = $responseFactory;
    }

    public static function factory(): self {
        $responseFactory = new ResponseFactory();
        return new self(
            WbRestApi::getGetPropertyLabelWithFallback(),
            new MiddlewareHandler( [
                WbRestApi::getUnexpectedErrorHandlerMiddleware(),
                new UserAgentCheckMiddleware(),
                new AuthenticationMiddleware( MediaWikiServices::getInstance()->getUserIdentityUtils() ),
                WbRestApi::getPreconditionMiddlewareFactory()->newPreconditionMiddleware(
                    fn( RequestInterface $request ): string => $request->getPathParam( self::PROPERTY_ID_PATH_PARAM )
                ),
            ] ),
            $responseFactory
        );
    }

    /**
     * @param mixed ...$args
     */
    public function run( ...$args ): Response {
        return $this->middlewareHandler->run( $this, [ $this, 'runUseCase' ], $args );
    }

    public function runUseCase( string $propertyId, string $languageCode ): Response {
        try {
            $response = $this->useCase->execute( new GetPropertyLabelWithFallbackRequest( $propertyId, $languageCode ) );

            return $response->getLabel()->getLanguageCode() === $languageCode ?
                $this->newSuccessResponse( $response ) :
                $this->newLanguageFallbackResponse( $propertyId, $response->getLabel()->getLanguageCode() );
        } catch ( UseCaseError $e ) {
            return $this->responseFactory->newErrorResponseFromException( $e );
        }
    }

    public function getParamSettings(): array {
        return [
            self::PROPERTY_ID_PATH_PARAM => [
                self::PARAM_SOURCE => 'path',
                ParamValidator::PARAM_TYPE => 'string',
                ParamValidator::PARAM_REQUIRED => true,
            ],
            self::LANGUAGE_CODE_PATH_PARAM => [
                self::PARAM_SOURCE => 'path',
                ParamValidator::PARAM_TYPE => 'string',
                ParamValidator::PARAM_REQUIRED => true,
            ],
        ];
    }

    private function newSuccessResponse( GetPropertyLabelWithFallbackResponse $useCaseResponse ): Response {
        $httpResponse = $this->getResponseFactory()->create();
        $httpResponse->setHeader( 'Content-Type', 'application/json' );
        $httpResponse->setHeader( 'Last-Modified', wfTimestamp( TS_RFC2822, $useCaseResponse->getLastModified() ) );
        $httpResponse->setHeader( 'ETag', "\"{$useCaseResponse->getRevisionId()}\"" );
        $httpResponse->setBody(
            new StringStream( json_encode( $useCaseResponse->getLabel()->getText() ) )
        );

        return $httpResponse;
    }

    /**
     * @inheritDoc
     */
    public function needsWriteAccess(): bool {
        return false;
    }

    /**
     * Preconditions are checked via {@link PreconditionMiddleware}
     */
    public function checkPreconditions(): ?ResponseInterface {
        return null;
    }

    private function newLanguageFallbackResponse( string $propertyId, string $fallbackLanguageCode ): Response {
        $httpResponse = $this->getResponseFactory()->create();
        $httpResponse->setHeader(
            'Location',
            $this->getRouter()->getRouteUrl(
                GetPropertyLabelRouteHandler::ROUTE,
                [
                    self::PROPERTY_ID_PATH_PARAM => $propertyId,
                    self::LANGUAGE_CODE_PATH_PARAM => $fallbackLanguageCode,
                ]
            )
        );
        $httpResponse->setStatus( 307 );

        return $httpResponse;
    }

}