1
0
mirror of synced 2024-12-14 23:26:04 +03:00

Finalize first version

This commit is contained in:
jsor 2011-11-29 10:31:07 +01:00
parent 228d8517c7
commit cbefb7c543

View File

@ -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 This article describes the third way by implementing the MySQL specific column
type `Point <http://dev.mysql.com/doc/refman/5.5/en/gis-class-point.html>`_. type `Point <http://dev.mysql.com/doc/refman/5.5/en/gis-class-point.html>`_.
The `Point` type is part of the `Spatial extension <http://dev.mysql.com/doc/refman/5.5/en/spatial-extensions.html>`_ The ``Point`` type is part of the `Spatial extension <http://dev.mysql.com/doc/refman/5.5/en/spatial-extensions.html>`_
of MySQL and enables you to store a single location in a coordinate space by of MySQL and enables you to store a single location in a coordinate space by
using x and y coordinates. using x and y coordinates. You can use the Point type to store a
As you might have already guessed, you can use the Point type to store a
longitude/latitude pair to represent a geographic location. longitude/latitude pair to represent a geographic location.
The entity The entity
@ -42,27 +40,53 @@ The entity class:
/** /**
* @Column(type="point") * @Column(type="point")
* *
* @var \Geo\Point * @var \Geo\ValueObject\Point
*/ */
private $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; $this->point = $point;
} }
/** /**
* @return \Geo\Point * @return \Geo\ValueObject\Point
*/ */
public function getPoint() public function getPoint()
{ {
return $this->point; 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: The point class:
.. code-block:: php .. code-block:: php
@ -73,17 +97,28 @@ The point class:
class Point class Point
{ {
/**
* @param float $latitude
* @param float $longitude
*/
public function __construct($latitude, $longitude) public function __construct($latitude, $longitude)
{ {
$this->latitude = $latitude; $this->latitude = $latitude;
$this->longitude = $longitude; $this->longitude = $longitude;
} }
/**
* @return float
*/
public function getLatitude() public function getLatitude()
{ {
return $this->latitude; return $this->latitude;
} }
/**
* @return float
*/
public function getLongitude() public function getLongitude()
{ {
return $this->longitude; return $this->longitude;
@ -93,10 +128,7 @@ The point class:
The mapping type The mapping type
---------------- ----------------
As you may have noticed, we used the custom type ``point`` in the ``@Column`` Now we're going to create the ``point`` type and implement all required methods.
docblock annotation of the ``$point`` field.
Now we're going to create this type and implement all required methods.
.. code-block:: php .. 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); 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).
* The format of the string representation format is called `Well-known text (WKT)
<http://en.wikipedia.org/wiki/Well-known_text>`_. 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 <http://dev.mysql.com/doc/refman/5.5/en/creating-spatial-values.html#function_pointfromtext>`_
and `AsText <http://dev.mysql.com/doc/refman/5.5/en/functions-to-convert-geometries-between-formats.html#function_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 <dql-user-defined-functions>` for
``PointFromText``.
Example usage
-------------
.. code-block:: php
<?php
// Bootstrapping stuff...
// $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
// Setup custom mapping type
use Doctrine\DBAL\Types\Type;
Type::addType('point', 'Geo\Types\Point');
$em->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();