SilverStripe Fluent 模块似乎无法与开箱即用的控制器一起使用
SilverStripe Fluent module doesn't seem to work with controller out of the box
我在让 SilverStripe Fluent 模块与 content/page 控制器一起工作时遇到问题。每当提供语言环境 url 段时,控制器 returns 404。例如,http://site.local/search
工作但 http://site.local/en/search
returns 404.
我尝试通过将 mi/search
指向控制器名称来使用路由配置。模板呈现但当前语言环境不正确。
重现:
- 使用
composer create-project silverstripe/installer test
设置 SilverStripe 项目
- 需要模块
composer require tractorcow/silverstripe-fluent
- 设置 2 语言环境
- 英语带 url 段 'en'
- 毛利语 url 片段 'mi'
- 创建一个名为
SearchController
的简单控制器
- 在配置文件夹中创建一个
route.yml
- 在模板文件夹中创建名为
Search.ss
的模板文件
<?php
namespace App\Controllers;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\CMS\Controllers\ContentController;
class SearchController extends ContentController
{
private static $allowed_actions = [
'index',
];
public function index(HTTPRequest $request)
{
return $this->renderWith('Search');
}
}
---
Name: approutes
After: framework/_config/routes#coreroutes
---
SilverStripe\Control\Director:
rules:
'search//': 'App\Controllers\SearchController'
# 'mi/search//': 'App\Controllers\SearchController'
# 'en/search//': 'App\Controllers\SearchController'
<h1>Search</h1>
$CurrentLocale
导航至 <baseurl>/mi/search
,模板应呈现:
<h1>Search</h1>
mi_NZ
但是返回错误404。
概念
因此 Fluent 支持通过开箱即用的查询字符串进行本地化,但将语言环境附加到 URL 是为 CMS 驱动的页面保留的。通过您的示例,我能够通过 /search?l=en
和 /search?l=mi
看到正确的结果。
为了允许 URL 中的语言环境用于非 SiteTree 路由,我们可以修补 FluentDirectorExtension
,即负责注入 Fluent 路由规则的 class,并添加支持用于显式配置也应该是可本地化的路由。这可以通过添加 Director 规则来实现,这些规则基本上与上述相同,但在后台将 /search?l=en
URL 屏蔽为 /en/search
。
我的示例配置是这样的:
TractorCow\Fluent\Extension\FluentDirectorExtension:
static_routes: # Routes that should also allow URL segment based localisation
- 'search//'
这应该与您的 Director.rules
配置中的规则键匹配。
然后我们可以构建新的 URL 以允许支持,并告诉 Director 使用现有配置的控制器,同时透明地传递区域设置的 l
参数。我们需要为每个语言环境执行此操作,并且需要在 Fluent 的默认规则之前插入规则。你可以做什么的一个例子:
diff --git a/src/Extension/FluentDirectorExtension.php b/src/Extension/FluentDirectorExtension.php
index 6ebf1d6..0cdd80b 100644
--- a/src/Extension/FluentDirectorExtension.php
+++ b/src/Extension/FluentDirectorExtension.php
@@ -116,7 +116,10 @@ class FluentDirectorExtension extends Extension
protected function getExplicitRoutes($originalRules)
{
$queryParam = static::config()->get('query_param');
+ $staticRoutes = static::config()->get('static_routes');
$rules = [];
+ $prependRules = []; // we push these into the $rules before default fluent rules
+
/** @var Locale $localeObj */
foreach (Locale::getCached() as $localeObj) {
$locale = $localeObj->getLocale();
@@ -138,8 +141,22 @@ class FluentDirectorExtension extends Extension
'Controller' => $controller,
$queryParam => $locale,
];
+
+ // Include opt-in static routes
+ foreach ($staticRoutes as $staticRoute) {
+ // Check for a matching rule in the Director configuration
+ if (!isset($originalRules[$staticRoute])) {
+ continue;
+ }
+
+ $prependRules[$url . '/' . $staticRoute] = [
+ 'Controller' => $originalRules[$staticRoute],
+ $queryParam => $locale,
+ ];
+ }
}
- return $rules;
+
+ return array_merge($prependRules, $rules);
}
/**
如果您在 updateRules()
方法的末尾调试 $rules
,您将看到 Fluent 现在已在每个语言环境中为该路由注入了一条新规则:
'en/search//' =>
array (size=2)
'Controller' => string 'App\Controllers\SearchController' (length=42)
'l' => string 'en_NZ' (length=5)
'mi/search//' =>
array (size=2)
'Controller' => string 'App\Controllers\SearchController' (length=42)
'l' => string 'mi_NZ' (length=5)
实施
一旦我可以用一些单元测试对其进行备份,我将针对此更改向模块提出拉取请求,但与此同时,您可以通过在项目代码中使用注入器覆盖来实现它,并扩展受保护的 getExplicitRoutes
方法以实现上述更改:
SilverStripe\Core\Injector\Injector:
TractorCow\Fluent\Extension\FluentDirectorExtension:
class: MyFluentDirectorExtension
class MyFluentDirectorExtension extends FluentDirectorExtension
{
protected function getExplicitRoutes($originalRules)
{
$rules = parent::getExplicitRoutes($originalRules);
$staticRoutes = static::config()->get('static_routes');
$queryParam = static::config()->get('query_param');
$prependRules = [];
// Include opt-in static routes
foreach (Locale::getCached() as $localeObj) {
foreach ($staticRoutes as $staticRoute) {
$locale = $localeObj->getLocale();
$url = urlencode($localeObj->getURLSegment());
// Check for a matching rule in the Director configuration
if (!isset($originalRules[$staticRoute])) {
continue;
}
$prependRules[$url . '/' . $staticRoute] = [
'Controller' => $originalRules[$staticRoute],
$queryParam => $locale,
];
}
}
return array_merge($prependRules, $rules);
}
}
我在让 SilverStripe Fluent 模块与 content/page 控制器一起工作时遇到问题。每当提供语言环境 url 段时,控制器 returns 404。例如,http://site.local/search
工作但 http://site.local/en/search
returns 404.
我尝试通过将 mi/search
指向控制器名称来使用路由配置。模板呈现但当前语言环境不正确。
重现:
- 使用
composer create-project silverstripe/installer test
设置 SilverStripe 项目
- 需要模块
composer require tractorcow/silverstripe-fluent
- 设置 2 语言环境
- 英语带 url 段 'en'
- 毛利语 url 片段 'mi'
- 创建一个名为
SearchController
的简单控制器
- 在配置文件夹中创建一个
route.yml
- 在模板文件夹中创建名为
Search.ss
的模板文件
<?php
namespace App\Controllers;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\CMS\Controllers\ContentController;
class SearchController extends ContentController
{
private static $allowed_actions = [
'index',
];
public function index(HTTPRequest $request)
{
return $this->renderWith('Search');
}
}
---
Name: approutes
After: framework/_config/routes#coreroutes
---
SilverStripe\Control\Director:
rules:
'search//': 'App\Controllers\SearchController'
# 'mi/search//': 'App\Controllers\SearchController'
# 'en/search//': 'App\Controllers\SearchController'
<h1>Search</h1>
$CurrentLocale
导航至 <baseurl>/mi/search
,模板应呈现:
<h1>Search</h1>
mi_NZ
但是返回错误404。
概念
因此 Fluent 支持通过开箱即用的查询字符串进行本地化,但将语言环境附加到 URL 是为 CMS 驱动的页面保留的。通过您的示例,我能够通过 /search?l=en
和 /search?l=mi
看到正确的结果。
为了允许 URL 中的语言环境用于非 SiteTree 路由,我们可以修补 FluentDirectorExtension
,即负责注入 Fluent 路由规则的 class,并添加支持用于显式配置也应该是可本地化的路由。这可以通过添加 Director 规则来实现,这些规则基本上与上述相同,但在后台将 /search?l=en
URL 屏蔽为 /en/search
。
我的示例配置是这样的:
TractorCow\Fluent\Extension\FluentDirectorExtension:
static_routes: # Routes that should also allow URL segment based localisation
- 'search//'
这应该与您的 Director.rules
配置中的规则键匹配。
然后我们可以构建新的 URL 以允许支持,并告诉 Director 使用现有配置的控制器,同时透明地传递区域设置的 l
参数。我们需要为每个语言环境执行此操作,并且需要在 Fluent 的默认规则之前插入规则。你可以做什么的一个例子:
diff --git a/src/Extension/FluentDirectorExtension.php b/src/Extension/FluentDirectorExtension.php
index 6ebf1d6..0cdd80b 100644
--- a/src/Extension/FluentDirectorExtension.php
+++ b/src/Extension/FluentDirectorExtension.php
@@ -116,7 +116,10 @@ class FluentDirectorExtension extends Extension
protected function getExplicitRoutes($originalRules)
{
$queryParam = static::config()->get('query_param');
+ $staticRoutes = static::config()->get('static_routes');
$rules = [];
+ $prependRules = []; // we push these into the $rules before default fluent rules
+
/** @var Locale $localeObj */
foreach (Locale::getCached() as $localeObj) {
$locale = $localeObj->getLocale();
@@ -138,8 +141,22 @@ class FluentDirectorExtension extends Extension
'Controller' => $controller,
$queryParam => $locale,
];
+
+ // Include opt-in static routes
+ foreach ($staticRoutes as $staticRoute) {
+ // Check for a matching rule in the Director configuration
+ if (!isset($originalRules[$staticRoute])) {
+ continue;
+ }
+
+ $prependRules[$url . '/' . $staticRoute] = [
+ 'Controller' => $originalRules[$staticRoute],
+ $queryParam => $locale,
+ ];
+ }
}
- return $rules;
+
+ return array_merge($prependRules, $rules);
}
/**
如果您在 updateRules()
方法的末尾调试 $rules
,您将看到 Fluent 现在已在每个语言环境中为该路由注入了一条新规则:
'en/search//' =>
array (size=2)
'Controller' => string 'App\Controllers\SearchController' (length=42)
'l' => string 'en_NZ' (length=5)
'mi/search//' =>
array (size=2)
'Controller' => string 'App\Controllers\SearchController' (length=42)
'l' => string 'mi_NZ' (length=5)
实施
一旦我可以用一些单元测试对其进行备份,我将针对此更改向模块提出拉取请求,但与此同时,您可以通过在项目代码中使用注入器覆盖来实现它,并扩展受保护的 getExplicitRoutes
方法以实现上述更改:
SilverStripe\Core\Injector\Injector:
TractorCow\Fluent\Extension\FluentDirectorExtension:
class: MyFluentDirectorExtension
class MyFluentDirectorExtension extends FluentDirectorExtension
{
protected function getExplicitRoutes($originalRules)
{
$rules = parent::getExplicitRoutes($originalRules);
$staticRoutes = static::config()->get('static_routes');
$queryParam = static::config()->get('query_param');
$prependRules = [];
// Include opt-in static routes
foreach (Locale::getCached() as $localeObj) {
foreach ($staticRoutes as $staticRoute) {
$locale = $localeObj->getLocale();
$url = urlencode($localeObj->getURLSegment());
// Check for a matching rule in the Director configuration
if (!isset($originalRules[$staticRoute])) {
continue;
}
$prependRules[$url . '/' . $staticRoute] = [
'Controller' => $originalRules[$staticRoute],
$queryParam => $locale,
];
}
}
return array_merge($prependRules, $rules);
}
}