CakePHP 3 - 默认情况下在 table 对象中使用 select() 中的 SQL 函数
CakePHP 3 - Use SQL function in select() by default in table object
我正在为包含一些 POINT
列的数据库设置系统。我使用食谱示例来构建自定义类型,它似乎可以正常工作。但是,要处理 POINT
s,我需要以特殊方式 SELECT
它们:
SELECT ST_AsText(location) as location ...
这对查询构建器来说并不难:
$this->Houses->find()->select(['location' => 'ST_AsText(location)'])
但是,我更希望默认情况下发生这种情况。
我正在考虑使用 beforeFind
事件,但我找不到以下伪代码的正确函数:
public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
{
if 'location' in query->getSelectedFields():
replace 'location' by 'location' => 'ST_AsText(location)'
}
当一个字段将被包含时,我如何用一个函数替换它?理想情况下,即使我还没有从一个函数中调用 ->select(...)
控制器。
关于 CakePHP 话语的较早的类似问题: https://discourse.cakephp.org/t/read-data-from-spatial-mysql-field-point-polygon/2124
在 中找到了我的解决方案。
这适用于 CakePHP 3.8。我决定将事件处理放在一个行为中,以便于重用:
<?php
// src/Model/Behavior/SpatialBehavior.php
namespace App\Model\Behavior;
use Cake\ORM\Behavior;
use Cake\ORM\Table;
use Cake\Event\Event;
use ArrayObject;
use Cake\ORM\Query;
/**
* Spatial behavior
*
* Make sure spatial columns are loaded as text when needed.
*
* @property \Cake\ORM\Table $_table
*/
class SpatialBehavior extends Behavior
{
/**
* Default configuration.
*
* @var array
*/
protected $_defaultConfig = [];
/**
* Callback before each find is executed
*
* @param Event $event
* @param Query $query
* @param ArrayObject $options
* @param type $primary
*/
public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
{
$query->traverse(function (&$value) use ($query)
{
if (is_array($value) && empty($value))
{
// Built up standard query when ->select() was never used
//$query->all(); // Execute query to learn columns
$query->select($this->_table);
}
$defaultTypes = $query->getDefaultTypes();
foreach ($value as $key => $field)
{
if (in_array($defaultTypes[$field], ['point', 'polygon']))
{
$value[$key] = $query->func()->ST_AsText([
$this->_table->aliasField($field) => 'identifier'
]);
}
}
$query->select($value);
}, ['select']);
}
}
在我的 table 对象中:
class HousesTable extends Table
{
public function initialize(array $config)
{
//...
$this->addBehavior('Spatial');
//...
}
我正在为包含一些 POINT
列的数据库设置系统。我使用食谱示例来构建自定义类型,它似乎可以正常工作。但是,要处理 POINT
s,我需要以特殊方式 SELECT
它们:
SELECT ST_AsText(location) as location ...
这对查询构建器来说并不难:
$this->Houses->find()->select(['location' => 'ST_AsText(location)'])
但是,我更希望默认情况下发生这种情况。
我正在考虑使用 beforeFind
事件,但我找不到以下伪代码的正确函数:
public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
{
if 'location' in query->getSelectedFields():
replace 'location' by 'location' => 'ST_AsText(location)'
}
当一个字段将被包含时,我如何用一个函数替换它?理想情况下,即使我还没有从一个函数中调用 ->select(...)
控制器。
关于 CakePHP 话语的较早的类似问题: https://discourse.cakephp.org/t/read-data-from-spatial-mysql-field-point-polygon/2124
在
这适用于 CakePHP 3.8。我决定将事件处理放在一个行为中,以便于重用:
<?php
// src/Model/Behavior/SpatialBehavior.php
namespace App\Model\Behavior;
use Cake\ORM\Behavior;
use Cake\ORM\Table;
use Cake\Event\Event;
use ArrayObject;
use Cake\ORM\Query;
/**
* Spatial behavior
*
* Make sure spatial columns are loaded as text when needed.
*
* @property \Cake\ORM\Table $_table
*/
class SpatialBehavior extends Behavior
{
/**
* Default configuration.
*
* @var array
*/
protected $_defaultConfig = [];
/**
* Callback before each find is executed
*
* @param Event $event
* @param Query $query
* @param ArrayObject $options
* @param type $primary
*/
public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
{
$query->traverse(function (&$value) use ($query)
{
if (is_array($value) && empty($value))
{
// Built up standard query when ->select() was never used
//$query->all(); // Execute query to learn columns
$query->select($this->_table);
}
$defaultTypes = $query->getDefaultTypes();
foreach ($value as $key => $field)
{
if (in_array($defaultTypes[$field], ['point', 'polygon']))
{
$value[$key] = $query->func()->ST_AsText([
$this->_table->aliasField($field) => 'identifier'
]);
}
}
$query->select($value);
}, ['select']);
}
}
在我的 table 对象中:
class HousesTable extends Table
{
public function initialize(array $config)
{
//...
$this->addBehavior('Spatial');
//...
}