/code/GeoLocation.php

https://github.com/dimension27/silverstripe-geolocator · PHP · 140 lines · 87 code · 16 blank · 37 comment · 2 complexity · 37cb241c6ebe4625d650aa557e3c7efb MD5 · raw file

  1. <?php
  2. class GeoLocation extends DataObject {
  3. public static $db = array(
  4. 'Name' => 'Varchar',
  5. 'State' => 'Varchar',
  6. 'Type' => 'Varchar',
  7. 'Postcode' => 'Varchar',
  8. 'Latitude' => 'Float',
  9. 'Longitude' => 'Float'
  10. );
  11. public static $belongs_many_many = array(
  12. 'Regions' => 'Region'
  13. );
  14. public static $summary_fields = array('Name', 'Postcode');
  15. public function getFullTitle() {
  16. return sprintf(
  17. "%s, %s %s",
  18. $this->Name,
  19. $this->State,
  20. $this->Postcode
  21. );
  22. }
  23. public function getNameCapitalised() {
  24. return ucwords( strtolower( $this->getField('Name') ) );
  25. }
  26. /**
  27. * Returns a list of GeoLocations for the given postcode
  28. * @param string $postcode The Postcode to search for
  29. * @return DataObjectSet
  30. */
  31. static public function getByPostcode($postcode) {
  32. return DataObject::get('GeoLocation', "`Postcode` = '$postcode'");
  33. }
  34. /**
  35. * Gets a single GeoLocation instance, by its unique Postcode
  36. * @param string $postcode The Postcode to search for
  37. * @return GeoLocation
  38. */
  39. static public function getFirstByPostcode($postcode) {
  40. return DataObject::get_one('GeoLocation', "`Postcode` = '$postcode'");
  41. }
  42. /**
  43. * Retrieve a list of GeoLocation's that match $keyword.
  44. *
  45. * @param string $keyword
  46. * @return DataObjectSet
  47. *
  48. * @author Alex Hayes <alex.hayes@dimension27.com>
  49. */
  50. static public function getByKeyword($keyword, $limit = false) {
  51. $keyword = Convert::raw2sql('%' . $keyword . '%');
  52. $postcode = substr($keyword, 1);
  53. return DataObject::get(
  54. 'GeoLocation',
  55. sprintf(
  56. "`Postcode` LIKE '%s' OR `State` LIKE '%s' OR `Name` LIKE '%s'",
  57. $postcode,
  58. $keyword,
  59. $keyword
  60. ),
  61. '', // Sort
  62. '', // Join
  63. $limit ? $limit : ''
  64. );
  65. }
  66. /**
  67. * @param DataObject $object The object containing the Relationship
  68. * @param string $postcodes The List of postcodes
  69. */
  70. static public function updatePostcodeRelationship( DataObject $object, $postcodes ) {
  71. //* debug */ $_REQUEST['showqueries'] = true;
  72. $geoLocations = $object->GeoLocations(); /* @var $geoLocations DataObjectSet */
  73. $geoLocations->removeAll();
  74. $postcodes = preg_split('/[ ,]+/', $postcodes);
  75. foreach ($postcodes as $postcode) {
  76. if ($postcode = trim($postcode)) {
  77. if ($geoLocation = self::getFirstByPostcode($postcode)) {
  78. $geoLocations->add($geoLocation);
  79. }
  80. }
  81. }
  82. $geoLocations->write();
  83. }
  84. /**
  85. * @param int $radius The distance from this GeoLocation (in km's)
  86. * @return DataObjectSet
  87. */
  88. public function getByDistance( $radius ) {
  89. $formula = $this->getDistanceFormula($this->Latitude, $this->Longitude);
  90. $sql = new SQLQuery();
  91. $sql->select('GeoLocation.*, '.$formula.' as Distance')
  92. ->from('GeoLocation')
  93. ->having('Distance < '.$radius)
  94. ->orderby('Distance');
  95. return singleton('GeoLocation')->buildDataObjectSet($sql->execute());
  96. }
  97. /**
  98. * @param int $radius
  99. * @return SQLQuery
  100. */
  101. public function getDistanceSQLQuery( $radius ) {
  102. $formula = $this->getDistanceFormula($this->Latitude, $this->Longitude);
  103. $sql = new SQLQuery();
  104. $sql->from('GeoLocation')->where($formula.' < '.$radius);
  105. return $sql;
  106. }
  107. /**
  108. * @param int $latitude
  109. * @param int $longitude
  110. * @param int $table
  111. * @return string
  112. */
  113. public function getDistanceFormula(
  114. $latitudeField = 'GeoLocation.Latitude', $longitudeField = 'GeoLocation.Longitude' ) {
  115. return self::getDistanceFormulaForCoords($this->Latitude, $this->Longitude, $latitudeField, $longitudeField);
  116. }
  117. public static function getDistanceFormulaForCoords( $latitude, $longitude,
  118. $latitudeField, $longitudeField ) {
  119. $factor = 6371; // for kilometres
  120. return "$factor * ACOS(COS(RADIANS('$latitude')) * COS(RADIANS($latitudeField)) "
  121. ."* COS(RADIANS($longitudeField) - RADIANS('$longitude')) + "
  122. ."SIN(RADIANS($latitude)) * SIN(RADIANS($latitudeField)))";
  123. }
  124. }