From 129b9d0945247690c72917ba5711e2ad8f083237 Mon Sep 17 00:00:00 2001 From: jsor Date: Mon, 28 Nov 2011 11:52:17 +0100 Subject: [PATCH 1/5] Setup article --- en/cookbook/custom-mapping-type-value-sql.rst | 8 ++++++++ en/reference/basic-mapping.rst | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 en/cookbook/custom-mapping-type-value-sql.rst diff --git a/en/cookbook/custom-mapping-type-value-sql.rst b/en/cookbook/custom-mapping-type-value-sql.rst new file mode 100644 index 000000000..83d19e968 --- /dev/null +++ b/en/cookbook/custom-mapping-type-value-sql.rst @@ -0,0 +1,8 @@ +Database-level field value conversion using custom mapping types +================================================================ + +.. sectionauthor:: Jan Sorgalla + +When creating entities, you sometimes have the need to transform field values +before they are saved to the database. In Doctrine you can use Custom Mapping +Types to solve this (see: :ref:`my-reference-label`). diff --git a/en/reference/basic-mapping.rst b/en/reference/basic-mapping.rst index 0e1ace490..146c71d6f 100644 --- a/en/reference/basic-mapping.rst +++ b/en/reference/basic-mapping.rst @@ -300,6 +300,8 @@ list: - ``scale``: (optional, default 0) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) +.. _reference-basic_mapping-custom_mapping_types: + Custom Mapping Types -------------------- From 1300758499d950bbb5e827f036f4734b9c7dfd78 Mon Sep 17 00:00:00 2001 From: jsor Date: Mon, 28 Nov 2011 15:19:49 +0100 Subject: [PATCH 2/5] Rename article and add more text --- ...-conversion-using-custom-mapping-types.rst | 91 +++++++++++++++++++ en/cookbook/custom-mapping-type-value-sql.rst | 8 -- en/index.rst | 3 +- 3 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst delete mode 100644 en/cookbook/custom-mapping-type-value-sql.rst diff --git a/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst new file mode 100644 index 000000000..73f1b10a8 --- /dev/null +++ b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst @@ -0,0 +1,91 @@ +Advanced field value conversion using custom mapping types +========================================================== + +.. sectionauthor:: Jan Sorgalla + +When creating entities, you sometimes have the need to transform field values +before they are saved to the database. In Doctrine you can use Custom Mapping +Types to solve this (see: :ref:`reference-basic_mapping-custom_mapping_types`). + +There are several ways to achieve this: converting the value inside the Type +class, converting the value on the database-level or a combination of both. + +This article describes the third way by implementing the MySQL specific column +type `Point `_. + +The `Point` type is part of the `Spatial extension `_ +of MySQL and enables you to store a single location in a coordinate space by +using x and y coordinates. + +As you might have already guessed, you can use the Point type to store a +longitude/latitude pair to represent a geographic location. + +The entity +---------- + +We create a simple entity which contains a field ``$point`` which should hold +a value object ``Point`` representing the latitude and longitude of the position. + +The entity class: + +.. code-block:: php + + point = $point; + } + + /** + * @return \Geo\Point + */ + public function getPoint() + { + return $this->point; + } + } + +The point class: + +.. code-block:: php + + latitude = $latitude; + $this->longitude = $longitude; + } + + public function getLatitude() + { + return $this->latitude; + } + + public function getLongitude() + { + return $this->longitude; + } + } diff --git a/en/cookbook/custom-mapping-type-value-sql.rst b/en/cookbook/custom-mapping-type-value-sql.rst deleted file mode 100644 index 83d19e968..000000000 --- a/en/cookbook/custom-mapping-type-value-sql.rst +++ /dev/null @@ -1,8 +0,0 @@ -Database-level field value conversion using custom mapping types -================================================================ - -.. sectionauthor:: Jan Sorgalla - -When creating entities, you sometimes have the need to transform field values -before they are saved to the database. In Doctrine you can use Custom Mapping -Types to solve this (see: :ref:`my-reference-label`). diff --git a/en/index.rst b/en/index.rst index ef2638705..b4816c73c 100644 --- a/en/index.rst +++ b/en/index.rst @@ -66,4 +66,5 @@ Cookbook cookbook/strategy-cookbook-introduction cookbook/validation-of-entities cookbook/working-with-datetime - cookbook/mysql-enums \ No newline at end of file + cookbook/mysql-enums + cookbook/advanced-field-value-conversion-using-custom-mapping-types \ No newline at end of file From bece5f0f915dcd03cb0ce79dcce856e750e161e3 Mon Sep 17 00:00:00 2001 From: jsor Date: Mon, 28 Nov 2011 15:22:55 +0100 Subject: [PATCH 3/5] Change ref name --- ...vanced-field-value-conversion-using-custom-mapping-types.rst | 2 +- en/reference/basic-mapping.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst index 73f1b10a8..5b79d2c4d 100644 --- a/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst +++ b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst @@ -5,7 +5,7 @@ Advanced field value conversion using custom mapping types When creating entities, you sometimes have the need to transform field values before they are saved to the database. In Doctrine you can use Custom Mapping -Types to solve this (see: :ref:`reference-basic_mapping-custom_mapping_types`). +Types to solve this (see: :ref:`reference-basic-mapping-custom-mapping-types`). There are several ways to achieve this: converting the value inside the Type class, converting the value on the database-level or a combination of both. diff --git a/en/reference/basic-mapping.rst b/en/reference/basic-mapping.rst index 146c71d6f..90970de2e 100644 --- a/en/reference/basic-mapping.rst +++ b/en/reference/basic-mapping.rst @@ -300,7 +300,7 @@ list: - ``scale``: (optional, default 0) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) -.. _reference-basic_mapping-custom_mapping_types: +.. _reference-basic-mapping-custom-mapping-types: Custom Mapping Types -------------------- From 228d8517c75d89a10fb12640e5f190a34aec9be0 Mon Sep 17 00:00:00 2001 From: Jan Sorgalla Date: Mon, 28 Nov 2011 21:06:01 +0100 Subject: [PATCH 4/5] Add type --- ...-conversion-using-custom-mapping-types.rst | 72 +++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst index 5b79d2c4d..addf2751d 100644 --- a/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst +++ b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst @@ -23,8 +23,8 @@ longitude/latitude pair to represent a geographic location. The entity ---------- -We create a simple entity which contains a field ``$point`` which should hold -a value object ``Point`` representing the latitude and longitude of the position. +We create a simple entity whith a field ``$point`` which holds a value object +``Point`` representing the latitude and longitude of the position. The entity class: @@ -32,7 +32,7 @@ The entity class: longitude; } } + +The mapping type +---------------- + +As you may have noticed, we used the custom type ``point`` in the ``@Column`` +docblock annotation of the ``$point`` field. + +Now we're going to create this type and implement all required methods. + +.. code-block:: php + + getLongitude(), $value->getLatitude()); + } + + return $value; + } + + public function convertToPHPValueSQL($sqlExpr, AbstractPlatform $platform) + { + return sprintf('AsText(%s)', $sqlExpr); + } + + public function convertToDatabaseValue($sqlExpr, AbstractPlatform $platform) + { + return sprintf('GeomFromText(%s)', $sqlExpr); + } + } + +A few notes about the implementation: + + * \ No newline at end of file From cbefb7c543f6f53db8a61bba4af5759a3706c0f5 Mon Sep 17 00:00:00 2001 From: jsor Date: Tue, 29 Nov 2011 10:31:07 +0100 Subject: [PATCH 5/5] Finalize first version --- ...-conversion-using-custom-mapping-types.rst | 128 +++++++++++++++--- 1 file changed, 112 insertions(+), 16 deletions(-) diff --git a/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst index addf2751d..4aad58919 100644 --- a/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst +++ b/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst @@ -13,11 +13,9 @@ class, converting the value on the database-level or a combination of both. This article describes the third way by implementing the MySQL specific column type `Point `_. -The `Point` type is part of the `Spatial extension `_ +The ``Point`` type is part of the `Spatial extension `_ of MySQL and enables you to store a single location in a coordinate space by -using x and y coordinates. - -As you might have already guessed, you can use the Point type to store a +using x and y coordinates. You can use the Point type to store a longitude/latitude pair to represent a geographic location. The entity @@ -42,27 +40,53 @@ The entity class: /** * @Column(type="point") * - * @var \Geo\Point + * @var \Geo\ValueObject\Point */ private $point; /** - * @param \Geo\Point $point + * @Column(type="string") + * + * @var string */ - public function setPoint(\Geo\Point $point) + private $address; + + /** + * @param \Geo\ValueObject\Point $point + */ + public function setPoint(\Geo\ValueObject\Point $point) { $this->point = $point; } /** - * @return \Geo\Point + * @return \Geo\ValueObject\Point */ public function getPoint() { return $this->point; } + + /** + * @param string $address + */ + public function setAddress($address) + { + $this->address = $address; + } + + /** + * @return string + */ + public function getAddress() + { + return $this->address; + } } +We use the custom type ``point`` in the ``@Column`` docblock annotation of the +``$point`` field. We will create this custom mapping type in the next chapter. + The point class: .. code-block:: php @@ -73,17 +97,28 @@ The point class: class Point { + + /** + * @param float $latitude + * @param float $longitude + */ public function __construct($latitude, $longitude) { $this->latitude = $latitude; $this->longitude = $longitude; } + /** + * @return float + */ public function getLatitude() { return $this->latitude; } + /** + * @return float + */ public function getLongitude() { return $this->longitude; @@ -93,10 +128,7 @@ The point class: The mapping type ---------------- -As you may have noticed, we used the custom type ``point`` in the ``@Column`` -docblock annotation of the ``$point`` field. - -Now we're going to create this type and implement all required methods. +Now we're going to create the ``point`` type and implement all required methods. .. code-block:: php @@ -144,12 +176,76 @@ Now we're going to create this type and implement all required methods. return sprintf('AsText(%s)', $sqlExpr); } - public function convertToDatabaseValue($sqlExpr, AbstractPlatform $platform) + public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) { - return sprintf('GeomFromText(%s)', $sqlExpr); + return sprintf('PointFromText(%s)', $sqlExpr); } } -A few notes about the implementation: +We do a 2-step conversion here. In the first step, we convert the ``Point`` +object into a string representation before saving to the database (in the +``convertToDatabaseValue`` method) and back into an object after fetching the +value from the database (in the ``convertToPHPValue`` method). - * \ No newline at end of file +The format of the string representation format is called `Well-known text (WKT) +`_. The advantage of this format +is, that it is both human readable and parsable by MySQL. + +Internally, MySQL stores geometry values in a binary format that is not +identical to the WKT format. So, we need to let MySQL transform the WKT +representation into its internal format. + +This is where the ``convertToPHPValueSQL`` and ``convertToDatabaseValueSQL`` +methods come into play. + +This methods wrap a sql expression (the WKT representation of the Point) into +MySQL functions `PointFromText `_ +and `AsText `_ +which convert WKT strings to and from the internal format of MySQL. + +.. note:: + + When using DQL queries, the ``convertToPHPValueSQL`` and + ``convertToDatabaseValueSQL`` methods only apply to identification variables + and path expressions in SELECT clauses. Expressions in WHERE clauses are + **not** wrapped! + + If you want to use Point values in WHERE clauses, you have to implement a + :doc:`user defined function ` for + ``PointFromText``. + +Example usage +------------- + +.. code-block:: php + + getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('point', 'point'); + + // Store a Location object + use Geo\Entity\Location; + use Geo\ValueObject\Point; + + $location = new Location(); + + $location->setAddress('1600 Amphitheatre Parkway, Mountain View, CA'); + $location->setPoint(new Point(37.4220761, -122.0845187)); + + $em->persist($location); + $em->flush(); + $em->clear(); + + // Fetch the Location object + $query = $em->createQuery("SELECT l FROM Geo\Entity\Location WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'"); + $location = $query->getSingleResult(); + + /* @var Geo\ValueObject\Point */ + $point = $location->getPoint();