Sorting CakePHP3:Paginator按语言排序(具有i18n翻译行为)
我有一个包含所有条目的表,包括所有多语言的翻译:如何在翻译字段上创建分页排序链接?(第3.1.6节) 摘要:这不起作用,我无法按翻译进行排序:Sorting CakePHP3:Paginator按语言排序(具有i18n翻译行为),sorting,cakephp,pagination,cakephp-3.1,cakephp-3.x,Sorting,Cakephp,Pagination,Cakephp 3.1,Cakephp 3.x,我有一个包含所有条目的表,包括所有多语言的翻译:如何在翻译字段上创建分页排序链接?(第3.1.6节) 摘要:这不起作用,我无法按翻译进行排序: $this->Paginator->sort('_translations.es.title', 'Spanish') 长版本: 我正在使用带有的i18n表 我在一个表中列出了所有的翻译(多种语言) 现在我想在翻译中使用(按语言排序) |标题英语|标题西班牙语|标题德语|=分页排序链接 | ---------------- | ----
$this->Paginator->sort('_translations.es.title', 'Spanish')
长版本:
- 我正在使用带有的i18n表
- 我在一个表中列出了所有的翻译(多种语言)
- 现在我想在翻译中使用(按语言排序)
|标题英语|标题西班牙语|标题德语|=分页排序链接
| ---------------- | ---------------- | --------------- |
|圣诞节|纳维达德|威纳克斯登|
|春天|普里马维拉|弗吕林|
| ...
下面是我的简化测试设置:
表文章只有一个字段标题
需要翻译。i18n表是默认设置 烘焙表格类
/src/Model/Table/ArticlesTable.php
,添加了翻译行为:
公共函数初始化(数组$config){
//…默认配置(在本文中删除以简化代码)
$this->addBehavior('Translate',['fields'=>['title']]);//添加了此行
}
烘焙Entity类/src/Model/Entity/Article.php
,添加了translaterait:
namespace-App\Model\Entity;
使用Cake\ORM\Behavior\Translate\TranslateTrait;//增加了这一行
使用Cake\ORM\Entity;
类文章扩展了实体{
受保护的$\u可访问=[
“*”=>正确,
'id'=>false,
];
使用translateRait;//添加了此行
}
烘焙控制器/src/Controller/ArticlesController.php
,修改如下:
namespace-App\Controller;
使用App\Controller\AppController;
类ArticlesController扩展了AppController{
公共$paginate=[
'sortWhitelist'=>[//允许在此字段上进行分页排序:
“头衔”,
“_translations.es.title”,
“\u translations.de.title”
]
];
公共职能指数(){
$query=$this->Articles->find('translations');//检索所有翻译
$this->set('articles',$this->paginate($query));
}
}
烘焙视图/src/Template/Articles/index.ctp
,修改/简化:
表中的翻译显示正确,但无法按翻译字段排序。当我单击翻译的分页链接时,出现以下错误:
SQLSTATE[42S22]:未找到列:“order子句”中的1054未知列“\u translations.es”
格式为Posts\u title\u translation.content
,我不知道这是从哪里来的,但我也尝试了这种方式(当然,我还在paginator白名单中添加了字段名的变体):
$this->Paginator->sort('Articles\u title\u translation','西班牙语')
$this->Paginator->sort('Articles\u title\u translation.es','西班牙语')
$this->Paginator->sort('Articles\u title\u translation.content','西班牙语')
$this->Paginator->sort('Articles\u title\u translation.es.content','西班牙语')
他们都不工作。。。(显然)
如何根据标题字段的i18n翻译对表项进行排序?对翻译字段进行排序需要联接
通常,您只能对加入主查询的字段进行排序
翻译后的字段仅与非默认的当前区域设置连接
默认情况下,只有在当前区域设置(I18n::locale()
)与默认区域设置(I18n::defaultLocale()
,intl.default\u locale
)不匹配的情况下(即实际需要翻译某些内容时),才会加入已翻译字段
将当前区域设置更改为非默认设置后
I18n::locale('de');
$query = $this->Articles->find('translations');
// ...
翻译行为将包含与翻译内容的关联,这就是TableAlias\u field\u translation
别名的来源,该行为使用该命名方案为每个翻译字段创建hasOne
关联
hasMany
关联来加载的,即使用单独的查询,因此它们不能用于排序。加入所有翻译都需要手动完成
这可能是一个特性请求,但我不确定这是否是一个可以证明这样的核心修改的常见用例,您可能希望在上打开一个问题或询问
话虽如此,这里有一个基本的例子,一个扩展的translate行为,它几乎完成了TranslateBehavior::setupFieldAssociations()
和TranslateBehavior::beforeFind()
所做的事情,只是稍微修改了一下。该行为采用了一个locales
选项,该选项需要与所有locales一起提供
I18n::locale('de');
$query = $this->Articles->find('translations');
// ...
public function index()
{
$sort = $this->request->query('sort');
if ($sort) {
$fieldMap = [
'Articles_title_translation.content' => 'Articles.title'
];
if (
isset($fieldMap[$sort]) &&
$this->Articles->locale() ===
$this->Articles->behaviors()->get('Translate')->config('defaultLocale')
) {
$this->request->query['sort'] = $fieldMap[$sort];
}
}
$query = $this->Articles->find('translations');
$this->set('articles', $this->paginate($query));
}
// Remove $this->addBehavior('Translate', ['fields' => ['title']]);
// and load the custom behavior instead (otherwise there will be an
// error about "duplicate translation finders"
$this->addBehavior('MyTranslate', [
'fields' => ['title'],
'locales' => ['es', 'de']
]);
namespace App\Model\Behavior;
use Cake\ORM\Behavior\TranslateBehavior;
use Cake\ORM\Query;
use Cake\ORM\Table;
class MyTranslateBehavior extends TranslateBehavior
{
protected $_associations = [];
public function __construct(Table $table, array $config)
{
$config += [
'locales' => []
];
parent::__construct($table, $config);
}
public function setupFieldAssociations($fields, $table, $model, $strategy)
{
parent::setupFieldAssociations($fields, $table, $model, $strategy);
$alias = $this->_table->alias();
$tableLocator = $this->tableLocator();
$locales = $this->config('locales');
$this->_associations = [];
foreach ($fields as $field) {
foreach ($locales as $locale) {
$name = $alias . '_' . $field . '_translation_' . $locale;
if (!$tableLocator->exists($name)) {
$fieldTable = $tableLocator->get($name, [
'className' => $table,
'alias' => $name,
'table' => $this->_translationTable->table()
]);
} else {
$fieldTable = $tableLocator->get($name);
}
$conditions = [
$name . '.locale' => $locale,
$name . '.model' => $model,
$name . '.field' => $field
];
$this->_table->hasOne($name, [
'targetTable' => $fieldTable,
'foreignKey' => 'foreign_key',
'joinType' => 'LEFT',
'conditions' => $conditions,
'propertyName' => $field . '_translation_' . $locale
]);
$this->_associations[] = $name;
}
}
}
public function findTranslations(Query $query, array $options)
{
$query->contain($this->_associations);
return parent::findTranslations($query, $options);
}
}
public $paginate = [
'order' => ['Articles.title' => 'ASC']
'sortWhitelist' => [
'Articles.title',
'Articles_title_translation_de.content',
'Articles_title_translation_es.content'
]
];
$this->Paginator->sort('Articles.title', 'English');
$this->Paginator->sort('Articles_title_translation_es.content', 'Spanish');
$this->Paginator->sort('Articles_title_translation_de.content', 'German');