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();