-
Notifications
You must be signed in to change notification settings - Fork 48
/
Geocodable.php
126 lines (114 loc) · 4.63 KB
/
Geocodable.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<?php
namespace Symbiote\Addressable;
use SilverStripe\Core\Config\Config;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\CompositeField;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\Forms\ToggleCompositeField;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ORM\DataExtension;
use SilverStripe\Core\Injector\Injector;
/**
* Adds automatic geocoding to a {@link Addressable} object. Uses the Google
* Maps API to save latitude and longitude on write.
*
* @package silverstripe-addressable
*/
class Geocodable extends DataExtension
{
/**
* Disable geocoding for onBeforeWrite().
*
* You may want to do disable this when modifying lots
* of data in a dev/task at once.
*
* @var boolean
* @config
*/
private static $is_geocodable = true;
private static $db = array(
'LatLngOverride' => 'Boolean',
'Lat' => 'Decimal(10,7)',
'Lng' => 'Decimal(10,7)'
);
public function onBeforeWrite()
{
$record = $this->getOwner();
// Reset last error
$record->__geocodable_exception = null;
if (!Config::inst()->get(__CLASS__, 'is_geocodable')) {
// Allow user-code to disable Geocodable. This was added
// so that dev/tasks that write a *lot* of Geocodable records can
// ignore this expensive logic.
return;
}
if ($record->LatLngOverride) {
// A CMS user disabled automatical retrieval of Lat/Lng
// and most likely input their own values.
return;
}
if (!$record->hasMethod('isAddressChanged') ||
!$record->isAddressChanged()) {
return;
}
$address = $record->getFullAddress();
$region = strtolower($record->Country);
$point = [];
try {
$point = Injector::inst()->get(GeocodeService::class)->addressToPoint($address, $region);
} catch (GeocodeServiceException $e) {
// Default behaviour is to ignore errors like ZERO_RESULTS or this just failing.
$record->__geocodable_exception = $e;
return;
}
if (!$point) {
return;
}
$record->Lat = $point['lat'];
$record->Lng = $point['lng'];
}
/**
* @return GeocodeServiceException|null
*/
public function getLastGeocodableException()
{
return $this->owner->__geocodable_exception;
}
public function updateCMSFields(FieldList $fields)
{
$record = $this->getOwner();
$fields->removeByName(array('LatLngOverride', 'Lat', 'Lng'));
// Adds Lat/Lng fields for viewing in the CMS
$compositeField = CompositeField::create();
$compositeField->push($overrideField = CheckboxField::create('LatLngOverride', 'Override Latitude and Longitude?'));
$overrideField->setDescription('Check this box and save to be able to edit the latitude and longitude manually.');
if ($record->Lng && $record->Lat) {
$googleMapURL = 'https://maps.google.com/?q='.$record->Lat.','.$record->Lng;
$googleMapDiv = '<div class="field"><label class="left" for="Form_EditForm_MapURL_Readonly">Google Map</label><div class="middleColumn"><a href="'.$googleMapURL.'" target="_blank">'.$googleMapURL.'</a></div></div>';
$compositeField->push(LiteralField::create('MapURL_Readonly', $googleMapDiv));
}
if ($record->LatLngOverride) {
$compositeField->push(TextField::create('Lat', 'Lat'));
$compositeField->push(TextField::create('Lng', 'Lng'));
} else {
$compositeField->push(ReadonlyField::create('Lat_Readonly', 'Lat', $record->Lat));
$compositeField->push(ReadonlyField::create('Lng_Readonly', 'Lng', $record->Lng));
}
if ($record->hasExtension(Addressable::class)) {
// If using addressable, put the fields with it
$fields->addFieldToTab('Root.Address', ToggleCompositeField::create('Coordinates', 'Coordinates', $compositeField));
} elseif ($record instanceof SiteTree) {
// If SIteTree but not using Addressable, put after 'Metadata' toggle composite field
$fields->insertAfter($compositeField, 'ExtraMeta');
} else {
$fields->addFieldToTab('Root.Main', ToggleCompositeField::create('Coordinates', 'Coordinates', $compositeField));
}
}
public function updateFrontEndFields(FieldList $fields)
{
$fields->removeByName(array('LatLngOverride', 'Lat', 'Lng'));
}
}