1
1
<?php
2
2
3
+ /**
4
+ * GoogleMapField
5
+ * Lets you record a precise location using latitude/longitude fields to a
6
+ * DataObject. Displays a map using the Google Maps API. The user may then
7
+ * choose where to place the marker; the landing coordinates are then saved.
8
+ * You can also search for locations using the search box, which uses the Google
9
+ * Maps Geocoding API.
10
+ * @author <@willmorgan>
11
+ */
3
12
class GoogleMapField extends FormField {
4
13
5
- protected
6
- $ data ,
7
- $ latField ,
8
- $ lngField ,
9
- $ options = array ();
10
-
11
- protected static
12
- $ defaults = array (
13
- 'fieldNames ' => array (
14
- 'lat ' => 'Lat ' ,
15
- 'lng ' => 'Lng ' ,
16
- ),
17
- 'showSearchBox ' => true ,
18
- 'apikey ' => null ,
19
- ),
20
- $ js_inserted = false ;
14
+ protected $ data ;
15
+
16
+ /**
17
+ * @var FormField
18
+ */
19
+ protected $ latField ;
20
+
21
+ /**
22
+ * @var FormField
23
+ */
24
+ protected $ lngField ;
25
+
26
+ /**
27
+ * @var FormField
28
+ */
29
+ protected $ zoomField ;
30
+
31
+ /**
32
+ * The merged version of the default and user specified options
33
+ * @var array
34
+ */
35
+ protected $ options = array ();
21
36
22
37
/**
23
38
* @param DataObject $data The controlling dataobject
@@ -28,82 +43,194 @@ public function __construct(DataObject $data, $title, $options = array()) {
28
43
$ this ->data = $ data ;
29
44
30
45
// Set up fieldnames
31
- $ this ->options = array_merge (self ::$ defaults , $ options );
46
+ $ this ->setupOptions ($ options );
47
+
48
+ $ this ->setupChildren ();
49
+
50
+ parent ::__construct ($ this ->getName (), $ title );
51
+ }
52
+
53
+ // Auto generate a name
54
+ public function getName () {
55
+ $ fieldNames = $ this ->getOption ('field_names ' );
56
+ return sprintf (
57
+ '%s_%s_%s ' ,
58
+ $ this ->data ->class ,
59
+ $ fieldNames ['Latitude ' ],
60
+ $ fieldNames ['Longitude ' ]
61
+ );
62
+ }
32
63
33
- $ fieldNames = $ this ->getOption ('fieldNames ' );
64
+ /**
65
+ * Merge options preserving the first level of array keys
66
+ * @param array $options
67
+ */
68
+ public function setupOptions (array $ options ) {
69
+ $ this ->options = static ::config ()->default_options ;
70
+ foreach ($ this ->options as $ name => &$ value ) {
71
+ if (isset ($ options [$ name ])) {
72
+ if (is_array ($ value )) {
73
+ $ value = array_merge ($ value , $ options [$ name ]);
74
+ }
75
+ else {
76
+ $ value = $ options [$ name ];
77
+ }
78
+ }
79
+ }
80
+ }
34
81
35
- // Auto generate a name
36
- $ name = sprintf ('%s_%s_%s ' , $ data ->class , $ fieldNames ['lat ' ], $ fieldNames ['lng ' ]);
82
+ /**
83
+ * Set up child hidden fields, and optionally the search box.
84
+ * @return FieldList the children
85
+ */
86
+ public function setupChildren () {
87
+ $ name = $ this ->getName ();
37
88
38
89
// Create the latitude/longitude hidden fields
90
+ $ this ->latField = HiddenField::create (
91
+ $ name .'[Latitude] ' ,
92
+ 'Lat ' ,
93
+ $ this ->recordFieldData ('Latitude ' )
94
+ )->addExtraClass ('googlemapfield-latfield ' );
95
+
96
+ $ this ->lngField = HiddenField::create (
97
+ $ name .'[Longitude] ' ,
98
+ 'Lng ' ,
99
+ $ this ->recordFieldData ('Longitude ' )
100
+ )->addExtraClass ('googlemapfield-lngfield ' );
101
+
102
+ $ this ->zoomField = HiddenField::create (
103
+ $ name .'[Zoom] ' ,
104
+ 'Zoom ' ,
105
+ $ this ->recordFieldData ('Zoom ' )
106
+ )->addExtraClass ('googlemapfield-zoomfield ' );
107
+
39
108
$ this ->children = new FieldList (
40
- $ this ->latField = HiddenField::create ($ name . '[ ' . $ fieldNames ['lat ' ] . '] ' , 'Lat ' , $ this ->getLatData ())->addExtraClass ('googlemapfield-latfield ' ),
41
- $ this ->lngField = HiddenField::create ($ name . '[ ' . $ fieldNames ['lng ' ] . '] ' , 'Lng ' , $ this ->getLngData ())->addExtraClass ('googlemapfield-lngfield ' ),
42
- TextField::create ('Search ' )
109
+ $ this ->latField ,
110
+ $ this ->lngField ,
111
+ $ this ->zoomField
112
+ );
113
+
114
+ if ($ this ->options ['show_search_box ' ]) {
115
+ $ this ->children ->push (
116
+ TextField::create ('Search ' )
43
117
->addExtraClass ('googlemapfield-searchfield ' )
44
118
->setAttribute ('placeholder ' , 'Search for a location ' )
45
- );
119
+ );
120
+ }
46
121
47
- parent :: __construct ( $ name , $ title ) ;
122
+ return $ this -> children ;
48
123
}
49
124
125
+ /**
126
+ * @param array $properties
127
+ * @see https://developers.google.com/maps/documentation/javascript/reference
128
+ * {@inheritdoc}
129
+ */
50
130
public function Field ($ properties = array ()) {
51
- $ key = $ this ->options ['apikey ' ] ? "&key= " .$ this ->options ['apikey ' ] : "" ;
52
- Requirements::javascript (GOOGLEMAPFIELD_BASE .'/javascript/GoogleMapField.js ' );
53
- Requirements::javascript ("//maps.googleapis.com/maps/api/js?callback=googlemapfieldInit " .$ key );
54
- Requirements::css (GOOGLEMAPFIELD_BASE .'/css/GoogleMapField.css ' );
55
131
$ jsOptions = array (
56
- 'coords ' => array ($ this ->getLatData (), $ this ->getLngData ()),
132
+ 'coords ' => array (
133
+ $ this ->recordFieldData ('Latitude ' ),
134
+ $ this ->recordFieldData ('Longitude ' )
135
+ ),
57
136
'map ' => array (
58
- 'zoom ' => 8 ,
137
+ 'zoom ' => $ this -> recordFieldData ( ' Zoom ' ) ?: $ this -> getOption ( ' map.zoom ' ) ,
59
138
'mapTypeId ' => 'ROADMAP ' ,
60
139
),
61
140
);
62
- if (!$ this ->options ['showSearchBox ' ]){
63
- $ this ->children ->removeByName ("Search " );
64
- }
65
- $ jsOptions = array_replace_recursive ($ jsOptions , $ this ->options );
66
- $ this ->setAttribute ('data-settings ' , Convert::array2json ($ jsOptions ));
67
141
142
+ $ jsOptions = array_replace_recursive ($ this ->options , $ jsOptions );
143
+ $ this ->setAttribute ('data-settings ' , Convert::array2json ($ jsOptions ));
144
+ $ this ->requireDependencies ();
68
145
return parent ::Field ($ properties );
69
146
}
70
147
71
- function setValue ($ value ) {
72
- $ this ->latField ->setValue ($ value [$ this ->getLatField ()]);
73
- $ this ->lngField ->setValue ($ value [$ this ->getLngField ()]);
148
+ /**
149
+ * Set up and include any frontend requirements
150
+ * @return void
151
+ */
152
+ protected function requireDependencies () {
153
+ $ gmapsParams = array (
154
+ 'callback ' => 'googlemapfieldInit ' ,
155
+ );
156
+ if ($ key = $ this ->getOption ('api_key ' )) {
157
+ $ gmapsParams ['key ' ] = $ key ;
158
+ }
159
+ Requirements::css (GOOGLEMAPFIELD_BASE .'/css/GoogleMapField.css ' );
160
+ Requirements::javascript (GOOGLEMAPFIELD_BASE .'/javascript/GoogleMapField.js ' );
161
+ Requirements::javascript ('//maps.googleapis.com/maps/api/js? ' . http_build_query ($ gmapsParams ));
162
+ }
163
+
164
+ /**
165
+ * {@inheritdoc}
166
+ */
167
+ public function setValue ($ record ) {
168
+ $ this ->latField ->setValue (
169
+ $ record ['Latitude ' ]
170
+ );
171
+ $ this ->lngField ->setValue (
172
+ $ record ['Longitude ' ]
173
+ );
174
+ $ this ->zoomField ->setValue (
175
+ $ record ['Zoom ' ]
176
+ );
74
177
return $ this ;
75
178
}
76
179
180
+ /**
181
+ * Take the latitude/longitude fields and save them to the DataObject.
182
+ * {@inheritdoc}
183
+ */
77
184
public function saveInto (DataObjectInterface $ record ) {
78
- $ record ->setCastedField ($ this ->getLatField (), $ this ->latField ->dataValue ());
79
- $ record ->setCastedField ($ this ->getLngField (), $ this ->lngField ->dataValue ());
185
+ $ record ->setCastedField ($ this ->childFieldName ('Latitude ' ), $ this ->latField ->dataValue ());
186
+ $ record ->setCastedField ($ this ->childFieldName ('Longitude ' ), $ this ->lngField ->dataValue ());
187
+ $ record ->setCastedField ($ this ->childFieldName ('Zoom ' ), $ this ->zoomField ->dataValue ());
80
188
return $ this ;
81
189
}
82
190
191
+ /**
192
+ * @return FieldList The Latitude/Longitude fields
193
+ */
83
194
public function getChildFields () {
84
195
return $ this ->children ;
85
196
}
86
197
87
- public function getLatField () {
88
- $ fieldNames = $ this ->getOption ('fieldNames ' );
89
- return $ fieldNames ['lat ' ];
198
+ protected function childFieldName ($ name ) {
199
+ $ fieldNames = $ this ->getOption ('field_names ' );
200
+ return $ fieldNames [$ name ];
201
+ }
202
+
203
+ protected function recordFieldData ($ name ) {
204
+ $ fieldName = $ this ->childFieldName ($ name );
205
+ return $ this ->data ->$ fieldName ?: $ this ->getDefaultValue ($ name );
90
206
}
91
207
92
- public function getLngField ( ) {
93
- $ fieldNames = $ this ->getOption ('fieldNames ' );
94
- return $ fieldNames [ ' lng ' ] ;
208
+ public function getDefaultValue ( $ name ) {
209
+ $ fieldValues = $ this ->getOption ('default_field_values ' );
210
+ return isset ( $ fieldValues [ $ name ]) ? $ fieldValues [ $ name ] : null ;
95
211
}
96
212
213
+ /**
214
+ * @return string The VALUE of the Latitude field
215
+ */
97
216
public function getLatData () {
98
- $ fieldNames = $ this ->getOption ('fieldNames ' );
99
- return $ this ->data ->$ fieldNames ['lat ' ];
217
+ $ fieldNames = $ this ->getOption ('field_names ' );
218
+ return $ this ->data ->$ fieldNames ['Latitude ' ];
100
219
}
101
220
221
+ /**
222
+ * @return string The VALUE of the Longitude field
223
+ */
102
224
public function getLngData () {
103
- $ fieldNames = $ this ->getOption ('fieldNames ' );
104
- return $ this ->data ->$ fieldNames ['lng ' ];
225
+ $ fieldNames = $ this ->getOption ('field_names ' );
226
+ return $ this ->data ->$ fieldNames ['Longitude ' ];
105
227
}
106
228
229
+ /**
230
+ * Get the merged option that was set on __construct
231
+ * @param string $name The name of the option
232
+ * @return mixed
233
+ */
107
234
public function getOption ($ name ) {
108
235
// Quicker execution path for "."-free names
109
236
if (strpos ($ name , '. ' ) === false ) {
@@ -124,6 +251,12 @@ public function getOption($name) {
124
251
}
125
252
}
126
253
254
+ /**
255
+ * Set an option for this field
256
+ * @param string $name The name of the option to set
257
+ * @param mixed $val The value of said option
258
+ * @return $this
259
+ */
127
260
public function setOption ($ name , $ val ) {
128
261
// Quicker execution path for "."-free names
129
262
if (strpos ($ name ,'. ' ) === false ) {
0 commit comments