Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#735 solves wrong routes matching #740

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,10 @@ will not work. Instead, one has to use
</form>
```


Another way to solve this is to put http method to config to 'laravellocalization.httpMethodsIgnored'
to prevent of processing this type of requests

### MethodNotAllowedHttpException

If you do not localize your post url and use a redirect middleware,
Expand Down
15 changes: 9 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"name": "mcamara/laravel-localization",
"name": "nuranto/laravel-localization",
"description": "Easy localization for Laravel",
"keywords": ["localization", "laravel", "php"],
"keywords": [
"localization",
"laravel",
"php"
],
"homepage": "https://github.com/mcamara/laravel-localization",
"license": "MIT",
"authors": [
Expand All @@ -13,7 +17,7 @@
],
"require": {
"php": ">=7.1.0",
"laravel/framework": "~5.2.0||~5.3.0||~5.4.0||~5.5.0||~5.6.0||~5.7.0||~5.8.0||^6.0||^7.0||^8.0"
"laravel/framework": "^10.0||^11.0"
},
"require-dev": {
"orchestra/testbench-browser-kit": "~3.4|~3.8|~4.0",
Expand All @@ -26,8 +30,7 @@
"test": "vendor/bin/phpunit"
},
"autoload": {
"classmap": [
],
"classmap": [],
"psr-0": {
"Mcamara\\LaravelLocalization": "src/"
}
Expand All @@ -44,4 +47,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
137 changes: 76 additions & 61 deletions src/Mcamara/LaravelLocalization/LaravelLocalization.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Config\Repository;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Illuminate\Support\Env;
use Mcamara\LaravelLocalization\Exceptions\SupportedLocalesNotDefined;
Expand Down Expand Up @@ -150,11 +151,15 @@ public function __construct()
* Set and return current locale.
*
* @param string $locale Locale to set the App to (optional)
* @param bool $asDefault set as default locale
*
* @return string Returns locale (if route has any) or null (if route does not have a locale)
*/
public function setLocale($locale = null)
public function setLocale($locale = null, $asDefault = false)
{
if($asDefault) {
$this->defaultLocale = $locale;
}
if (empty($locale) || !\is_string($locale)) {
// If the locale has not been passed through the function
// it tries to get it from the first segment of the url
Expand Down Expand Up @@ -761,7 +766,7 @@ protected function findTranslatedRouteByUrl($url, $attributes, $locale)
$routeName = $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);

// We can ignore extra url parts and compare only their url_path (ignore arguments that are not attributes)
if (parse_url($this->getNonLocalizedURL($routeName), PHP_URL_PATH) == parse_url($this->getNonLocalizedURL($url), PHP_URL_PATH)) {
if (parse_url($this->getNonLocalizedURL($routeName), PHP_URL_PATH) == parse_url($this->getNonLocalizedURL(urldecode($url)), PHP_URL_PATH)) {
$this->cachedTranslatedRoutesByUrl[$locale][$url] = $translatedRoute;

return $translatedRoute;
Expand Down Expand Up @@ -885,83 +890,93 @@ public function setSerializedTranslatedRoutes($serializedRoutes)
*/
protected function extractAttributes($url = false, $locale = '')
{

if (!empty($url)) {
$attributes = [];
$parse = parse_url($url);
if (isset($parse['path'])) {
$parse['path'] = trim(str_replace('/'.$this->currentLocale.'/', '', $parse['path']), "/");
$url = explode('/', trim($parse['path'], '/'));
} else {
$url = [];
}

foreach ($this->router->getRoutes() as $route) {
$cacheKey = 'laravellocalisation-ea-'.$locale.'-'.$url;
return Cache::remember($cacheKey, 30, function() use ($url, $locale) {
$attributes = [];
$path = method_exists($route, 'uri') ? $route->uri() : $route->getUri();

if (!preg_match("/{[\w]+\??}/", $path)) {
continue;
$originalUrl = $url;
$parse = parse_url($url);
if (isset($parse['path'])) {
$parse['path'] = trim(str_replace('/'.$this->currentLocale.'/', '', $parse['path']), "/");
$url = explode('/', trim($parse['path'], '/'));
} else {
$url = [];
}

$path = explode('/', $path);
$i = 0;

// The system's route can't be smaller
// only the $url can be missing segments (optional parameters)
// We can assume it's the wrong route
if (count($path) < count($url)) {
continue;
}

$match = true;
foreach ($path as $j => $segment) {
if (isset($url[$i])) {
if ($segment === $url[$i]) {
$i++;
continue;
} elseif (preg_match("/{[\w]+}/", $segment)) {
// must-have parameters
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
$attributes[$attribute_name] = $url[$i];
$i++;
continue;
} elseif (preg_match("/{[\w]+\?}/", $segment)) {
// optional parameters
if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) {
// optional parameter taken

foreach ($this->router->getRoutes() as $route) {
$attributes = [];
$path = method_exists($route, 'uri') ? $route->uri() : $route->getUri();



if (!preg_match("/{[\w]+\??}/", $path)) {
continue;
}
$path = explode('/', $path);
$i = 0;

// The system's route can't be smaller
// only the $url can be missing segments (optional parameters)
// We can assume it's the wrong route
if (count($path) < count($url)) {
continue;
}


$match = true;
foreach ($path as $j => $segment) {
if (isset($url[$i])) {
if ($segment === $url[$i]) {
$i++;
continue;
} elseif (preg_match("/{[\w]+}/", $segment)) {
// must-have parameters
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
$attributes[$attribute_name] = $url[$i];
$i++;
continue;
} elseif (preg_match("/{[\w]+\?}/", $segment)) {
// optional parameters
if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) {
// optional parameter taken
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
$attributes[$attribute_name] = $url[$i];
$i++;
continue;
} else {
$match = false;
break;
}
} else {
// As soon as one segment doesn't match, then we have the wrong route
$match = false;
break;
}
} elseif (preg_match("/{[\w]+\?}/", $segment)) {
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
$attributes[$attribute_name] = null;
$i++;
} else {
// As soon as one segment doesn't match, then we have the wrong route
// no optional parameters but no more $url given
// this route does not match the url
$match = false;
break;
}
} elseif (preg_match("/{[\w]+\?}/", $segment)) {
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
$attributes[$attribute_name] = null;
$i++;
} else {
// no optional parameters but no more $url given
// this route does not match the url
}

if (isset($url[$i + 1])) {
$match = false;
break;
}

if ($match) {
if($route->matches(request()->create($originalUrl))) {
return $attributes;
}
}
}

if (isset($url[$i + 1])) {
$match = false;
}

if ($match) {
return $attributes;
}
}
return [];
});
} else {
if (!$this->router->current()) {
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class LaravelLocalizationMiddlewareBase
*/
protected function shouldIgnore($request)
{
if (in_array($request->method(), config('laravellocalization.httpMethodsIgnored'))) {
return true;
}
$this->except = $this->except ?? config('laravellocalization.urlsIgnored', []);
foreach ($this->except as $except) {
if ($except !== '/') {
Expand Down
1 change: 1 addition & 0 deletions src/config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,5 @@
// Defaults to []
'urlsIgnored' => ['/skipped'],

'httpMethodsIgnored' => ['POST', 'PUT', 'PATCH', 'DELETE'],
];