While doing work on #2555 I've noticed that App is being passed around in order to provide its proxy methods get(), post(), put(), patch(), delete(), options(), any() and map().
As seen here in App::group(), RouteGroup needs to be invoked so we can pass App to it in order for the callable to have access to the Router's proxy method:
public function group(string $pattern, $callable): RouteGroupInterface
{
$router = $this->getRouter();
/** @var RouteGroup $group */
$group = $router->pushGroup($pattern, $callable);
if ($this->callableResolver instanceof CallableResolverInterface) {
$group->setCallableResolver($this->callableResolver);
}
$group($this);
$router->popGroup();
return $group;
}
The reference flow of this is terrible, Router is in charge of handling groups, App shouldn't be. As you see here, $group($this); refers to RouteGroup::__invoke() which was just a hackish way to pass in App to the called function;
public function __invoke(App $app = null)
{
/** @var callable $callable */
$callable = $this->callable;
if ($this->callableResolver) {
$callable = $this->callableResolver->resolve($callable);
}
$callable($app);
}
What I propose is that we create a RouterProxy that App can extend and that RouteGroup can extend as well so then we don't have to pass this reference in a hackish way:
abstract class RouterProxy {
public function get(string $pattern, $callable): RouteInterface
{
return $this->map(['GET'], $pattern, $callable);
}
public function post(string $pattern, $callable): RouteInterface
{
return $this->map(['POST'], $pattern, $callable);
}
public function put(string $pattern, $callable): RouteInterface
{
return $this->map(['PUT'], $pattern, $callable);
}
public function patch(string $pattern, $callable): RouteInterface
{
return $this->map(['PATCH'], $pattern, $callable);
}
public function delete(string $pattern, $callable): RouteInterface
{
return $this->map(['DELETE'], $pattern, $callable);
}
public function options(string $pattern, $callable): RouteInterface
{
return $this->map(['OPTIONS'], $pattern, $callable);
}
public function any(string $pattern, $callable): RouteInterface
{
return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable);
}
public function map(array $methods, string $pattern, $callable): RouteInterface
{
// Bind route callable to container, if present
if ($this->container instanceof ContainerInterface && $callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}
return $this->router->map($methods, $pattern, $callable);
}
public function redirect(string $from, $to, int $status = 302): RouteInterface
{
$handler = function ($request, ResponseInterface $response) use ($to, $status) {
return $response->withHeader('Location', (string)$to)->withStatus($status);
};
return $this->get($from, $handler);
}
public function group(string $pattern, $callable): RouteGroupInterface
{
$route = $this->router->pushGroup($pattern, $callable);
$this->router->popGroup();
return $route;
}
}
This will clean up the code a lot. We can get rid of the Routable abstract class and Route will overtake all of those methods, then RouteGroup will extend the theoretical RouterProxy which will have Router injected in its constructor.
Need thoughts and comments on this.
Thanks y'all
While doing work on #2555 I've noticed that
Appis being passed around in order to provide its proxy methodsget(),post(),put(),patch(),delete(),options(),any()andmap().As seen here in
App::group(),RouteGroupneeds to be invoked so we can passAppto it in order for the callable to have access to the Router's proxy method:The reference flow of this is terrible,
Routeris in charge of handling groups,Appshouldn't be. As you see here,$group($this);refers toRouteGroup::__invoke()which was just a hackish way to pass inAppto the called function;What I propose is that we create a
RouterProxythatAppcan extend and thatRouteGroupcan extend as well so then we don't have to pass this reference in a hackish way:This will clean up the code a lot. We can get rid of the
Routableabstract class andRoutewill overtake all of those methods, thenRouteGroupwill extend the theoreticalRouterProxywhich will haveRouterinjected in its constructor.Need thoughts and comments on this.
Thanks y'all