Laravel 模型与 POINT/POLYGON 等使用 DB::raw 表达式

2022-01-08 00:00:00 spatial php mysql laravel laravel-4

我有一些使用地理空间字段的模型,例如 POINTPOLYGONMULTIPOLYGON.我想告诉我的模型以一种特殊的方式处理这些属性,以便我获得所需的模型属性集.

I have some models that use geospatial fields like POINT, POLYGON or MULTIPOLYGON. I would like to tell my model to process these attributes in a special way, for me to get the desired model attributes set.

示例:每个常规 Model::find() 或其他 Eloquent 方法都应在存储或检索数据库值之前应用一些自定义代码.

Example: Every regular Model::find() or other Eloquent method should apply some custom code before storing or after retrieving a database value.

$area->surface 是 MySQL 中的 POLYGON 字段,但在我的模型类中,我想处理 $area->surfare 作为一个点数组.

$area->surface is a POLYGON field in MySQL, but in my model class I would like to handle $area->surfare as an array of points.

SELECT 上,因此我想 1) 使用原始表达式获取值以获取值的文本表示,以及 2) 通过一些自定义 PHP 代码将 WKT 字符串转换为一个数组.

On SELECT I would therefore like to 1) fetch the value using a raw expression to get a text representation of the value, and 2) go through some custom PHP code to convert the WKT string into an array.

INSERT/UPDATE 我想获取属性值(一个数组)并 1)将其转换为 WKT 字符串,然后 2)使用 DB 原始语句将其写入数据库存储值.

On INSERT/UPDATE I would like to take the attribute value (an array) and 1) convert it into a WKT string, whereafter 2) it's written to the databse using a DB raw statement that stores the value.

我想在字段的基础上进行设置,而不是作为每个字段的特殊 get/set 函数,而不是在控制器中 - 因为我有很多地理字段.

I'd like to set this on a field-basis, not as special get/set functions for each field, and not in the controllers - because I have many geosptial fields.

有没有办法在 Laravel 中实现这一点?

(同一个问题的一个更抽象的版本,是我如何创建代码来操作实际 SQL 查询的属性值,而不仅仅是通过修改器和访问器进行一些基于值的操作)

更新:深入研究 Laravel Doc 和 API,我发现也许 Eloquent::newQuery() 方法是我需要操作的?无论是 SELECTINSERT 还是 UPDATE,这都会用于任何查询吗?

UPDATE: Looking deeper into the Laravel Doc and API, I found that maybe the Eloquent::newQuery() method is what I need to manipulate? Would that be used for any query regardless if SELECT, INSERT or UPDATE?

推荐答案

我们现在已经通过使用以下功能扩展我们的基础模型来解决所有模型的通用问题:

We have now solved this generically for all models by extending our base model with the following functionaly:

  • 我们定义了一个包含几何数据的属性数组.
  • 如果我们希望将其作为文本自动加载,我们会根据每个模型来决定.
  • 我们更改默认查询构建器以从数据库中选择几何属性作为文本.

这是我们现在使用的基本模型的摘录:

Here is an excerpt from the base model we now use:

/**
 * The attributes that hold geometrical data.
 *
 * @var array
 */
protected $geometry = array();

/**
 * Select geometrical attributes as text from database.
 *
 * @var bool
 */
protected $geometryAsText = false;

/**
 * Get a new query builder for the model's table.
 * Manipulate in case we need to convert geometrical fields to text.
 *
 * @param  bool  $excludeDeleted
 * @return IlluminateDatabaseEloquentBuilder
 */
public function newQuery($excludeDeleted = true)
{
    if (!empty($this->geometry) && $this->geometryAsText === true)
    {
        $raw = '';
        foreach ($this->geometry as $column)
        {
            $raw .= 'AsText(`' . $this->table . '`.`' . $column . '`) as `' . $column . '`, ';
        }
        $raw = substr($raw, 0, -2);
        return parent::newQuery($excludeDeleted)->addSelect('*', DB::raw($raw));
    }
    return parent::newQuery($excludeDeleted);
}

相关文章