1
0
mirror of synced 2024-12-14 15:16: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
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
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).
*
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();