, (*1)
Germania KG · RouteNameUrlCallable
Callable for generating full URLs using Slim 4's RouteContext and RouteParser. Works well as Twig function., (*2)
, (*3)
Installation with Composer
This package requires Slim Framework 4. For using Slim Framework 3, checkout the v1 branch., (*4)
$ composer require germania-kg/routenameurlcallable "^2.0"
Alternatively, add this package directly to your composer.json:, (*5)
"require": {
"germania-kg/routenameurlcallable": "^2.0"
}
Introduction
The controller callable within a Slim route sometimes needs a full URL, be it for a redirect response or for rendering links. Consider this route which creates a new thing via POST and redirects to its GET representation. The redirect requires a full URL., (*6)
Given a named Slim route like this…, (*7)
$app->get("/hello/{name}", function($request, $response, $args) {
$response->getBody()->write("Hello " . $args['name'] );
return $response;
})->setName("Hello");
…Slim framework provides a solution using RouteContext and RouteParser:, (*8)
$app->post("/users", function($request, $response, $args) {
// Create new user and grab name
$user = "john";
$route = "Hello";
// The Slim way
$uri = $request->getUri();
$context = \Slim\Routing\RouteContext::fromRequest($request);
$parser = $context->getRouteParser();
$location = $parser->fullUrlFor($uri, $route, ['name' => $user]);
# http://test.com/hello/john
return $response->withHeader('Location', $location)->withStatus(302);
});
The RouteNameUrlCallable now hides the cumbersome stuff. It works basically as a shortcut:, (*9)
$app->post("/users", function($request, $response, $args) {
// Create new user and grab name
$user = "john";
$route = "Hello";
$uri_factory = new RouteNameUrlCallable($request);
$location = $uri_factory($route, ['name' => $user]);
# http://test.com/hello/john
return $response->withHeader('Location', $location)->withStatus(302);
});
Instantiation
Pass a Slim\Psr7\Request
instance to the constructor. This is the default variant as of release 2., (*10)
$rnc = new RouteNameUrlCallable($request);
As of release 2.2, it is also possible to inject a Slim\Interfaces\RouteParserInterface
. This way will become the standard as of major release 3 (which at the time of writing has no time schedule)., (*11)
use Slim\Routing\RouteContext;
$request = ...;
$route_parser = RouteContext::fromRequest($request)->getRouteParser();
$rnc = new RouteNameUrlCallable($route_parser);
Recommendation: As a replacement for injecting the request into the constructor, one is encouraged to use the static fromRequest
method., (*12)
$rnc = RouteNameUrlCallable::fromRequest($request);
Usage
While Slim's RouteParser's relativeUrlFor, relativeUrlFor, and fullUrlFor methods return a string, the RouteNameUrlCallable returns a Slim\Http\Uri instance:, (*13)
<?php
use Germania\RouteNameUrlCallable\RouteNameUrlCallable;
use Slim\Factory\AppFactory;
// Setup Slim 4 App
$app = AppFactory::create();
$app->addRoutingMiddleware();
// Our named route:
$app->get("/hello/{name}", function($request, $response, $args) {
$response->getBody()->write("Hello " . $args['name'] );
return $response;
})->setName("Hello");
// ...and a route we use the callable within:
$app->post("/users", function($request, $response, $args) {
// Create new user and grab name
$user = "john";
$route = "Hello";
$uri_factory = new RouteNameUrlCallable::fromRequest($request);
$location = $uri_factory($route, ['name' => $user]);
echo get_class($location);
# \Slim\Http\Uri
echo $login_url->__toString();
# http://test.com/hello/john
return $response->withHeader('Location', $location)->withStatus(302);
});
Invokation alternatives
The first RouteNameUrlCallable parameter may be an array or object which holds the name, args, and query stuff., (*14)
Placeholder args and query parameters may be overridden with the second resp. third parameter which will be merged:, (*15)
$url_data = array(
'name' => "Hello",
'args' => ['name' => 'John'],
'params' => ['foo' => 'bar']
);
echo $uri_factory( $url_data );
http://test.com/hello/john?foo=bar
echo $uri_factory( $url_data, [], ['view' => 'table'] );
http://test.com/hello/john?foo=bar&view=table
echo $uri_factory( $url_data, [], ['foo' => 'baz', 'view' => 'table'] );
http://test.com/hello/john?foo=baz&view=table
Usage with Twig
Since RouteNameUrlCallable is callable, it can be used as Twig Function inside a template:, (*16)
{# "hello-user.html" #}
<a href="{{route_url('hello', {'name' => user})}}">Say hello to {{user}}</a>
Inside you route controller, add the callable to Twig like this:, (*17)
<?php
$app->get("/", function($request, $response, $args) {
$uri_factory = new RouteNameUrlCallable($request);
$twig = new \Twig\Environment( ... );
$twig->addFunction(new \Twig\TwigFunction('route_url', $uri_factory));
$html = $twig->render("hello-user.html", [
"user" => "john"
]);
$response->getBody()->write( $html );
return $response;
});
Development
$ git clone https://github.com/GermaniaKG/RouteNameUrlCallable.git
$ cd RouteNameUrlCallable
$ composer install
Unit tests
Either copy phpunit.xml.dist
to phpunit.xml
and adapt to your needs, or leave as is. Run PhpUnit test or composer scripts like this:, (*18)
$ composer test
# or
$ vendor/bin/phpunit