1

Zend Expressive has an adapters for Aura.Router, FastRoute and zend-mvc Router and the route can match the method and path easily:

<?php
$app->get('/foo', $middleware);

With zend-mvc Router component it is possible to match the hostname:

<?php
use Zend\Mvc\Router\Http\Hostname;

$route = Hostname::factory([
    'route' => ':subdomain.example.com/foo',
    'constraints' => [
        'subdomain' => 'api',
    ],
]);

$router->addRoute('foo', $route);

This is also possible with Symfony Routing Component:

<?php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$route = new Route(
    '/foo', // path
    array('_controller' => 'SomeController'), // default values
    array('subdomain' => 'api'), // requirements
    array(), // options
    '{subdomain}.example.com', // host
    array(), // schemes
    array() // methods
);

$routes = new RouteCollection();
$routes->add('foo', $route);

So, I would like to be able to do something similar with Expressive, and to dispatch the request to a different middleware depending on the subdomain:

// dispatch the requiest to ApiMiddleware
$app->get(':subdomain.example.com/foo', $ApiMiddleware, ['subdomain' => 'api']);

// dispatch the requiest to WebMiddleware
$app->get(':subdomain.example.com/foo', $WebMiddleware, ['subdomain' => 'www']);

Thanks in advance!

Vasil Dakov
  • 2,040
  • 2
  • 19
  • 38
  • 1
    I don't think any of the routers support that. What you could do is write your own bridge for the Symfony Router component. It has some nice features that the others are missing. – xtreamwayz Feb 02 '17 at 06:17
  • There is [PR](https://github.com/zendframework/zend-expressive/pull/370]) for hostname routing – venca Feb 03 '17 at 06:14

1 Answers1

2

Why did you not create a new middleware for extracting the request and choose which middleware should be called in the pipeline next?

You could do something like that:

Application\Middleware\DeciderMiddleware

<?php

namespace Application\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class DeciderMiddleware
{
    protected $apiMiddleware;
    protected $webMiddleware;

    public function __construct(
        callable $apiMiddleware,
        callable $webMiddleware
    ) {
        $this->apiMiddleware = $apiMiddleware;
        $this->webMiddleware = $webMiddleware;
    }

    public function __invoke(
        ServerRequestInterface $request,
        ResponseInterface $response,
        callable $next = null
    ) {
        if (strpos($request->getUri()->getHost(), 'api.') === 0) {
            return ($this->apiMiddleware)($request, $response);
        }

        if (strpos($request->getUri()->getHost(), 'www.') === 0) {
            return ($this->webMiddleware)($request, $response);
        }

        return $next($request, $response);
    }
}

config/autoload/middleware-pipeline.global.php

<?php

return [
    'dependencies' => [
        'factories' => [
            Application\Middleware\DeciderMiddleware::class => Application\Middleware\DeciderMiddlewareFactory::class
        ],
    ],
    'middleware_pipeline' => [
        'always' => [
            'middleware' => [
                Application\Middleware\DeciderMiddleware::class
            ],
            'priority' => 10000,
        ],
    ],
];

The only thing you have to do is to define the apiMiddleware and the webMiddleware in the DeciderMiddlewareFactory and initialize the DeciderMiddleware-object with these parameters.

GreedyBytes
  • 101
  • 6