diff --git a/config/routing-expressive.xml b/config/routing-expressive.xml
index 5c68c260..84c53492 100644
--- a/config/routing-expressive.xml
+++ b/config/routing-expressive.xml
@@ -56,6 +56,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ createStream
+
+
+
+
+
+
+
+
+
+ fromGlobals
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -63,5 +103,7 @@
+
+
diff --git a/config/routing-mezzio.xml b/config/routing-mezzio.xml
index b5079136..3e82f658 100644
--- a/config/routing-mezzio.xml
+++ b/config/routing-mezzio.xml
@@ -56,6 +56,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ createStream
+
+
+
+
+
+
+
+
+
+ fromGlobals
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/infection.json.dist b/infection.json.dist
index cf685482..642f8012 100644
--- a/infection.json.dist
+++ b/infection.json.dist
@@ -9,5 +9,5 @@
"text": "infection.log"
},
"minMsi": 40,
- "minCoveredMsi": 80
+ "minCoveredMsi": 75
}
diff --git a/src/Routing/Expressive/RegisterServices.php b/src/Routing/Expressive/RegisterServices.php
index 9d49bd15..54fd5411 100644
--- a/src/Routing/Expressive/RegisterServices.php
+++ b/src/Routing/Expressive/RegisterServices.php
@@ -9,8 +9,8 @@
use Chimera\ExecuteQuery;
use Chimera\IdentifierGenerator;
use Chimera\MessageCreator;
+use Chimera\Routing\Application as ApplicationInterface;
use Chimera\Routing\Expressive\Application;
-use Chimera\Routing\Expressive\UriGenerator;
use Chimera\Routing\Handler\CreateAndFetch;
use Chimera\Routing\Handler\CreateOnly;
use Chimera\Routing\Handler\ExecuteAndFetch;
@@ -18,7 +18,9 @@
use Chimera\Routing\Handler\FetchOnly;
use Chimera\Routing\MissingRouteDispatching;
use Chimera\Routing\RouteParamsExtraction;
+use Chimera\Routing\UriGenerator as UriGeneratorInterface;
use Fig\Http\Message\StatusCodeInterface as StatusCode;
+use InvalidArgumentException;
use Lcobucci\ContentNegotiation\ContentTypeMiddleware;
use Lcobucci\ContentNegotiation\Formatter\Json;
use Psr\Http\Message\ResponseFactoryInterface;
@@ -27,15 +29,12 @@
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
-use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
-use Zend\Diactoros\ServerRequestFactory;
use Zend\Expressive\Application as Expressive;
use Zend\Expressive\Helper\BodyParams\BodyParamsMiddleware;
use Zend\Expressive\Middleware\LazyLoadingMiddleware;
use Zend\Expressive\MiddlewareContainer;
use Zend\Expressive\MiddlewareFactory;
-use Zend\Expressive\Response\ServerRequestErrorResponseGenerator;
use Zend\Expressive\Router\FastRouteRouter;
use Zend\Expressive\Router\Middleware\DispatchMiddleware;
use Zend\Expressive\Router\Middleware\ImplicitHeadMiddleware;
@@ -43,7 +42,7 @@
use Zend\Expressive\Router\Middleware\MethodNotAllowedMiddleware;
use Zend\Expressive\Router\Middleware\RouteMiddleware;
use Zend\Expressive\Router\RouteCollector;
-use Zend\HttpHandlerRunner\Emitter\EmitterInterface;
+use Zend\Expressive\Router\RouterInterface;
use Zend\HttpHandlerRunner\RequestHandlerRunner;
use Zend\Stratigility\Middleware\PathMiddlewareDecorator;
use Zend\Stratigility\MiddlewarePipe;
@@ -95,13 +94,13 @@ public function process(ContainerBuilder $container): void
$this->registerApplication(
$container,
- $routes[$this->applicationName] ?? [],
- $this->prioritiseMiddleware($middlewareList[$this->applicationName] ?? [])
+ $routes ?? [],
+ $this->prioritiseMiddleware($middlewareList ?? [])
);
}
/**
- * @return string[][][]
+ * @return string[][]
*
* @throws InvalidArgumentException
*/
@@ -135,12 +134,10 @@ private function extractRoutes(ContainerBuilder $container): array
$tag['methods'] = explode(',', $tag['methods']);
}
- $tag['app'] ??= $this->applicationName;
$tag['async'] = (bool) ($tag['async'] ?? false);
$tag['serviceId'] = $serviceId;
- $routes[$tag['app']] ??= [];
- $routes[$tag['app']][] = $tag;
+ $routes[] = $tag;
$names[$tag['route_name']] = $serviceId;
}
@@ -163,31 +160,26 @@ private function extractMiddlewareList(ContainerBuilder $container): array
$priority = $tag['priority'] ?? 0;
$path = $tag['path'] ?? '/';
- $tag['app'] ??= $this->applicationName;
-
- $list[$tag['app']][$priority][$path] ??= [];
- $list[$tag['app']][$priority][$path][] = $serviceId;
+ $list[$priority][$path] ??= [];
+ $list[$priority][$path][] = $serviceId;
}
}
- $list[$this->applicationName][Priorities::CONTENT_NEGOTIATION]['/'] ??= [];
- $list[$this->applicationName][Priorities::BEFORE_CUSTOM]['/'] ??= [];
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'] ??= [];
+ $list[Priorities::CONTENT_NEGOTIATION]['/'] ??= [];
+ $list[Priorities::BEFORE_CUSTOM]['/'] ??= [];
+ $list[Priorities::AFTER_CUSTOM]['/'] ??= [];
- $list[$this->applicationName][Priorities::CONTENT_NEGOTIATION]['/'][] = $this->applicationName
- . '.http.middleware.content_negotiation';
+ $list[Priorities::CONTENT_NEGOTIATION]['/'][] = ContentTypeMiddleware::class;
- $list[$this->applicationName][Priorities::BEFORE_CUSTOM]['/'][] = $this->applicationName
- . '.http.middleware.route';
- $list[$this->applicationName][Priorities::BEFORE_CUSTOM]['/'][] = BodyParamsMiddleware::class;
+ $list[Priorities::BEFORE_CUSTOM]['/'][] = RouteMiddleware::class;
+ $list[Priorities::BEFORE_CUSTOM]['/'][] = BodyParamsMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = $this->applicationName
- . '.http.middleware.implicit_head';
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = ImplicitOptionsMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = MethodNotAllowedMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = RouteParamsExtraction::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = DispatchMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = MissingRouteDispatching::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = ImplicitHeadMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = ImplicitOptionsMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = MethodNotAllowedMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = RouteParamsExtraction::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = DispatchMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = MissingRouteDispatching::class;
return $list;
}
@@ -245,15 +237,23 @@ private function registerApplication(
array $routes,
array $middlewareList
): void {
+ if ($container->hasDefinition(ApplicationInterface::class)) {
+ throw new InvalidArgumentException('Registering multiple applications is deprecated.');
+ }
+
$services = [];
+ $aliases = []; // for BC
foreach ($routes as $route) {
// @phpstan-ignore-next-line
$services[] = $this->{self::BEHAVIORS[$route['behavior']]['callback']}(
- $this->applicationName . '.http.route.' . $route['route_name'],
+ 'http.route.' . $route['route_name'],
$route,
$container
);
+
+ $aliases[$this->applicationName . '.http.route.' . $route['route_name']]
+ = 'http.route.' . $route['route_name'];
}
$middleware = [];
@@ -282,16 +282,12 @@ private function registerApplication(
// -- middleware container
$middlewareContainer = $this->createService(MiddlewareContainer::class, [$locator]);
- $container->setDefinition($this->applicationName . '.http.middleware_container', $middlewareContainer);
+ $container->setDefinition(MiddlewareContainer::class, $middlewareContainer);
+ $aliases[$this->applicationName . '.http.middleware_container'] = MiddlewareContainer::class;
// -- middleware factory
- $middlewareFactory = $this->createService(
- MiddlewareFactory::class,
- [new Reference($this->applicationName . '.http.middleware_container')]
- );
-
- $container->setDefinition($this->applicationName . '.http.middleware_factory', $middlewareFactory);
+ $aliases[$this->applicationName . '.http.middleware_factory'] = MiddlewareFactory::class;
// -- middleware pipeline
@@ -301,28 +297,28 @@ private function registerApplication(
$middlewarePipeline->addMethodCall('pipe', [new Reference($service)]);
}
- $container->setDefinition($this->applicationName . '.http.middleware_pipeline', $middlewarePipeline);
+ $container->setDefinition(MiddlewarePipe::class, $middlewarePipeline);
+ $aliases[$this->applicationName . '.http.middleware_pipeline'] = MiddlewarePipe::class;
// -- routing
- $appRouterConfig = $container->hasParameter($this->applicationName . '.router_config')
- ? '%' . $this->applicationName . '.router_config%'
- : [];
-
- $router = $this->createService(FastRouteRouter::class, [null, null, $appRouterConfig]);
-
- $container->setDefinition($this->applicationName . '.http.router', $router);
-
- $uriGenerator = $this->createService(
- UriGenerator::class,
- [new Reference($this->applicationName . '.http.router')]
+ $router = $this->createService(
+ FastRouteRouter::class,
+ [
+ null,
+ null,
+ $this->readBCParameter($container, $this->applicationName . '.router_config', 'router_config', []),
+ ]
);
- $container->setDefinition($this->applicationName . '.http.uri_generator', $uriGenerator);
+ $container->setDefinition(FastRouteRouter::class, $router);
+ $container->setAlias(RouterInterface::class, FastRouteRouter::class);
+ $aliases[$this->applicationName . '.http.router'] = FastRouteRouter::class;
+ $aliases[$this->applicationName . '.http.uri_generator'] = UriGeneratorInterface::class;
$routeCollector = $this->createService(
RouteCollector::class,
- [new Reference($this->applicationName . '.http.router')]
+ [new Reference(FastRouteRouter::class)]
);
foreach ($routes as $route) {
@@ -330,31 +326,17 @@ private function registerApplication(
'route',
[
$route['path'],
- new Reference($this->applicationName . '.http.route.' . $route['route_name']),
+ new Reference('http.route.' . $route['route_name']),
$route['methods'] ?? self::BEHAVIORS[$route['behavior']]['methods'],
$route['route_name'],
]
);
}
- $container->setDefinition($this->applicationName . '.http.route_collector', $routeCollector);
-
- $routingMiddleware = $this->createService(
- RouteMiddleware::class,
- [new Reference($this->applicationName . '.http.router')]
- );
-
- $container->setDefinition($this->applicationName . '.http.middleware.route', $routingMiddleware);
-
- $implicitHeadMiddleware = $this->createService(
- ImplicitHeadMiddleware::class,
- [
- new Reference($this->applicationName . '.http.router'),
- [new Reference(StreamFactoryInterface::class), 'createStream'],
- ]
- );
-
- $container->setDefinition($this->applicationName . '.http.middleware.implicit_head', $implicitHeadMiddleware);
+ $container->setDefinition(RouteCollector::class, $routeCollector);
+ $aliases[$this->applicationName . '.http.route_collector'] = RouteCollector::class;
+ $aliases[$this->applicationName . '.http.middleware.route'] = RouteMiddleware::class;
+ $aliases[$this->applicationName . '.http.middleware.implicit_head'] = ImplicitHeadMiddleware::class;
// -- content negotiation
@@ -371,13 +353,15 @@ private function registerApplication(
$formatters['application/problem+json'] = new Reference(Json::class);
}
- $applicationAllowedFormats = $this->applicationName . '.allowed_formats';
-
$negotiator = $this->createService(
ContentTypeMiddleware::class,
[
- $container->hasParameter($applicationAllowedFormats) ? '%' . $applicationAllowedFormats . '%'
- : '%chimera.default_allowed_formats%',
+ $this->readBCParameter(
+ $container,
+ $this->applicationName . '.allowed_formats',
+ 'allowed_formats',
+ '%chimera.default_allowed_formats%'
+ ),
$formatters,
new Reference(StreamFactoryInterface::class),
]
@@ -385,39 +369,21 @@ private function registerApplication(
$negotiator->setFactory([ContentTypeMiddleware::class, 'fromRecommendedSettings']);
- $container->setDefinition($this->applicationName . '.http.middleware.content_negotiation', $negotiator);
-
- // --- request handler runner
+ $container->setDefinition(ContentTypeMiddleware::class, $negotiator);
+ $aliases[$this->applicationName . '.http.middleware.content_negotiation'] = ContentTypeMiddleware::class;
+ $aliases[$this->applicationName . '.http.request_handler_runner'] = RequestHandlerRunner::class;
- $requestHandlerRunner = $this->createService(
- RequestHandlerRunner::class,
- [
- new Reference($this->applicationName . '.http.middleware_pipeline'),
- new Reference(EmitterInterface::class),
- [ServerRequestFactory::class, 'fromGlobals'],
- new Reference(ServerRequestErrorResponseGenerator::class),
- ]
- );
+ $app = new Definition(Application::class, [new Reference(Expressive::class)]);
+ $app->setPublic(true);
- $container->setDefinition($this->applicationName . '.http.request_handler_runner', $requestHandlerRunner);
+ $container->setDefinition(ApplicationInterface::class, $app);
+ $aliases[$this->applicationName . '.http'] = ApplicationInterface::class;
- $container->setDefinition(
- $this->applicationName . '.http_expressive',
- new Definition(
- Expressive::class,
- [
- new Reference($this->applicationName . '.http.middleware_factory'),
- new Reference($this->applicationName . '.http.middleware_pipeline'),
- new Reference($this->applicationName . '.http.route_collector'),
- new Reference($this->applicationName . '.http.request_handler_runner'),
- ]
- )
- );
-
- $app = new Definition(Application::class, [new Reference($this->applicationName . '.http_expressive')]);
- $app->setPublic(true);
+ foreach ($aliases as $alias => $service) {
+ $container->setAlias($alias, $service);
+ }
- $container->setDefinition($this->applicationName . '.http', $app);
+ $container->getAlias($this->applicationName . '.http')->setPublic(true);
}
private function generateReadAction(string $name, string $query, ContainerBuilder $container): Reference
@@ -457,7 +423,7 @@ private function wrapHandler(string $name, ContainerBuilder $container): string
$middleware = $this->createService(
LazyLoadingMiddleware::class,
[
- new Reference($this->applicationName . '.http.middleware_container'),
+ new Reference(MiddlewareContainer::class),
$name . '.handler',
]
);
@@ -492,7 +458,7 @@ public function createOnly(string $routeServiceId, array $route, ContainerBuilde
$this->generateWriteAction($routeServiceId . '.action', $route['command'], $container),
new Reference(ResponseFactoryInterface::class),
$route['redirect_to'],
- new Reference($this->applicationName . '.http.uri_generator'),
+ new Reference(UriGeneratorInterface::class),
new Reference(IdentifierGenerator::class),
$route['async'] === true ? StatusCode::STATUS_ACCEPTED : StatusCode::STATUS_CREATED,
]
@@ -513,7 +479,7 @@ public function createAndFetch(string $routeServiceId, array $route, ContainerBu
$this->generateReadAction($routeServiceId . '.read_action', $route['query'], $container),
new Reference(ResponseFactoryInterface::class),
$route['redirect_to'],
- new Reference($this->applicationName . '.http.uri_generator'),
+ new Reference(UriGeneratorInterface::class),
new Reference(IdentifierGenerator::class),
]
);
@@ -564,4 +530,22 @@ public function noBehavior(string $routeServiceId, array $route, ContainerBuilde
return $this->wrapHandler($routeServiceId, $container);
}
+
+ /**
+ * @param string|mixed[] $default
+ *
+ * @return mixed[]|string
+ */
+ private function readBCParameter(ContainerBuilder $container, string $legacyName, string $parameterName, $default)
+ {
+ if ($container->hasParameter($legacyName)) {
+ return '%' . $legacyName . '%';
+ }
+
+ if ($container->hasParameter($parameterName)) {
+ return '%' . $parameterName . '%';
+ }
+
+ return $default;
+ }
}
diff --git a/src/Routing/Mezzio/RegisterServices.php b/src/Routing/Mezzio/RegisterServices.php
index 3adbc42e..2413ad3f 100644
--- a/src/Routing/Mezzio/RegisterServices.php
+++ b/src/Routing/Mezzio/RegisterServices.php
@@ -9,29 +9,28 @@
use Chimera\ExecuteQuery;
use Chimera\IdentifierGenerator;
use Chimera\MessageCreator;
+use Chimera\Routing\Application as ApplicationInterface;
use Chimera\Routing\Handler\CreateAndFetch;
use Chimera\Routing\Handler\CreateOnly;
use Chimera\Routing\Handler\ExecuteAndFetch;
use Chimera\Routing\Handler\ExecuteOnly;
use Chimera\Routing\Handler\FetchOnly;
use Chimera\Routing\Mezzio\Application;
-use Chimera\Routing\Mezzio\UriGenerator;
use Chimera\Routing\MissingRouteDispatching;
use Chimera\Routing\RouteParamsExtraction;
+use Chimera\Routing\UriGenerator as UriGeneratorInterface;
use Fig\Http\Message\StatusCodeInterface as StatusCode;
-use Laminas\Diactoros\ServerRequestFactory;
-use Laminas\HttpHandlerRunner\Emitter\EmitterInterface;
+use InvalidArgumentException;
use Laminas\HttpHandlerRunner\RequestHandlerRunner;
use Laminas\Stratigility\Middleware\PathMiddlewareDecorator;
use Laminas\Stratigility\MiddlewarePipe;
use Lcobucci\ContentNegotiation\ContentTypeMiddleware;
use Lcobucci\ContentNegotiation\Formatter\Json;
-use Mezzio\Application as Expressive;
+use Mezzio\Application as Mezzio;
use Mezzio\Helper\BodyParams\BodyParamsMiddleware;
use Mezzio\Middleware\LazyLoadingMiddleware;
use Mezzio\MiddlewareContainer;
use Mezzio\MiddlewareFactory;
-use Mezzio\Response\ServerRequestErrorResponseGenerator;
use Mezzio\Router\FastRouteRouter;
use Mezzio\Router\Middleware\DispatchMiddleware;
use Mezzio\Router\Middleware\ImplicitHeadMiddleware;
@@ -39,13 +38,13 @@
use Mezzio\Router\Middleware\MethodNotAllowedMiddleware;
use Mezzio\Router\Middleware\RouteMiddleware;
use Mezzio\Router\RouteCollector;
+use Mezzio\Router\RouterInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
-use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use function array_combine;
@@ -95,13 +94,13 @@ public function process(ContainerBuilder $container): void
$this->registerApplication(
$container,
- $routes[$this->applicationName] ?? [],
- $this->prioritiseMiddleware($middlewareList[$this->applicationName] ?? [])
+ $routes ?? [],
+ $this->prioritiseMiddleware($middlewareList ?? [])
);
}
/**
- * @return string[][][]
+ * @return string[][]
*
* @throws InvalidArgumentException
*/
@@ -135,12 +134,10 @@ private function extractRoutes(ContainerBuilder $container): array
$tag['methods'] = explode(',', $tag['methods']);
}
- $tag['app'] ??= $this->applicationName;
$tag['async'] = (bool) ($tag['async'] ?? false);
$tag['serviceId'] = $serviceId;
- $routes[$tag['app']] ??= [];
- $routes[$tag['app']][] = $tag;
+ $routes[] = $tag;
$names[$tag['route_name']] = $serviceId;
}
@@ -163,31 +160,26 @@ private function extractMiddlewareList(ContainerBuilder $container): array
$priority = $tag['priority'] ?? 0;
$path = $tag['path'] ?? '/';
- $tag['app'] ??= $this->applicationName;
-
- $list[$tag['app']][$priority][$path] ??= [];
- $list[$tag['app']][$priority][$path][] = $serviceId;
+ $list[$priority][$path] ??= [];
+ $list[$priority][$path][] = $serviceId;
}
}
- $list[$this->applicationName][Priorities::CONTENT_NEGOTIATION]['/'] ??= [];
- $list[$this->applicationName][Priorities::BEFORE_CUSTOM]['/'] ??= [];
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'] ??= [];
+ $list[Priorities::CONTENT_NEGOTIATION]['/'] ??= [];
+ $list[Priorities::BEFORE_CUSTOM]['/'] ??= [];
+ $list[Priorities::AFTER_CUSTOM]['/'] ??= [];
- $list[$this->applicationName][Priorities::CONTENT_NEGOTIATION]['/'][] = $this->applicationName
- . '.http.middleware.content_negotiation';
+ $list[Priorities::CONTENT_NEGOTIATION]['/'][] = ContentTypeMiddleware::class;
- $list[$this->applicationName][Priorities::BEFORE_CUSTOM]['/'][] = $this->applicationName
- . '.http.middleware.route';
- $list[$this->applicationName][Priorities::BEFORE_CUSTOM]['/'][] = BodyParamsMiddleware::class;
+ $list[Priorities::BEFORE_CUSTOM]['/'][] = RouteMiddleware::class;
+ $list[Priorities::BEFORE_CUSTOM]['/'][] = BodyParamsMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = $this->applicationName
- . '.http.middleware.implicit_head';
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = ImplicitOptionsMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = MethodNotAllowedMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = RouteParamsExtraction::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = DispatchMiddleware::class;
- $list[$this->applicationName][Priorities::AFTER_CUSTOM]['/'][] = MissingRouteDispatching::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = ImplicitHeadMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = ImplicitOptionsMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = MethodNotAllowedMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = RouteParamsExtraction::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = DispatchMiddleware::class;
+ $list[Priorities::AFTER_CUSTOM]['/'][] = MissingRouteDispatching::class;
return $list;
}
@@ -245,15 +237,23 @@ private function registerApplication(
array $routes,
array $middlewareList
): void {
+ if ($container->hasDefinition(ApplicationInterface::class)) {
+ throw new InvalidArgumentException('Registering multiple applications is deprecated.');
+ }
+
$services = [];
+ $aliases = []; // for BC
foreach ($routes as $route) {
// @phpstan-ignore-next-line
$services[] = $this->{self::BEHAVIORS[$route['behavior']]['callback']}(
- $this->applicationName . '.http.route.' . $route['route_name'],
+ 'http.route.' . $route['route_name'],
$route,
$container
);
+
+ $aliases[$this->applicationName . '.http.route.' . $route['route_name']]
+ = 'http.route.' . $route['route_name'];
}
$middleware = [];
@@ -282,16 +282,12 @@ private function registerApplication(
// -- middleware container
$middlewareContainer = $this->createService(MiddlewareContainer::class, [$locator]);
- $container->setDefinition($this->applicationName . '.http.middleware_container', $middlewareContainer);
+ $container->setDefinition(MiddlewareContainer::class, $middlewareContainer);
+ $aliases[$this->applicationName . '.http.middleware_container'] = MiddlewareContainer::class;
// -- middleware factory
- $middlewareFactory = $this->createService(
- MiddlewareFactory::class,
- [new Reference($this->applicationName . '.http.middleware_container')]
- );
-
- $container->setDefinition($this->applicationName . '.http.middleware_factory', $middlewareFactory);
+ $aliases[$this->applicationName . '.http.middleware_factory'] = MiddlewareFactory::class;
// -- middleware pipeline
@@ -301,28 +297,28 @@ private function registerApplication(
$middlewarePipeline->addMethodCall('pipe', [new Reference($service)]);
}
- $container->setDefinition($this->applicationName . '.http.middleware_pipeline', $middlewarePipeline);
+ $container->setDefinition(MiddlewarePipe::class, $middlewarePipeline);
+ $aliases[$this->applicationName . '.http.middleware_pipeline'] = MiddlewarePipe::class;
// -- routing
- $appRouterConfig = $container->hasParameter($this->applicationName . '.router_config')
- ? '%' . $this->applicationName . '.router_config%'
- : [];
-
- $router = $this->createService(FastRouteRouter::class, [null, null, $appRouterConfig]);
-
- $container->setDefinition($this->applicationName . '.http.router', $router);
-
- $uriGenerator = $this->createService(
- UriGenerator::class,
- [new Reference($this->applicationName . '.http.router')]
+ $router = $this->createService(
+ FastRouteRouter::class,
+ [
+ null,
+ null,
+ $this->readBCParameter($container, $this->applicationName . '.router_config', 'router_config', []),
+ ]
);
- $container->setDefinition($this->applicationName . '.http.uri_generator', $uriGenerator);
+ $container->setDefinition(FastRouteRouter::class, $router);
+ $container->setAlias(RouterInterface::class, FastRouteRouter::class);
+ $aliases[$this->applicationName . '.http.router'] = FastRouteRouter::class;
+ $aliases[$this->applicationName . '.http.uri_generator'] = UriGeneratorInterface::class;
$routeCollector = $this->createService(
RouteCollector::class,
- [new Reference($this->applicationName . '.http.router')]
+ [new Reference(FastRouteRouter::class)]
);
foreach ($routes as $route) {
@@ -330,31 +326,17 @@ private function registerApplication(
'route',
[
$route['path'],
- new Reference($this->applicationName . '.http.route.' . $route['route_name']),
+ new Reference('http.route.' . $route['route_name']),
$route['methods'] ?? self::BEHAVIORS[$route['behavior']]['methods'],
$route['route_name'],
]
);
}
- $container->setDefinition($this->applicationName . '.http.route_collector', $routeCollector);
-
- $routingMiddleware = $this->createService(
- RouteMiddleware::class,
- [new Reference($this->applicationName . '.http.router')]
- );
-
- $container->setDefinition($this->applicationName . '.http.middleware.route', $routingMiddleware);
-
- $implicitHeadMiddleware = $this->createService(
- ImplicitHeadMiddleware::class,
- [
- new Reference($this->applicationName . '.http.router'),
- [new Reference(StreamFactoryInterface::class), 'createStream'],
- ]
- );
-
- $container->setDefinition($this->applicationName . '.http.middleware.implicit_head', $implicitHeadMiddleware);
+ $container->setDefinition(RouteCollector::class, $routeCollector);
+ $aliases[$this->applicationName . '.http.route_collector'] = RouteCollector::class;
+ $aliases[$this->applicationName . '.http.middleware.route'] = RouteMiddleware::class;
+ $aliases[$this->applicationName . '.http.middleware.implicit_head'] = ImplicitHeadMiddleware::class;
// -- content negotiation
@@ -371,13 +353,15 @@ private function registerApplication(
$formatters['application/problem+json'] = new Reference(Json::class);
}
- $applicationAllowedFormats = $this->applicationName . '.allowed_formats';
-
$negotiator = $this->createService(
ContentTypeMiddleware::class,
[
- $container->hasParameter($applicationAllowedFormats) ? '%' . $applicationAllowedFormats . '%'
- : '%chimera.default_allowed_formats%',
+ $this->readBCParameter(
+ $container,
+ $this->applicationName . '.allowed_formats',
+ 'allowed_formats',
+ '%chimera.default_allowed_formats%'
+ ),
$formatters,
new Reference(StreamFactoryInterface::class),
]
@@ -385,39 +369,23 @@ private function registerApplication(
$negotiator->setFactory([ContentTypeMiddleware::class, 'fromRecommendedSettings']);
- $container->setDefinition($this->applicationName . '.http.middleware.content_negotiation', $negotiator);
-
- // --- request handler runner
+ $container->setDefinition(ContentTypeMiddleware::class, $negotiator);
+ $aliases[$this->applicationName . '.http.middleware.content_negotiation'] = ContentTypeMiddleware::class;
+ $aliases[$this->applicationName . '.http.request_handler_runner'] = RequestHandlerRunner::class;
- $requestHandlerRunner = $this->createService(
- RequestHandlerRunner::class,
- [
- new Reference($this->applicationName . '.http.middleware_pipeline'),
- new Reference(EmitterInterface::class),
- [ServerRequestFactory::class, 'fromGlobals'],
- new Reference(ServerRequestErrorResponseGenerator::class),
- ]
- );
+ $app = new Definition(Application::class, [new Reference(Mezzio::class)]);
+ $app->setPublic(true);
- $container->setDefinition($this->applicationName . '.http.request_handler_runner', $requestHandlerRunner);
+ $container->setDefinition(ApplicationInterface::class, $app);
+ $aliases[$this->applicationName . '.http'] = ApplicationInterface::class;
- $container->setDefinition(
- $this->applicationName . '.http_expressive',
- new Definition(
- Expressive::class,
- [
- new Reference($this->applicationName . '.http.middleware_factory'),
- new Reference($this->applicationName . '.http.middleware_pipeline'),
- new Reference($this->applicationName . '.http.route_collector'),
- new Reference($this->applicationName . '.http.request_handler_runner'),
- ]
- )
- );
-
- $app = new Definition(Application::class, [new Reference($this->applicationName . '.http_expressive')]);
- $app->setPublic(true);
+ foreach ($aliases as $alias => $service) {
+ $container->setAlias($alias, $service)->setDeprecated('chimera/di-symfony', '0.5.0', null);
+ }
- $container->setDefinition($this->applicationName . '.http', $app);
+ $container->getAlias($this->applicationName . '.http')
+ ->setDeprecated('chimera/di-symfony', '0.5.0', null)
+ ->setPublic(true);
}
private function generateReadAction(string $name, string $query, ContainerBuilder $container): Reference
@@ -457,7 +425,7 @@ private function wrapHandler(string $name, ContainerBuilder $container): string
$middleware = $this->createService(
LazyLoadingMiddleware::class,
[
- new Reference($this->applicationName . '.http.middleware_container'),
+ new Reference(MiddlewareContainer::class),
$name . '.handler',
]
);
@@ -492,7 +460,7 @@ public function createOnly(string $routeServiceId, array $route, ContainerBuilde
$this->generateWriteAction($routeServiceId . '.action', $route['command'], $container),
new Reference(ResponseFactoryInterface::class),
$route['redirect_to'],
- new Reference($this->applicationName . '.http.uri_generator'),
+ new Reference(UriGeneratorInterface::class),
new Reference(IdentifierGenerator::class),
$route['async'] === true ? StatusCode::STATUS_ACCEPTED : StatusCode::STATUS_CREATED,
]
@@ -513,7 +481,7 @@ public function createAndFetch(string $routeServiceId, array $route, ContainerBu
$this->generateReadAction($routeServiceId . '.read_action', $route['query'], $container),
new Reference(ResponseFactoryInterface::class),
$route['redirect_to'],
- new Reference($this->applicationName . '.http.uri_generator'),
+ new Reference(UriGeneratorInterface::class),
new Reference(IdentifierGenerator::class),
]
);
@@ -564,4 +532,22 @@ public function noBehavior(string $routeServiceId, array $route, ContainerBuilde
return $this->wrapHandler($routeServiceId, $container);
}
+
+ /**
+ * @param string|mixed[] $default
+ *
+ * @return mixed[]|string
+ */
+ private function readBCParameter(ContainerBuilder $container, string $legacyName, string $parameterName, $default)
+ {
+ if ($container->hasParameter($legacyName)) {
+ return '%' . $legacyName . '%';
+ }
+
+ if ($container->hasParameter($parameterName)) {
+ return '%' . $parameterName . '%';
+ }
+
+ return $default;
+ }
}
diff --git a/src/ValidateApplicationComponents.php b/src/ValidateApplicationComponents.php
index 8f4a60ef..f473f656 100644
--- a/src/ValidateApplicationComponents.php
+++ b/src/ValidateApplicationComponents.php
@@ -3,6 +3,7 @@
namespace Chimera\DependencyInjection;
+use Chimera\Routing\Application;
use RuntimeException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -22,9 +23,10 @@ public function __construct(string $appName)
/** @throws InvalidArgumentException */
public function process(ContainerBuilder $container): void
{
- $httpInterface = $container->getDefinition($this->appName . '.http');
+ $httpInterface = $container->getDefinition(Application::class);
+ $alias = $container->getAlias($this->appName . '.http');
- if (! $httpInterface->isPublic()) {
+ if (! $httpInterface->isPublic() || ! $alias->isPublic()) {
throw new RuntimeException(
sprintf('The HTTP interface for "%s" is not a public service', $this->appName)
);
diff --git a/tests/Functional/ApplicationTestCase.php b/tests/Functional/ApplicationTestCase.php
index 6b3d6cde..882d167f 100644
--- a/tests/Functional/ApplicationTestCase.php
+++ b/tests/Functional/ApplicationTestCase.php
@@ -44,11 +44,6 @@ final protected function createContainer(): ContainerInterface
$builder->addPass(
$this->makeServicesPublic(
[
- 'sample-app.http.route_collector',
- 'sample-app.http.middleware_pipeline',
- 'sample-app.http.middleware.content_negotiation',
- 'sample-app.http.middleware.route',
- 'sample-app.http.middleware.implicit_head',
'sample-app.command_bus',
'sample-app.command_bus.decorated_bus',
'sample-app.command_bus.decorated_bus.handler',
@@ -70,6 +65,11 @@ final protected function createContainer(): ContainerInterface
ErrorConversionMiddleware::class,
],
[
+ 'sample-app.http.route_collector',
+ 'sample-app.http.middleware_pipeline',
+ 'sample-app.http.middleware.content_negotiation',
+ 'sample-app.http.middleware.route',
+ 'sample-app.http.middleware.implicit_head',
'sample-app.command_bus.decorated_bus.handler.locator',
'sample-app.query_bus.decorated_bus.handler.locator',
]
diff --git a/tests/Unit/Routing/Expressive/RegisterServicesTest.php b/tests/Unit/Routing/Expressive/RegisterServicesTest.php
index 9eadccd0..a91172c4 100644
--- a/tests/Unit/Routing/Expressive/RegisterServicesTest.php
+++ b/tests/Unit/Routing/Expressive/RegisterServicesTest.php
@@ -40,4 +40,36 @@ public function exceptionShouldBeRaisedWhenTryingToRegisterDuplicatedRoutes(): v
);
$registerServices->process($builder);
}
+
+ /**
+ * @test
+ *
+ * @covers ::__construct
+ * @covers ::createService
+ * @covers ::extractMiddlewareList
+ * @covers ::extractRoutes
+ * @covers ::prioritiseMiddleware
+ * @covers ::process
+ * @covers ::readBCParameter
+ * @covers ::registerApplication
+ * @covers ::registerServiceLocator
+ */
+ public function registeringServicesDoesNotAllowMultipleApplications(): void
+ {
+ $container = new ContainerBuilder();
+
+ $this->createRegisterServices('testing1')->process($container);
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->createRegisterServices('testing2')->process($container);
+ }
+
+ private function createRegisterServices(string $applicationName): RegisterServices
+ {
+ return new RegisterServices(
+ $applicationName,
+ $applicationName . '.command_bus',
+ $applicationName . '.query_bus'
+ );
+ }
}
diff --git a/tests/Unit/ValidateApplicationComponentsTest.php b/tests/Unit/ValidateApplicationComponentsTest.php
new file mode 100644
index 00000000..d2c5715a
--- /dev/null
+++ b/tests/Unit/ValidateApplicationComponentsTest.php
@@ -0,0 +1,71 @@
+setDefinition(Application::class, new Definition());
+ $builder->setAlias('sample-app.http', Application::class)->setPublic(true);
+
+ $pass = new ValidateApplicationComponents('sample-app');
+
+ $this->expectException(RuntimeException::class);
+ $this->expectErrorMessage('The HTTP interface for "sample-app" is not a public service');
+ $pass->process($builder);
+ }
+
+ /**
+ * @test
+ *
+ * @covers ::__construct
+ * @covers ::process
+ */
+ public function exceptionShouldBeRaisedWhenLegacyAliasIsNotPublic(): void
+ {
+ $builder = new ContainerBuilder();
+ $builder->setDefinition(Application::class, (new Definition())->setPublic(true));
+ $builder->setAlias('sample-app.http', Application::class);
+
+ $pass = new ValidateApplicationComponents('sample-app');
+
+ $this->expectException(RuntimeException::class);
+ $this->expectErrorMessage('The HTTP interface for "sample-app" is not a public service');
+ $pass->process($builder);
+ }
+
+ /**
+ * @test
+ *
+ * @covers ::__construct
+ * @covers ::process
+ */
+ public function noExceptionShouldBeRaisedWhenExpectedServicesArePublic(): void
+ {
+ $builder = new ContainerBuilder();
+ $builder->setDefinition(Application::class, (new Definition())->setPublic(true));
+ $builder->setAlias('sample-app.http', Application::class)->setPublic(true);
+
+ $pass = new ValidateApplicationComponents('sample-app');
+ $pass->process($builder);
+
+ $this->addToAssertionCount(1);
+ }
+}