phpslimphp-dislim-4

How to access slim4's routeParser with the PHP-DI setup demonstrated in Slim-Skeleton?


I've set up a new app based on the SlimPHP team's Slim Skeleton application. Inside of my route definitions, I want to be able to access the route parser as described in the Slim4 documentation. So, for example, I'd like to be able to edit the skeleton's app/routes.php file something like this:

    $app->get('/', function (Request $request, Response $response) {
        $routeParser = $app->getRouteCollector()->getRouteParser();  // this doesn't work
        $response->getBody()->write('Hello world! ' . $routeParser->urlFor('something'));
        return $response;
    });

It makes sense that $app->getRouteCollector()->getRouteParser() doesn't work, because $app isn't defined here. But I would think that we'd instead call $this->getRouteCollector()->getRouteParser();, but that gives the error: "Call to undefined method DI\\Container::getRouteCollector()".

It definitely seems that my confusion is about Dependency Injection, which is new for me and not coming naturally to me. I'd honestly love to define the $routeParser variable somewhere else (inside index.php?) so that I could access it in any route definition without having to call $app->getRouteCollector()->getRouteParser() every time. But at the moment I'd settle for anything that worked.


Solution

  • Slim skeleton actually demonstrate an example of what you need to achieve. After creating the App instance in index.php, there is an assignment like this:

    // Instantiate the app
    AppFactory::setContainer($container);
    $app = AppFactory::create();
    $callableResolver = $app->getCallableResolver();
    

    You can do the same:

    $routeParser = $app->getRouteCollector()->getRouteParser();
    

    And if you really need this instance of RouteParser to be available inside every route callback, you can put it in dependency container, something like:

    $container->set(Slim\Interfaces\RouteParserInterface::class, $routeParser);
    

    Then you can use PHP-DI auto-wiring feature to inject this RouteParser into controller constructor:

    use Slim\Interfaces\RouteParserInterface;
    class SampleController {
        public function __construct(RouteParserInterface $routeParser) {
            $this->routeParser = $routeParser;
            //...
        }
    }
    

    or if you need to call $container->get() inside any of your route callbacks:

    $app->get('/', function (Request $request, Response $response) {
        $routeParser = $this->get(Slim\Interfaces\RouteParserInterface::class);
        $response->getBody()->write('Hello world! ' . $routeParser->urlFor('something'));
        return $response;
    });