PHP-DI / Slim-Bridge

PHP-DI integration with the Slim framework
http://php-di.org/doc/frameworks/slim.html
MIT License
176 stars 38 forks source link

Error when I add PSR-15 middleware with class string #61

Closed ghost closed 4 years ago

ghost commented 4 years ago

When I add PSR-15 middleware on Slim (with Bridge) with class string, the following error appears:

Fatal error: Uncaught Invoker\Exception\NotCallableException: Instance of App\Middleware\ExampleMiddleware is not a callable in C:\Users\Ashura\Desktop\Projetos\ignitor\vendor\php-di\invoker\src\Exception\NotCallableException.php:33 

Stack trace: 
#0 C:\Users\Ashura\Desktop\Projetos\ignitor\vendor\php-di\invoker\src\CallableResolver.php(44): Invoker\Exception\NotCallableException::fromInvalidCallable(Object(App\Middleware\ExampleMiddleware), true) 
#1 C:\Users\Ashura\Desktop\Projetos\ignitor\vendor\php-di\slim-bridge\src\CallableResolver.php(26): Invoker\CallableResolver->resolve(Object(App\Middleware\ExampleMiddleware))
#2 C:\Users\Ashura\Desktop\Projetos\ignitor\vendor\slim\slim\Slim\MiddlewareDispatcher.php(195): DI\Bridge\Slim\CallableResolver->resolve('App\\Middleware\\...') 
#3 C:\Users\Ashura\Desktop\Projetos\ignitor\vendor\selective\basepath\src\BasePathMiddleware.php(52): class@anonymous->handle(Object(Slim\Http\ServerRequest)) 
#4 C:\Users\Ashura\Desktop\Projetos\ignitor\vendor\slim\slim\Slim\MiddlewareDispatcher.php in C:\Users\Ashura\Desktop\Projetos\ignitor\vendor\php-di\invoker\src\Exception\NotCallableException.php on line 33

Code:

<?php

// config/middleware.php

$app->add(ExampleMiddleware::class);

// ExampleMiddleware.php
namespace App\Middleware;

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Server\MiddlewareInterface;

class ExampleMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        return $handler->handle($request);
    }
}

But when I add middleware as invokable class the middleware works:

<?php

namespace App\Middleware;

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

class ExampleMiddleware
{
    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        return $handler->handle($request);
    }
}
mnapoli commented 4 years ago

I think $app->add(ExampleMiddleware::class); should be $app->add([ExampleMiddleware::class, 'process']); instead 🤔

ghost commented 4 years ago

With this format of array, is giving me this error:

Fatal error: Uncaught Error: Using $this when not in object context in C:\Users\thelu\Desktop\tests\index.php:26 
Stack trace: 
#0 C:\Users\thelu\Desktop\tests\vendor\slim\slim\Slim\MiddlewareDispatcher.php(283): ExampleMiddleware::process(Object(Slim\Psr7\Request), Object(Slim\Routing\RouteRunner)) 
#1 C:\Users\thelu\Desktop\tests\vendor\slim\slim\Slim\Middleware\RoutingMiddleware.php(60): class@anonymous->handle(Object(Slim\Psr7\Request)) 
#2 C:\Users\thelu\Desktop\tests\vendor\slim\slim\Slim\MiddlewareDispatcher.php(140): Slim\Middleware\RoutingMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) 
#3 C:\Users\thelu\Desktop\tests\vendor\slim\slim\Slim\MiddlewareDispatcher.php(81): class@anonymous->handle(Object(Slim\Psr7\Request)) 
#4 C:\Users\thelu\Desktop\tests\vendor\slim\slim\Slim\App.php(215): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) 
#5 C:\Users\thelu\Desktop\tests\vendor\slim\slim\Slim\App.php(199): Slim\App->handle(Object(Slim\Psr7\Request)) 
#6 C:\Users\thelu\Desktop\tests\index.p in C:\Users\thelu\Desktop\tests\index.php on line 26

Code:

// Middleware
use Psr\Http\Server\MiddlewareInterface as Middleware;
use Psr\Http\Message\ServerRequestInterface as ServerRequest;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Psr\Http\Message\ResponseInterface as Response;

class ExampleMiddleware implements Middleware
{
    public function __construct(Foo $foo)
    {
        $this->foo = $foo;
    }

    public function process(ServerRequest $request, RequestHandler $handler): Response
    {
        $response = $handler->handle($request);

        $response->getBody()->write($this->foo->hello());

        return $response;
    }
}

// config/middleware.php
$app->add([ExampleMiddleware::class, 'process']);
jDolba commented 4 years ago

you should pass MIddlewareInterface instance so with PHP-DI bridge you should use Container for passing instancefor middleware

eg.

$app->add( $container->get(ExampleMiddleware::class) );

or the Slim way to register middleware/route should be with method-to-call string definition (I do not prefer this one so not 100% sure)

$app->add(ExampleMiddleware::class . '::process');
ghost commented 4 years ago

With Middleware::class . '::process' syntax I can successfully add the middleware, thanks guys.

I think it would be nice to also support this method for adding Slim middleware:

$app->add(ExampleMiddleware::class);

I think I can try to add this method and send a PR. Thanks :)

Rarst commented 3 years ago

Duplicates #51, trying to get that and related stuff work. :)