在数据库中对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']);
}
通过知道对虚拟属性的排序可能不起作用,我不确定我是否正在使用正确的方法来完成此操作。
是否有人建议您采用最佳做法来实现此方案?
答案 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
个实例时设置方向,但是我个人可能会坚持使用自定义查询和功能构建器。
如果您想让它更具可重用性,您可能需要查看自定义/扩展分页器组件,自定义查找程序和行为。
最后但并非最不重要的是,您的实体与此无关,它只是一个数据容器,所以抛弃了虚拟财产,它们无法用于查找。