middlewares / utils

Common utils used by PSR-15 middlewares
MIT License
51 stars 12 forks source link

Error when trying to use an object & method as a handler #25

Open mav2287 opened 3 years ago

mav2287 commented 3 years ago

I am trying to register a route with fast route using an Object and static method with the following code:

static public function registerRoute( RouteCollector &$r ): void {
  $r->addRoute(['GET', 'OPTIONS'], '/password', array( self::class, 'renderChallenge') );
}

instead of the handler being called I instead get the following error message:

Argument 1 passed to Middlewares\Utils\CallableHandler::__construct() must be callable, object given, called in /src/vendor/middlewares/utils/src/RequestHandlerContainer.php on line 51

In the course of trying to debug I decided to test if what I was passing was callable using the following:

// Regular function to check if something is callable
function isThisCallable( callable $callable  ) {
    call_user_func( $callable );
}

// Modified code from above
static public function registerRoutes( RouteCollector &$r ): void {
    $r->addRoute(['GET', 'OPTIONS'], '/password', function() {
       isThisCallable( array(static::class, 'renderChallenge') );
    } );
}

This test code ran as expected and called the static object's method. Is this a bug or is there another way I should be passing an object and method as the handler?

oscarotero commented 3 years ago

The CallableHandler class is not receiving a callable element. Can I see the code including how are the middlewares implemented?

mav2287 commented 3 years ago

After doing some additional testing the only ways I have found to make a static method call are by setting the handler to __CLASS__."::loginRedirect_renderChallenge" or invoking a new instance of the class, array( new self, "loginRedirect_renderChallenge" ). In terms of a static method call via an array I have yet to find anything that works other than invoking a new instance of the class. I also did a quick check and replaced self::class with the full name of the class array( 'namespace\Class', 'renderChallenge'), but still got the same error.

Below is how the Middlewares are implemented

// Emitter for response
$middlewares[] = new Middlewares\Emitter();

// Redirect to https
$middlewares[] = ( new Middlewares\Https() )->includeSubdomains();

// remove www
$middlewares[] = new Middlewares\Www(false);

// Removes the trailing slash
$middlewares[] = new Middlewares\TrailingSlash(false);

// Save the client ip in the '_ip' attribute
$middlewares[] = (new Middlewares\ClientIp())
    ->attribute('_client-ip');

// Log the request
/** @var Monolog\Logger $logger */
$middlewares[] = (new Middlewares\AccessLog( $GLOBALS['AccessLogger'] ) )
    ->ipAttribute('_client-ip');

// Negotiate the language
$middlewares[] = new Middlewares\ContentLanguage([ 'en', 'gl', 'es' ]);

// Handle Error Responses
$middlewares[] = new Middlewares\ErrorResponse();

// Negotiate the content-type
$middlewares[] = new Middlewares\ContentType();

// CORS Analyzer
/** @var Neomerx\Cors\Analyzer $CORS_analyzer */
$middlewares[] = new Middlewares\Cors( $GLOBALS['CORS_analyzer'] );

// Insert the X-Uuid header of the request and response. Useful for debugging purposes.
$middlewares[] = new Middlewares\Uuid();

// Calculate the response time
$middlewares[] = new Middlewares\ResponseTime();

// Add cache expiration headers
$middlewares[] = new Middlewares\CachePrevention();

// Sets header to disable robots
$middlewares[] = new Middlewares\Robots(false);

//Parse the json payload
$middlewares[] = new Middlewares\JsonPayload();

//Parse the urlencoded payload
$middlewares[] = new Middlewares\UrlEncodePayload();

// Set the route via fast-route
/** @var FastRoute\Dispatcher\GroupCountBased $router */
$middlewares[] = new Middlewares\FastRoute( $GLOBALS['router'] );

//Calls the callable handler from FastRoute
$middlewares[] = new Middlewares\RequestHandler();

$response = ( new Middlewares\Utils\Dispatcher( $middlewares ) )
    ->dispatch( Zend\Diactoros\ServerRequestFactory::fromGlobals() );
oscarotero commented 3 years ago

This is the code of RequestHandler middleware that decided how to handle your callable: https://github.com/middlewares/request-handler/blob/master/src/RequestHandler.php#L75

If it's a string (your case now), seems to work fine.

If it's an array (like your previous case Array(static::class, 'renderChallenge')) it enter here (https://github.com/middlewares/request-handler/blob/master/src/RequestHandler.php#L80) and try to get the class instance from the container. The class you're providing can be instantiated? or is static?

mav2287 commented 3 years ago

The class can be instantiated the method it is calling is static.

oscarotero commented 3 years ago

Ok, I'll take a look. Thanks