ComposerizeEndpoint.php 3.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
<?php

declare(strict_types = 1);

/*
 * This file is part of TYPO3 CMS-extension "ter", created by Oliver Bartsch.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 */

namespace T3o\Ter\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use T3o\Ter\Controller\ComposerizeController;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
 * This middleware handles requests to the /composerize/* endpoints
 */
class ComposerizeEndpoint implements MiddlewareInterface
{
    protected string $base = '/composerize';
    protected array $routes = [
        'createExtensionComposerMap' => ['endpoint' => '', 'method' => 'GET'],
        'createComposerManifest' => ['endpoint' => '/{key}', 'method' => 'POST']
    ];

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if (!$this->canHandle($request)) {
            return $handler->handle($request);
        }

        try {
            $routeResult = (new UrlMatcher(
                $this->getRouteCollection(),
                $this->getRequestContext($request)
            ))->match($request->getUri()->getPath());
        } catch (\Exception $e) {
            return $handler->handle($request);
        }

        if (!isset($routeResult['_controller'], $routeResult['_route'])) {
            return $handler->handle($request);
        }

        $controller = GeneralUtility::makeInstance($routeResult['_controller']);
        $action = $routeResult['_route'] . 'Action';

        if (is_callable([$controller, $action])) {
            return $controller->{$action}(
                $request->withAttribute('routeResult', array_filter($routeResult, static function ($_, $k) {
                    return strpos($k, '_') !== 0;
                }, ARRAY_FILTER_USE_BOTH)),
            );
        }

        return $handler->handle($request);
    }

    protected function canHandle(ServerRequestInterface $request): bool
    {
        return strpos($request->getUri()->getPath(), $this->base) === 0
            && isset(array_flip(array_unique(array_column($this->routes, 'method')))[$request->getMethod()]);
    }

    protected function getRouteCollection(): RouteCollection
    {
        $routeCollection = new RouteCollection();

        foreach ($this->routes as $name => $options) {
            $routeCollection->add(
                $name,
                (new Route($this->base . $options['endpoint']))
                    ->setMethods([$options['method']])
                    ->setDefault('_controller', ComposerizeController::class)
            );
        }

        return $routeCollection;
    }

    protected function getRequestContext(ServerRequestInterface $request): RequestContext
    {
        $uri = $request->getUri();
        return new RequestContext(
            '',
            $request->getMethod(),
            (string)idn_to_ascii($uri->getHost()),
            $uri->getScheme(),
            80,
            443,
            $uri->getPath(),
            $uri->getQuery()
        );
    }
}