如何使用Paginator排序顺序的函数表达式?

时间:2015-10-10 14:36:56

标签: php mysql cakephp pagination cakephp-3.0

在数据库中对IP地址进行排序时,我使用MySQL提供的INET_ATON函数。

现在,当我在CakePHP 3中尝试这样做时(我不熟悉),我失败了。

这是我得到的:

class Ip extends Entity
{

    /**
     * Fields that can be mass assigned using newEntity() or patchEntity().
     *
     * Note that when '*' is set to true, this allows all unspecified fields to
     * be mass assigned. For security purposes, it is advised to set '*' to false
     * (or remove it), and explicitly make individual fields accessible as needed.
     *
     * @var array
     */
    protected $_accessible = [
        '*' => true,
        'id' => false,
    ];

    protected $_virtual = ['ip_address'];

    protected function _getIpAddress()
    {
        $vc = (new FunctionsBuilder())->inet_aton(['ip' => 'literal']);
        return $vc;
    }
}

这是我的Controller方法。

<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\ORM\TableRegistry;
use Cake\Validation\Validator;
use Cake\Database\FunctionsBuilder;
/**
 * Ips Controller
 *
 * @property \App\Model\Table\IpsTable $Ips
 */
class IpsController extends AppController
{

    /**
     * Index method
     *
     * @return void
     */
    public function index()
    {
        $this->paginate = [
            'contain' => ['Users'],
            'order' => [(new FunctionsBuilder())->inet_aton(['ip' => 'literal'])]
        ];
        $this->set('ips', $this->paginate($this->Ips));
        $this->set('_serialize', ['ips']);
    }

通过知道对虚拟属性的排序可能不起作用,我不确定我是否正在使用正确的方法来完成此操作。

是否有人建议您采用最佳做法来实现此方案?

1 个答案:

答案 0 :(得分:1)

使用其他列

我个人而是另外将IP的整数表示存储在一个单独的列中,并使用该表进行排序。这不仅可以提供更好的性能,因为DBMS可以使用索引,它还可以避免处理函数表达式所需的额外逻辑,并允许您像往常一样使用分页组件。

在视图中,然后只需使用新列的名称,并手动定义要为排序链接显示的名称,例如

<?= $this->Paginator->sort('ip_int', 'IP') ?>

使用表达式

通过选项或自定义查询

在当前状态下,分页不能处理函数表达式,而只能处理列名。至少在与分页视图助手的组合中也是如此!虽然您可以为order选项定义表达式,例如

$this->paginate['order'] = [
    new \Cake\Database\Expression\OrderClauseExpression(
        $this->Ips->query()->func()->inet_aton(['ip' => 'literal']),
        'ASC'
    )
];

或使用自定义查询,例如

$query = $this->Ips->find();
$query->orderAsc($query->func()->inet_aton(['ip' => 'literal']));

$this->set('ips', $this->paginate($query));

您必须使用一些自定义逻辑才能使其与视图一起工作,因为分页帮助程序仅用于处理列名(字符串)。

使用视图帮助程序进行动态排序

现在,如果您也想使用分页视图助手,您必须创建一些逻辑来评估助手生成的排序列和方向,并手动配置选项/查询,类似于上面的示例。

这是一个基本的例子,使用Query::orderAsc()Query::orderDesc()方法,可以在使用函数表达式时定义方向(表达式不能通过{{1与其他值组合) }})。

Query::order()

这应该主要是自我解释,首先检查由Paginator帮助者处理的$query = $this->Ips->find(); $sort = $this->request->query('sort'); if ($sort === null || $sort === 'ip') { $method = 'orderAsc'; if ($this->request->query('direction') === 'desc') { $method = 'orderDesc'; } $query->{$method}($query->func()->inet_aton(['ip' => 'literal'])); } $this->set('articles', $this->paginate($query)); 密钥是否通过,如果它不是或者是,并且它是您的IP列,请申请您可能设置的sort密钥的自定义订单。如果direction不是您的IP列,只需忽略它,Paginator将获取值并评估并照常使用它们。

类似地,您可以在手动创建sort个实例时设置方向,但是我个人可能会坚持使用自定义查询和功能构建器。

多干一点?

如果您想让它更具可重用性,您可能需要查看自定义/扩展分页器组件,自定义查找程序和行为。

实体是数据容器

最后但并非最不重要的是,您的实体与此无关,它只是一个数据容器,所以抛弃了虚拟财产,它们无法用于查找。

另见