没有不值得去解决的问题,也没有不值得去学习的技术!

yii\base\InvalidArgumentException: Malformed UTF-8 Characters, Possibly Incorrectly Encoded in C:\wwwroot\object\src\vendor\yiisoft\yii2\helpers\BaseJson.php:147

Inspecting the API response data, the cause is identified as the checkin_location_coordinates field in the response being a MySQL point type

1. I inspected the response data from the API and identified the cause: the checkin_location_coordinates field in the response is a MySQL point type. See Figure 1.

Inspecting the API response data, the cause is identified as the checkin_location_coordinates field in the response being a MySQL point type
Figure 1

2. I decided to adjust the SQL query to use MySQL spatial functions (such as ST_X and ST_Y) to extract the longitude and latitude, thereby avoiding direct manipulation of the POINT field. Using the addSelect() method, I can add the longitude and latitude fields on top of querying all existing fields. Then, I would unset the checkin_location_coordinates field.

SQL

SELECT * FROM `survey_forms` WHERE (`id`='1825203750690273') AND (`user_id`='1825203750689422') LIMIT 1

SQL

SELECT *, ST_X(checkin_location_coordinates) AS `checkin_location_longitude`, ST_Y(checkin_location_coordinates) AS `checkin_location_latitude` FROM `survey_forms` WHERE `id`='1825203750690273' LIMIT 1

PHP

$form = SurveyForm::find()
	->select('*') // 查询所有字段
	->addSelect([
		'ST_X(checkin_location_coordinates) AS checkin_location_longitude',
		'ST_Y(checkin_location_coordinates) AS checkin_location_latitude',
	])
	->where([
	'id' => $id,
])->limit(1)->asArray()->one();
unset($form['checkin_location_coordinates']);

3. However, this approach requires adjustments to every query involving this model. The workload exceeded expectations. I tried to implement automatic querying of checkin_location_longitude and checkin_location_latitude in the model file, followed by unsetting checkin_location_coordinates. I found that the fields() method was never executed. Ultimately, the only working solution was to call unset($form[‘checkin_location_coordinates’]); directly in the controller. I decided to stick with the approach from step 2.

PHP

    public $checkin_location_longitude;
    public $checkin_location_latitude;

    public function afterFind()
    {
        parent::afterFind();
        // 设置经度和纬度
        $this->checkin_location_longitude = Yii::$app->db->createCommand("SELECT ST_X(checkin_location_coordinates) FROM {$this->tableName()} WHERE id = :id", [':id' => $this->id])->queryScalar();

        $this->checkin_location_latitude = Yii::$app->db->createCommand("SELECT ST_Y(checkin_location_coordinates) FROM {$this->tableName()} WHERE id = :id", [':id' => $this->id])->queryScalar();

        // 排除原始字段
        unset($this->checkin_location_coordinates);
    }

    public function fields()
    {
        $fields = parent::fields();
        Yii::debug('Fields before modification: ' . print_r($fields, true));
        // 添加自定义字段
        $fields['checkin_location_longitude'] = 'checkin_location_longitude';
        $fields['checkin_location_latitude'] = 'checkin_location_latitude';
        // 排除原始字段
        unset($fields['checkin_location_coordinates']);
        Yii::debug('Fields after modification: ' . print_r($fields, true));
        return $fields;
    }

PHP

$form = SurveyForm::find()->where([
            'id' => $id,
        ])->with(['fields', 'fields.diagram_image', 'fields.options', 'cover_image', 'submit_success_image'])->limit(1)->asArray()->one();

unset($form['checkin_location_coordinates']);

4. I ultimately decided to abandon the point field type. I changed the schema to use checkin_location_longitude decimal(9,6) and checkin_location_latitude decimal(9,6).

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系