From 11024f0fe2f137f00e0bf92408a52a26730bbfde Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 24 Nov 2016 21:11:50 +0200 Subject: [PATCH 1/4] added routes localizer --- .../Routing/Middleware/Localize.php | 86 +++++++++++++++ src/Illuminate/Routing/Router.php | 16 +++ src/Illuminate/Routing/RoutesLocalizer.php | 88 +++++++++++++++ tests/Routing/RouteLocalizationTest.php | 101 ++++++++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 src/Illuminate/Routing/Middleware/Localize.php create mode 100644 src/Illuminate/Routing/RoutesLocalizer.php create mode 100644 tests/Routing/RouteLocalizationTest.php diff --git a/src/Illuminate/Routing/Middleware/Localize.php b/src/Illuminate/Routing/Middleware/Localize.php new file mode 100644 index 000000000000..a0fb737c5fe7 --- /dev/null +++ b/src/Illuminate/Routing/Middleware/Localize.php @@ -0,0 +1,86 @@ +app = $app; + $this->url = $url; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle($request, Closure $next) + { + $defaultLocale = $this->app['config']->get('app.fallback_locale'); + + if (! $this->requestPathHasLocale($request)) { + return redirect(trim($defaultLocale.'/'.$request->path(), '/')); + } + + $locale = $this->getLocaleFromRequest($request); + + $this->app->setLocale($locale); + + $this->url->formatPathUsing(function ($path) use ($locale) { + return rtrim('/'.$locale.$path, '/'); + }); + + return $next($request); + } + + /** + * Determine if the request path contains locale information. + * + * @param \Illuminate\Http\Request $request + * @return bool + */ + protected function requestPathHasLocale($request) + { + return in_array($request->segment(1), $this->app['config']->get('app.locales')); + } + + /** + * Extract the locale from the given request. + * + * @param \Illuminate\Http\Request $request + * @return string + */ + private function getLocaleFromRequest($request) + { + return $this->requestPathHasLocale($request) ? + $request->segment(1) : $this->app['config']->get('app.fallback_locale'); + } +} diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index c7aad3daea46..7c42bf41d15f 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -280,6 +280,22 @@ public function resource($name, $controller, array $options = []) $registrar->register($name, $controller, $options); } + /** + * Localize the registered routes. + * + * @return void + */ + public function localize() + { + if ($this->container && $this->container->bound('Illuminate\Routing\RoutesLocalizer')) { + $localizer = $this->container->make('Illuminate\Routing\RoutesLocalizer'); + } else { + $localizer = new RoutesLocalizer($this, $this->container['config']); + } + + $localizer->localize(); + } + /** * Register the typical authentication routes for an application. * diff --git a/src/Illuminate/Routing/RoutesLocalizer.php b/src/Illuminate/Routing/RoutesLocalizer.php new file mode 100644 index 000000000000..f9e1eb74d565 --- /dev/null +++ b/src/Illuminate/Routing/RoutesLocalizer.php @@ -0,0 +1,88 @@ +router = $router; + $this->config = $config; + } + + /** + * Localize routes using the given locales. + * + * @return void + */ + public function localize() + { + foreach ($this->router->getRoutes() as $route) { + if (! $this->routeShouldBeLocalized($route)) { + return; + } + + foreach ($this->config->get('app.locales') as $locale) { + $this->addRouteForLocale($route, $locale); + } + } + } + + /** + * Add a route for the locale in the route collection. + * + * @param \Illuminate\Routing\Route $route + * @param string $locale + * @return void + */ + private function addRouteForLocale($route, $locale) + { + $route = clone $route; + + $routeUri = $route->getUri(); + + $route->setUri( + $routeUri == '/' ? $locale : $locale.'/'.$routeUri + ); + + if ($route->getName()) { + $route->name('.'.$locale); + } + + $this->router->getRoutes()->add($route); + } + + /** + * Determine if the route should be localized. + * + * @param \Illuminate\Routing\Route $route + * @return bool + */ + private function routeShouldBeLocalized($route) + { + return in_array('localize', $route->gatherMiddleware()); + } +} diff --git a/tests/Routing/RouteLocalizationTest.php b/tests/Routing/RouteLocalizationTest.php new file mode 100644 index 000000000000..6a2374cfbc95 --- /dev/null +++ b/tests/Routing/RouteLocalizationTest.php @@ -0,0 +1,101 @@ +app = new Application(); + } + + public function testLocalizerMatchesRouteWithLocale() + { + $router = $this->getRouter(); + + $router->get('foo', function () { + return 'foo'; + })->middleware('localize'); + + $this->app['config']->shouldReceive('get')->with('app.locales')->andReturn(['en', 'ar']); + $this->app['config']->shouldReceive('get')->with('app.fallback_locale')->andReturn('en'); + + $this->app['config']->shouldReceive('set')->with("app.locale", "ar"); + $this->app['translator']->shouldReceive('setLocale')->with('ar'); + + $this->app['config']->shouldReceive('set')->with("app.locale", "en"); + $this->app['translator']->shouldReceive('setLocale')->with('en'); + + $this->url->shouldReceive('formatPathUsing'); + + $router->localize(); + + $this->assertEquals('foo', $router->dispatch(Request::create('ar/foo', 'GET'))->getContent()); + $this->assertEquals('foo', $router->dispatch(Request::create('en/foo', 'GET'))->getContent()); + } + + /** + * @expectedException Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public function testLocalizerDoesntLocalizeRoutesWithoutTheMiddleware() + { + $router = $this->getRouter(); + + $router->get('foo', function () { + return 'foo'; + }); + + $router->localize(); + + $this->assertEquals('foo', $router->dispatch(Request::create('ar/foo', 'GET'))->getContent()); + } + + public function testLocalizerRedirectesToPathWithDefaultLocale() + { + $router = $this->getRouter(); + + $redirector = Mockery::mock('Illuminate\Routing\Redirector'); + $redirector->shouldReceive('to')->once()->with('en/foo', 302, [], null); + + $this->app->bind('redirect', function () use ($redirector){ + return $redirector; + }); + + $this->app['config']->shouldReceive('get')->with('app.fallback_locale')->andReturn('en'); + $this->app['config']->shouldReceive('get')->with('app.locales')->andReturn(['en', 'ar']); + + $router->get('foo', function () { + return 'foo'; + })->middleware('localize'); + + $router->dispatch(Request::create('foo', 'GET')); + } + + protected function getRouter() + { + $this->url = Mockery::mock('Illuminate\Contracts\Routing\UrlGenerator'); + + $this->app['config'] = Mockery::mock('Illuminate\Contracts\Config\Repository'); + + $this->app['translator'] = Mockery::mock('Illuminate\Translation\Translator'); + + $this->app->bind('Illuminate\Contracts\Routing\UrlGenerator', function () { + return $this->url; + }); + + $router = new Router(new Dispatcher, $this->app); + + $router->middleware('localize', 'Illuminate\Routing\Middleware\Localize'); + + return $router; + } +} From 5a32abe159a210a99e9f40f6c79488caf937ef32 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 24 Nov 2016 23:00:17 +0200 Subject: [PATCH 2/4] fix style --- tests/Routing/RouteLocalizationTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Routing/RouteLocalizationTest.php b/tests/Routing/RouteLocalizationTest.php index 6a2374cfbc95..d9c1913985e0 100644 --- a/tests/Routing/RouteLocalizationTest.php +++ b/tests/Routing/RouteLocalizationTest.php @@ -1,10 +1,9 @@ app = new Application(); } @@ -29,10 +29,10 @@ public function testLocalizerMatchesRouteWithLocale() $this->app['config']->shouldReceive('get')->with('app.locales')->andReturn(['en', 'ar']); $this->app['config']->shouldReceive('get')->with('app.fallback_locale')->andReturn('en'); - $this->app['config']->shouldReceive('set')->with("app.locale", "ar"); + $this->app['config']->shouldReceive('set')->with('app.locale', 'ar'); $this->app['translator']->shouldReceive('setLocale')->with('ar'); - $this->app['config']->shouldReceive('set')->with("app.locale", "en"); + $this->app['config']->shouldReceive('set')->with('app.locale', 'en'); $this->app['translator']->shouldReceive('setLocale')->with('en'); $this->url->shouldReceive('formatPathUsing'); @@ -66,12 +66,12 @@ public function testLocalizerRedirectesToPathWithDefaultLocale() $redirector = Mockery::mock('Illuminate\Routing\Redirector'); $redirector->shouldReceive('to')->once()->with('en/foo', 302, [], null); - $this->app->bind('redirect', function () use ($redirector){ + $this->app->bind('redirect', function () use ($redirector) { return $redirector; }); $this->app['config']->shouldReceive('get')->with('app.fallback_locale')->andReturn('en'); - $this->app['config']->shouldReceive('get')->with('app.locales')->andReturn(['en', 'ar']); + $this->app['config']->shouldReceive('get')->with('app.locales')->andReturn(['en', 'ar']); $router->get('foo', function () { return 'foo'; From 4e1b89cf7c8127e3bc67c102d3b6502ac16daf3d Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Fri, 25 Nov 2016 14:30:03 +0200 Subject: [PATCH 3/4] a bit of refactoring --- .../Routing/Middleware/Localize.php | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Routing/Middleware/Localize.php b/src/Illuminate/Routing/Middleware/Localize.php index a0fb737c5fe7..f65d362b41d8 100644 --- a/src/Illuminate/Routing/Middleware/Localize.php +++ b/src/Illuminate/Routing/Middleware/Localize.php @@ -46,12 +46,10 @@ public function handle($request, Closure $next) { $defaultLocale = $this->app['config']->get('app.fallback_locale'); - if (! $this->requestPathHasLocale($request)) { + if (! $locale = $this->getLocaleFromRequest($request)) { return redirect(trim($defaultLocale.'/'.$request->path(), '/')); } - $locale = $this->getLocaleFromRequest($request); - $this->app->setLocale($locale); $this->url->formatPathUsing(function ($path) use ($locale) { @@ -62,25 +60,26 @@ public function handle($request, Closure $next) } /** - * Determine if the request path contains locale information. + * Extract the locale from the given request. * * @param \Illuminate\Http\Request $request - * @return bool + * @return string|null */ - protected function requestPathHasLocale($request) + private function getLocaleFromRequest($request) { - return in_array($request->segment(1), $this->app['config']->get('app.locales')); + if($this->localeIsValid($locale = $request->segment(1))){ + return $locale; + } } /** - * Extract the locale from the given request. + * Determine if the given locale is valid. * - * @param \Illuminate\Http\Request $request - * @return string + * @param string $locale + * @return bool */ - private function getLocaleFromRequest($request) + private function localeIsValid($locale) { - return $this->requestPathHasLocale($request) ? - $request->segment(1) : $this->app['config']->get('app.fallback_locale'); + return in_array($locale, $this->app['config']->get('app.locales')); } } From 8e97e2f366627348f353569ed13557b60a440bce Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Fri, 25 Nov 2016 14:30:34 +0200 Subject: [PATCH 4/4] fix style --- src/Illuminate/Routing/Middleware/Localize.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Middleware/Localize.php b/src/Illuminate/Routing/Middleware/Localize.php index f65d362b41d8..b966c80dcf72 100644 --- a/src/Illuminate/Routing/Middleware/Localize.php +++ b/src/Illuminate/Routing/Middleware/Localize.php @@ -67,7 +67,7 @@ public function handle($request, Closure $next) */ private function getLocaleFromRequest($request) { - if($this->localeIsValid($locale = $request->segment(1))){ + if ($this->localeIsValid($locale = $request->segment(1))) { return $locale; } }