Reputation: 7752
I have the following code to match a route with a hostname;
'router' => [
'router_class' => 'Zend\Mvc\Router\Http\TranslatorAwareTreeRouteStack',
'routes' => [
'website' => [
'type' => 'hostname',
'may_terminate' => true,
'options' => [
'route' => ':locale.domain.:tld',
'constraints' => [
'language' => '(nl|en)',
'tld' => '(dev|org)',
],
],
]
],
],
And some routes to match the uri.
So in dev I can have routes like en.domain.dev
and nl.domain.dev
. The translation of the route also works like a charm but then my 'issues' occur
1. Assemble url
For every url I now need the locale
and tld
variable. To do this I do <?= $this->url('website/languages', [], true); ?>
, but that makes it a mess. Because I only want to use the TLD and locale of the current route.
So I came with the solution to extend the URL view helper. And set the locale
and tld
param when it was not set with the route match. This worked for 1 'minor' problem, see 2. But was wondering if there was a beter solution for this.
2. 404 paga
In 1 I use the current route match to get the locale
/tld
to assemble url's this all works, except for the 404 page. Because than there is no route match, obviously.
I started digging arround and when I found the router (from the service locator
). I tried to get the route for website
it only returned Zend\Mvc\Router\Http\Part
.
The protected $route
was the Zend\Mvc\Router\Http\Hostname
which is not accessible. So no luck that way.
The only way I got the Hostname route was by constructing it my self, which I don't really want to do.
So the question is how do you easily reuse the hostname params, and get the hostname params on a 404 page?
I know that for example test.domain.test will not match the hostname and will provide a broken Hostname, but that is a matter of Nginx. So Nginx will make sure the hostname are always correct
Upvotes: 0
Views: 315
Reputation: 7752
Well I continued searching and thinking and came with a 'solution'.
To tackle 2. I created a listener that listens on the MvcEvent::EVENT_DISPATCH_ERROR
.
Code;
// use are above the class declaration
use Zend\Mvc\Router\Http\TranslatorAwareTreeRouteStack;
use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventManagerInterface;
use Zend\Http\PhpEnvironment\Request;
use Zend\Mvc\Router\Http\RouteMatch;
use Zend\Mvc\MvcEvent;
public function onDispatchError(MvcEvent $event)
{
if (is_null($event->getRouteMatch())) {
$router = $event->getRouter();
$request = $event->getRequest();
if ($router instanceof TranslatorAwareTreeRouteStack && $request instanceof Request) {
$match = $router->getRoute('website')->match($request, strlen($request->getUri()->getPath()), array(
'translator' => $router->getTranslator(),
));
if ($match instanceof RouteMatch) {
$match->setMatchedRouteName('website');
$event->setRouteMatch($match);
}
}
}
}
What it does;
check if there is a route match, if not it is a 404
check the $router
is TranslatorAwareTreeRouteStack
and the $request
is a HttpRequest
get the route for website
(this is the route for the hostname`
then it matches it (the trick is that offset is set so only the hostname is checked)
sets the route matched name (is empty if not set which will lead to issues)
then the routematch is injected in the event
To tackle 1. I now had always access to a route match
so I could do some own magic. I extended the url viewhelper
.
public function __invoke(
$name = null,
$params = array(),
$options = array(),
$reuseMatchedParams = false
) {
if ($this->routeMatch instanceof RouteMatch) {
foreach(['locale', 'tld'] as $key) {
if (!array_key_exists($key, $params)) {
$params[$key] = $this->routeMatch->getParam($key);
}
}
}
// This is needed for the magic that can happen when `reuseMatchedParams` is used at the third position
if (is_bool($options)) {
$reuseMatchedParams = $options;
$options = array();
}
return parent::__invoke(
$name,
$params,
$options,
$reuseMatchedParams
);
}
Not the most elegant method but it works for now
Upvotes: 1