Skip to content

The actual callable is not passed to InvocationStrategy since introduction of DeferredCallable in Slim 3.2.0 #1785

Closed

Description

@astax-t

Since introduction of DeferredCallable in Slim 3.2.0, the actual controller's callable is not given to the class implementing InvocationStrategy (the one set in $container['foundHandler'])

This makes it impossible to use reflection to find what are actual expected parameters.

I'm trying to use a custom InvocationStrategy that would match controller parameters names to route parameters - similar to the way it's done in Symfony HttpKernel. This was working in Slim 3.1.0, but not in 3.2.0.

Activity

  1. astax-t commented on Feb 28, 2016

    @astax-t
    Author

    The pull request #1783 would help to mitigate this, if accepted. I'd be able to retrieve the resolved callable and get its parameters using reflection.

    But really it would be better to call the custom InvocationStrategy from DeferredCallable instead of just passing arguments given to DeferredCallable ::__invoke()

  2. irfanevrens commented on Feb 29, 2016

    @irfanevrens
    Contributor

    I am agree with @astax-t and I also use a custon InvocationStrategy.

  3. michaelboke commented on Feb 29, 2016

    @michaelboke

    Having the same issue since 3.2 my auto wiring isn't working anymore.

    @irfanevrens i added a pull request on #1783 that now passes the resolvedCallable result to the foundHandler. Restoring the old behavior.

  4. akrabat commented on Feb 29, 2016

    @akrabat
    Member

    Can you provide an example of code that's no longer working please?

  5. astax-t commented on Feb 29, 2016

    @astax-t
    Author

    Sure. It's not the minimal code to replicate the problem, but pretty much copied from HttpFoundation:

    class CompatibilityInvocationStrategy implements InvocationStrategyInterface
    {
        public function __invoke(
            callable $callable,
            ServerRequestInterface $request,
            ResponseInterface $response,
            array $routeArguments
        )
        {
            if (is_array($callable))
            {
                $r = new \ReflectionMethod($callable[0], $callable[1]);
            } elseif (is_object($callable) && !$callable instanceof \Closure)
            {
                /** @noinspection PhpParamsInspection */
                $r = new \ReflectionObject($callable);
                $r = $r->getMethod('__invoke');
            } else
            {
                $r = new \ReflectionFunction($callable);
            }
    
            $arguments = $this->doGetArguments($request, $response, $routeArguments, $r->getParameters());
    
            $result = call_user_func_array($callable, $arguments);
    
            return $result;
        }
    
        protected function doGetArguments($request, $response, $attributes, array $parameters)
        {
            $arguments = array();
            foreach ($parameters as $param)
            {
                /** @var \ReflectionParameter $param */
                /** @var \ReflectionClass|null $class */
                $class = $param->getClass() ?: null;
                if ($class && $class->isInstance($request)) {
                    $arguments[] = $request;
                } elseif ($class && $class->isInstance($response)) {
                    $arguments[] = $response;
                } elseif (array_key_exists($param->name, $attributes)) {
                    $arguments[] = $attributes[$param->name];
                } elseif ($param->isDefaultValueAvailable()) {
                    $arguments[] = $param->getDefaultValue();
                } else {
                    throw new \RuntimeException(sprintf('Controller requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $param->name));
                }
            }
            return $arguments;
        }
    }
    

    But there is another PR to fix this problem. Maybe it's even better.

  6. akrabat commented on Feb 29, 2016

    @akrabat
    Member

    Please test 3.x and let me know if this is now solved.

  7. astax-t commented on Feb 29, 2016

    @astax-t
    Author

    Tested and is working correctly now

  8. akrabat commented on Mar 1, 2016

    @akrabat
    Member

    Version 3.2.1 released now. Thank you very much for reporting this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions