【问题标题】:SilverStripe Fluent module doesn't seem to work with controller out of the boxSilverStripe Fluent 模块似乎不适用于开箱即用的控制器
【发布时间】:2019-12-31 06:06:00
【问题描述】:

我在让 SilverStripe Fluent 模块与内容/页面控制器一起工作时遇到问题。每当提供语言环境 url 段时,控制器都会返回 404。例如,http://site.local/search 有效,但 http://site.local/en/search 返回 404。

我尝试通过将mi/search 指向控制器名称来使用路由配置。模板呈现,但当前语言环境不正确。

重现:

  1. 使用composer create-project silverstripe/installer test 设置 SilverStripe 项目
  2. 需要模块composer require tractorcow/silverstripe-fluent
  3. 设置 2 语言环境
    • 英文网址段为“en”
    • 网址段为“mi”的毛利语
  4. 创建一个名为SearchController 的简单控制器
  5. 在配置文件夹中创建route.yml
  6. 在模板文件夹中创建名为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

导航到&lt;baseurl&gt;/mi/search,模板应该呈现:

<h1>Search</h1>
mi_NZ

但返回错误 404。

【问题讨论】:

    标签: php translation silverstripe silverstripe-4


    【解决方案1】:

    概念

    因此,Fluent 支持通过开箱即用的查询字符串进行本地化,但将语言环境附加到 URL 是为 CMS 驱动的页面保留的。通过您的示例,我可以通过/search?l=en/search?l=mi 看到正确的结果。

    为了允许非 SiteTree 路由的 URL 中的区域设置,我们可以修补 FluentDirectorExtension,它是负责注入 Fluent 路由规则的类,并添加对也应该是可本地化的路由的显式配置的支持。这可以通过添加与上述基本相同的 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);
        }
    }
    

    【讨论】:

    • 罗比,我认为$queryParam =&gt; $locale 不应该在那里。该路线有效,但测试模板中的 $CurrentLocale 未显示所选区域设置 - 始终为 mi_NZ
    • 抱歉,我忘记包含 $queryParam 的定义 - 已更新示例代码以包含它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    相关资源
    最近更新 更多