6

Geometry タイプを Doctrine に追加しようとしています。私の Doctrine DBAL バージョンと ORM バージョンは 2.1.7 です。

ここの指示に従おうとしました: Doctrine 2 Types - Custom Mapping Types

新しいデータ型は正常に作成されましたが、convertToPHPValueSQL メソッドに問題があります。データベースからジオメトリ列を取得するときに、関数 ST_AsText(' .. ') が常に呼び出されるようにします (データベースは PostgreSQL 9.1 + PostGIS 2.0.0 です)。

Doctrine DBAL 2.1のドキュメントには次のように書かれています:

Doctrine-DBAL の仕事は、型を SQL 宣言に変換することです。Doctrine が生成する SQL 宣言を変更できます。最初に、canRequireSQLConversion メソッドをオーバーライドして、この機能を有効にする必要があります。

<?php
public function canRequireSQLConversion()
{
    return true;
}  

次に、メソッド convertToPhpValueSQL および convertToDatabaseValueSQL をオーバーライドします。

<?php
public function convertToPHPValueSQL($sqlExpr, $platform)
{
    return 'MyMoneyFunction(\''.$sqlExpr.'\') ';
}

public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
{
    return 'MyFunction('.$sqlExpr.')';
}

次に、このタイプを Doctrine Type システムに登録し、データベース プラットフォームにフックする必要があります。

<?php
Type::addType('money', 'My\Project\Types\MoneyType');
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'money');

私はこれが好きでした(コードの多くはプレースホルダーコードですが、何か愚かなことをした場合は、すべてのアドバイスを歓迎します):

<?php

namespace Minupeenrad\Types;

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;

/**
 * Class for database column "geometry".
 *
 * @author Rauni Lillemets
 */
class GeometryType extends Type {
    const GEOMETRY = 'geometry';
    const SRID = 3301;

    public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform) {
        return 'geometry';
    }

    //Should create WKT object from WKT string. (or leave as WKT string)
    public function convertToPHPValue($value, AbstractPlatform $platform) {
        return $value; //+ 
    }

    //Should create WKT string from WKT object. (or leave as WKT string)
    public function convertToDatabaseValue($value, AbstractPlatform $platform) {
        return $value; //+
    }

    public function getName() {
        return self::GEOMETRY;
    }

    public function canRequireSQLConversion() {
        return true;
    }

    //Should give WKT
    public function convertToPHPValueSQL($sqlExpr, $platform) {
        return 'ST_AsText(\''.$sqlExpr.'\') '; //+
    }

    //Should create WKB
    public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) {
        return 'ST_GeomFromText(\''.$sqlExpr.'\', '.self::SRID.')'; //+
    }
}

この列を使用するエンティティを追加しました。

<?php
namespace Minupeenrad\Entities;

/**
 * Field
 *
 * @author Rauni Lillemets
 * @Entity
 * @Table(name="myfields.fields")
 */
class Field extends GeometryObject {
    /**
     * @Id
     * @Column(type="integer")
     * @GeneratedValue
     */
    private $id;

    /** 
     * @ManyToOne(targetEntity="User") 
     */
    private $user;

    /**
     * @Column(type = "string", length = "40")
     */
    private $fieldNumber;

    public function getId() {
        return $this->id;
    }

    public function getUser() {
        return $this->user;
    }

    public function setUser($user) {
        $this->user = $user;
    }

    public function getFieldNumber() {
        return $this->fieldNumber;
    }

    public function setFieldNumber($fieldNumber) {
        $this->fieldNumber = $fieldNumber;
    }
}
?>

しかし、私がこれを好きなら:

$entity = $em->find('\Minupeenrad\Entities\Field', 1);

Doctrine はデータベースへの SQL リクエストを次のように行います:

SELECT t0.id AS id1, t0.fieldNumber AS fieldnumber2, t0.geometry AS geometry3, t0.user_id AS user_id4
FROM myfields.fields t0
WHERE t0.id = ?

canRequireSQLConversion() は true を返しますが、Doctrine は私の convertToPHPValueSQL メソッドを使用しません。さらに、canRequireSQLConversion() が呼び出されても呼び出されないかどうかを確認するためのデバッグ コードを追加しました。私は何を間違っていますか?

PS: Stack Overflow を検索しようとしましたが、既に読んだ Doctrine 2.1.x マニュアルにリンクしているDoctrine 2 の GIS 拡張しか思いつきませんでした。

編集: ここで読みます: http://docs.doctrine-project.org/en/latest/cookbook/advanced-field-value-conversion-using-custom-mapping-types.html

EDIT2: 私のコードで間違っていた関数 getSqlDeclaration() を修正しました。コメントを追加しました。

より完全なチュートリアルのようです。

4

1 に答える 1

8

答えを見つけました。

Doctrine 2.1.7 では、$em->find() を使用すると、最終的に BasicEntityPersister()_getSelectColumnSQL() が呼び出されました。次のコードがあります: ( https://github.com/doctrine/doctrine2/blob/2.1.x/lib/Doctrine/ORM/Persisters/BasicEntityPersister.phpから取得)

/**
 * Gets the SQL snippet of a qualified column name for the given field name.
 *
 * @param string $field The field name.
 * @param ClassMetadata $class The class that declares this field. The table this class is
 * mapped to must own the column for the given field.
 * @param string $alias
 */
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
    $columnName = $class->columnNames[$field];
    $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
    $columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
    $this->_rsm->addFieldResult($alias, $columnAlias, $field);

    return "$sql AS $columnAlias";
}

このコードは明らかにメソッド「canRequireSQLConversion」を尊重しません

Doctrine の最新バージョン 2.3.1 ( https://github.com/doctrine/doctrine2/blob/2.3/lib/Doctrine/ORM/Persisters/BasicEntityPersister.phpを参照):

/**
 * Gets the SQL snippet of a qualified column name for the given field name.
 *
 * @param string $field The field name.
 * @param ClassMetadata $class The class that declares this field. The table this class is
 * mapped to must own the column for the given field.
 * @param string $alias
 */
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
    $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
         . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform);
    $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);

    $this->_rsm->addFieldResult($alias, $columnAlias, $field);

    if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
        $type = Type::getType($class->getTypeOfField($field));
        $sql = $type->convertToPHPValueSQL($sql, $this->_platform);
    }

    return $sql . ' AS ' . $columnAlias;
}

答えは私のORMを更新することです。

于 2013-01-04T10:43:38.797 に答える