CakePHP 3.0 中虚拟字段/实体属性上的分页排序链接

Posted

技术标签:

【中文标题】CakePHP 3.0 中虚拟字段/实体属性上的分页排序链接【英文标题】:Pagination sort link on a virtual field/entity property in CakePHP 3.0 【发布时间】:2015-10-24 03:36:54 【问题描述】:

我想在 Cakephp 3.0 中的 virtual field/entity property 上创建一个 pagination sort link。

在 CakePHP 2.x 中,我曾经创建一个virtual field,然后在该字段上创建一个分页排序链接。但是,在 CakePHP 3.0 中,virtual fields 已被 virtual entity properties 取代。

有什么方法可以让我在 CakePHP 3.0 中使用它吗?

在我的情况下,我有一个 first_name 和 last_name 列,它们在 virtual entity property 中组合为 full_name。我想按全名排序。

【问题讨论】:

【参考方案1】:

如链接文档中所述,虚拟属性不能用于查找。这是设计使然,虚拟属性只存在于实体中,它们是在从数据库中检索到数据之后在 PHP 中构建的。

所以让我们暂时忘掉虚拟属性,专注于查询和计算列。

计算列需要通过sortWhitelist指定

就像关联模型的列一样,计算列需要在sortWhitelist 选项中指定才能用于排序!

Cookbook > Controllers > Components > Pagination > Control which Fields Used for Ordering

通过分页选项

这里有一些选项,例如你可以在分页选项中定义计算列:

$this->paginate = [
    // ...
    'sortWhitelist' => [
        'id',
        'first_name',
        'last_name',
        'full_name',
        // ...
    ],
    'fields' => [
        'id',
        'first_name',
        'last_name',
        'full_name' => $this->Table->query()->func()->concat([
            'first_name' => 'literal',
            'last_name' => 'literal'
        ]),
        // ...
    ],
    'order' => [
        'full_name' => 'DESC'
    ]
];

自定义查找器

另一个更可重用的选项是使用自定义查找器:

$this->paginate = [
    // ...
    'sortWhitelist' => [
        'id',
        'first_name',
        'last_name',
        'full_name',
        // ...
    ],
    'finder' => 'withFullName',
    'order' => [
        'full_name' => 'DESC'
    ]
];
public function findWithFullName(\Cake\ORM\Query $query, array $options)

    return $query->select([
        'id',
        'first_name',
        'last_name',
        'full_name' => $query->func()->concat([
            'first_name' => 'literal',
            'last_name' => 'literal'
        ]),
        // ...
    ]);

Cookbook > Controllers > Components > Pagination > Using Controller::paginate() Cookbook > ... ORM > Retrieving Data & Results Sets > Custom Finder Methods

单独的自定义查询

也可以直接将查询对象传递给Controller::paginate()

$this->paginate = [
    // ...
    'sortWhitelist' => [
        'id',
        'first_name',
        'last_name',
        'full_name',
        // ...
    ],
    'order' => [
        'full_name' => 'DESC'
    ]
];

$query = $this->Table
    ->find()
    ->select(function (\Cake\ORM\Query $query) 
        return [
            'id',
            'first_name',
            'last_name',
            'full_name' => $query->func()->concat([
                'first_name' => 'literal',
                'last_name' => 'literal'
            ]),
            // ...
        ];
    );
$results = $this->paginate($query);

【讨论】:

我会看看这个(可能明天)。我会让你知道它是否有效。提前致谢。【参考方案2】:

将默认排序顺序设置为与虚拟字段相同:

public $paginate = [
  'order' => [
    'first_name' => 'ASC',
    'last_name' => 'ASC',
  ]
];

然后只需将以下内容添加到您的视图中,以防止分页器覆盖默认顺序,除非用户指定:

if (empty($_GET['direction']))  $this->Paginator->options(['url' => ['direction' => null, 'sort' => null]]); 

【讨论】:

以上是关于CakePHP 3.0 中虚拟字段/实体属性上的分页排序链接的主要内容,如果未能解决你的问题,请参考以下文章

CAKEPHP 3.x - 实体更新时出错 - 即使有值,也会声明缺少字段

CakePHP 3.0 保存我的关联数据

Cakephp 分页按计算字段排序( COUNT )

Cakephp 验证更新实体上的数据

CakePHP 3.0 ORM - 调试工作,翻转直播,抛出错误

CakePHP3:修改所有读取的实体