Question

I recently wrote a post about request forwarding in Silex, which used a blog example to explain sub requests in Silex.

I use a slightly modified version of this example for a domain controller. The path to the domain endpoint = /product/domain

A domain can also have a webhosting package attached to it. The url path for this endpoint would be /product/domain/(id)/webhosting/

You can fetch info about a webhosting package by using the url path. The url path for this endpoint would be /product/domain/(id)/webhosting/(id)

To handle these sub requests, I have a method called forwardRequest, which has no parameters in it's method signature, but uses func_get_args to keep it dynamic.

Unfortunately this doesn't work as Silex uses the named parameters in your route to call your method. So if you have /product/domain/domain_id/webhosting/webhosting_id, your method should have a signature of method($domain_id, $webhosting_id), which is a PITA if you want to forward multiple endpoints through one method. If you have additional /product/domain/domain_id/emailhosting and /product/domain/domain_id/dns endpoints, you have to create a method for each in order to forward the request.

Does anyone have a solution in which I can use only 1 method to forward all these sub requests?

Note: I'm using PHP 5.3.

Was it helpful?

Solution

The part of silex that decides which arguments to pass to the controller is called the "controller resolver". The default controller resolver uses reflection. You can override the controller_resolver service with a custom implementation though.

Defining a custom controller resolver that wraps the existing one but replaces the arguments with a single one, the request:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;

class RequestArgumentControllerResolver implements ControllerResolverInterface
{
    protected $resolver;

    public function __construct(ControllerResolverInterface $resolver)
    {
        $this->resolver = $resolver;
    }

    public function getController(Request $request)
    {
        return $this->resolver->getController($request, $controller);
    }

    public function getArguments(Request $request, $controller)
    {
        return [$request];
    }
}

Extend the existing controller resolver with the newly defined decorator:

$app['controller_resolver'] = $app->share($app->extend('controller_resolver', function ($resolver, $app) {
    return new RequestArgumentControllerResolver($resolver);
}));

Note: This is just one way of doing it. You don't have to decorate, you can also replace the resolver completely if you like. And obviously this is just a very basic example of only passing a single arg to the controller, you can do something more sophisticated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top