CakePHP 3.5 始终将 asText() MySQL 函数应用于空间字段

CakePHP 3.5 Always apply asText() MySQL function to Spatial field

我有一个自定义 PolygonType,它表示 MySQL table 中的 POLYGON() 字段。

class PolygonType extends BaseType implements ExpressionTypeInterface
{
    public function toPHP($value, Driver $d)
    {
        // $value is binary, requires unpack()
    }
}

我可以在每个 查找上使用$query->func()->astext(),但我想知道是否可以始终 应用MySQL 的 AsText() 函数,而不是选择此字段时(类似于插入数据时可以使用 toExpression() 的方式)。

AFAIK 没有这样的功能,类型 classes 和 select 子句内容永远不会接触。

如果您想将此应用于所有发现,那么您可以使用 Model.beforeFind() 事件,遍历 select 子句并将字段转换为表达式。这是一个简单粗暴的示例,其中 fieldPOLYGON 类型列的名称:

// in the respective table class

use Cake\Event\Event;
use Cake\ORM\Query;

// ...

public function beforeFind(Event $event, Query $query, \ArrayObject $options, $primary)
{
    $query->traverse(
        function (&$value) use ($query) {
            if (empty($value)) {
                $value = $query->aliasFields($this->getSchema()->columns());
            }

            foreach ($value as $key => $field) {
                if (is_string($field) &&
                    $this->aliasField($field) === $this->aliasField('field')
                ) {
                    unset($value[$key]);
                    $value[key($query->aliasField($field))] = $query->func()->AsText([
                        $this->aliasField('field') => 'identifier'
                    ]);
                }
            }
        },
        ['select']
    );
}

您可能还需要将 $field 考虑为表达式,以防该字段可能在其中使用并且也需要在那里进行转换。

另一种方法是在类型 class' toPHP() 方法中转换 PHP 级别的数据,如您的代码示例中所示。

另见

基于 ndp's ,可以通过 $query->getDefaultTypes() 检查字段类型并根据需要应用 SQL 函数。但是,如果最初没有声明任何字段,$value 为空(例如,当使用 Table::get() 时,因此也会对此进行检查。

public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
{
    $query->traverse(
        function (&$value) use ($query) {

            if (is_array($value) && empty($value)) {
                $query->all();
            }

            $defaultTypes = $query->getDefaultTypes();

            foreach ($value as $key => $field) {
                if (in_array($defaultTypes[$field], ['point', 'polygon'])) {
                    $value[$key] = $query->func()->astext([
                        $this->aliasField($field) => 'identifier'
                    ]);
                }
            }

            $query->select($value);
        },
        ['select']
    );
}