middlewares / ideas

Need a Middleware or looking for ideas?
5 stars 0 forks source link

`callable` utils #1

Open schnittstabil opened 7 years ago

schnittstabil commented 7 years ago

I'm planning to create 4 middleware related projects, allowing clients to additional deal with callable middlewares:

  1. middleware/is-delegate
  2. middleware/is-middleware
  3. middleware/to-delegate, casting/adapting DelegateInterface instances and callable delegates to DelegateInterface instances.
  4. middleware/to-middleware, casting/adapting MiddlewareInterface instances and callable delegates to MiddlewareInterface instances.

I'm always shilly shally about project names. For example:

@middlewares/contributors Thoughts are welcome.

oscarotero commented 7 years ago

I'm not sure if this is a good idea because I see the use of callable as a feature implementation. For example, I have this middleware dispatcher with some features like support of callables, container-interop, nested middlewares, etc... IMHO, the support of callables is another feature, not special or more important than others, due the ability to instantiate anonimous classes in php7, opening a new way to do the same, but safety (and better). I just use closures when I'm too lazy to respect the psr-15 interface signature :D

schnittstabil commented 7 years ago

I see the use of callable as a feature implementation.

That is exactly its purpose. It allows middleware dispatchers to easily implement a callable feature, thus they do not need to reinvent the wheel. In addition, consumers of middleware dispatchers which do not provide a callable feature, can easily reuse their already existing closures.

And more importantly, they do not have to test that feature…

oscarotero commented 7 years ago

Yes but I mean that you're using a 1:1 convert. This callable works:

$callable = function (ServerRequestInterface $request, DelegateInterface $delegate) {
    return $delegate->process($request);
}

but a more lazy typed callable doesn't:

$callable = function ($request, $delegate) {
    return $delegate->process($request);
}

And for me, it's more confortable use callables to create lazy middlewares, for testing purposes or for minor operations, because if I need strong typing, I can do this:

$middleware = new class () implements MiddlewareInterface
{
    public function (ServerRequestInterface $request, DelegateInterface $delegate) {
        return $delegate->process($request);
    }
}

That it's faster than callables (because there's no need to create wrappers or use Reflections). Of course, this only works in php7, but I think is the primary focus.

schnittstabil commented 7 years ago

I understand your point of view. But, for example the is_middleware may look like that:

function is_middleware($var, bool $strict)
{
    /* short circuit for interface implementers */
    if ($var instanceof MiddlewareInterface) {
        return true;
    }

    if (! is_callable($var)) {
        return false;
    }

    if (! $strict) {
        return true;
    }

    // use reflection
    …
}

If we think about middleware frameworks, then I can imagine a usage like this:

class App
{
    public function get(string $route, $middleware)
    {
        $middleware = to_middleware($middleware, $this->debug); // throw an exception in case of non-middleware
        …
    }
    …
}

This means we can type-check early:

$app = new \App([
   'debug' => true,
]);

// this uses reflection:
$app->get('/hello/{name}', function (ServerRequestInterface $request, DelegateInterface $delegate) {
    …
});

// this doesn't uses reflection:
$app->get('/hello/{name}', new ContactMiddleware());

$app->run();

Well, that all depends on the features a concrete framework wants to provide. If you feel that this does not fit to http://github.com/middlewares, then I will create it at http://github.com/schnittstabil – that wouldn't be a tragedy :wink:

oscarotero commented 7 years ago

I think this organization should focus mostly in creating psr-15 middleware packages that everybody can consume, instead packages for frameworks or other implementations. For this kind of utilities, we have a middlewares/utils package, so if you like, you can add this feature as a static class. For example:

use Middlewares\Utils\CallableValidator;

$valid = CallableValidator::isMiddleware($callable);

As you can see, there's a CallableMiddleware, a Dispatcher and a Delegate, so you can reuse this classes to create the toDelegate and toMiddleware functions.

schnittstabil commented 7 years ago

:+1: middlewares/utils seems the right place to provide such features.