Completed
Push — master ( 83571a...9e9b74 )
by Nic
30s
created

code/Locator.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Class Locator
5
 *
6
 * @property bool $AutoGeocode
7
 * @property bool $ModalWindow
8
 * @property string $Unit
9
 * @method Categories|ManyManyList $Categories
10
 */
11
class Locator extends Page
12
{
13
14
    /**
15
     * @var array
16
     */
17
    private static $db = array(
18
        'AutoGeocode' => 'Boolean',
19 1
        'ModalWindow' => 'Boolean',
20
        'Unit' => 'Enum("m,km","m")',
21 1
    );
22
23
    /**
24 1
     * @var array
25 1
     */
26 1
    private static $many_many = array(
27
        'Categories' => 'LocationCategory',
28
    );
29 1
30 1
    /**
31
     * @var array
32
     */
33 1
    private static $defaults = array(
34 1
        'AutoGeocode' => true,
35 1
    );
36 1
37 1
    /**
38 1
     * @var string
39 1
     */
40
    private static $singular_name = 'Locator';
41 1
    /**
42
     * @var string
43 1
     */
44
    private static $plural_name = 'Locators';
45
    /**
46 3
     * @var string
47
     */
48 3
    private static $description = 'Find locations on a map';
49
50 3
    /**
51 3
     * @return FieldList
52 3
     */
53 3
    public function getCMSFields()
54
    {
55
        $fields = parent::getCMSFields();
56 1
57
        // Settings
58 1
        $fields->addFieldsToTab('Root.Settings', array(
59
            HeaderField::create('DisplayOptions', 'Display Options', 3),
60
            OptionsetField::create('Unit', 'Unit of measure', array('m' => 'Miles', 'km' => 'Kilometers')),
61 1
            CheckboxField::create('AutoGeocode', 'Auto Geocode - Automatically filter map results based on user location')
62
                ->setDescription('Note: if any locations are set as featured, the auto geocode is automatically disabled.'),
63 1
            CheckboxField::create('ModalWindow', 'Modal Window - Show Map results in a modal window'),
64
        ));
65
66
        // Filter categories
67
        $config = GridFieldConfig_RelationEditor::create();
68
        if (class_exists('GridFieldAddExistingSearchButton')) {
69
            $config->removeComponentsByType('GridFieldAddExistingAutocompleter');
70
            $config->addComponent(new GridFieldAddExistingSearchButton());
71
        }
72
        $categories = $this->Categories();
73
        $categoriesField = GridField::create('Categories', 'Categories', $categories, $config)
74
            ->setDescription('only show locations from the selected category');
75
76
        // Filter
77
        $fields->addFieldsToTab('Root.Filter', array(
78
            HeaderField::create('CategoryOptionsHeader', 'Location Filtering', 3),
79
            $categoriesField,
80
        ));
81
82
        $this->extend('updateCMSFields', $fields);
83
84
        return $fields;
85
    }
86
87
    /**
88
     * @param array $filter
89
     * @param array $filterAny
90
     * @param array $exclude
91
     * @param null $filterByCallback
92
     * @return ArrayList
93
     */
94
    public static function locations(
95
        $filter = array(),
96
        $filterAny = array(),
97
        $exclude = array(),
98
        $filterByCallback = null
99
    )
100
    {
101
        $locationsList = ArrayList::create();
102
103
        // filter by ShowInLocator
104
        $filter['ShowInLocator'] = 1;
105
106
        $locations = Location::get()->filter($filter);
107
108
        if (!empty($filterAny)) {
109
            $locations = $locations->filterAny($filterAny);
110
        }
111
        if (!empty($exclude)) {
112
            $locations = $locations->exclude($exclude);
113
        }
114
115
        if ($filterByCallback !== null && is_callable($filterByCallback)) {
116
            $locations = $locations->filterByCallback($filterByCallback);
117
        }
118
119
        if ($locations->exists()) {
120
            $locationsList->merge($locations);
121
        }
122
123
        return $locationsList;
124
    }
125
126
    /**
127
     * @return DataList
128
     */
129
    public static function getAllCategories()
130
    {
131
        return LocationCategory::get();
132
    }
133
134
    /**
135
     * @param null $id
136
     * @return bool
137
     */
138
    public static function getPageCategories($id = null)
139
    {
140
        if ($id) {
141
            if ($locator = self::get()->byID($id)) {
142
                return $locator->Categories();
143
            }
144
145
            return false;
146
        }
147
148
        return false;
149
    }
150
151
152
}
153
154
/**
155
 * Class Locator_Controller
156
 */
157
class Locator_Controller extends Page_Controller
158
{
159
    /**
160
     * @var array
161
     */
162
    private static $allowed_actions = array(
163
        'xml',
164
    );
165
166
    /**
167
     * Set Requirements based on input from CMS
168 1
     */
169
    public function init()
170 1
    {
171 1
        parent::init();
172 1
173 1
        $themeDir = SSViewer::get_theme_folder();
174
175 1
        // google maps api key
176 1
        $key = Config::inst()->get('GoogleGeocoding', 'google_api_key');
177 1
178 1
        $locations = $this->Items($this->request);
179
180 1
        Requirements::javascript('framework/thirdparty/jquery/jquery.js');
181
        if ($locations) {
182 1
            Requirements::javascript('http://maps.google.com/maps/api/js?key=' . $key);
183
            Requirements::javascript('locator/thirdparty/handlebars/handlebars-v1.3.0.js');
184 1
            Requirements::javascript('locator/thirdparty/jquery-store-locator/js/jquery.storelocator.js');
185
        }
186
187
        Requirements::css('locator/css/map.css');
188
189
        $featuredInList = ($locations->filter('Featured', true)->count() > 0);
190
191
        $featured = $featuredInList
192 1
            ? 'featuredLocations: true'
193
            : 'featuredLocations: false';
194 1
195 1
        // map config based on user input in Settings tab
196 1
        // AutoGeocode or Full Map
197
        if ($this->data()->AutoGeocode) {
198 1
            $load = $featuredInList
199
                ? 'autoGeocode: false, fullMapStart: true, storeLimit: 1000, maxDistance: true,'
200
                : 'autoGeocode: true, fullMapStart: false,';
201 1
        } else {
202
            $load = 'autoGeocode: false, fullMapStart: true, storeLimit: 1000, maxDistance: true,';
203
        }
204
205
        /*$load = ($this->data()->AutoGeocode) ?
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
206
            'autoGeocode: true, fullMapStart: false,' :
207
            'autoGeocode: false, fullMapStart: true, storeLimit: 1000, maxDistance: true,';*/
208
209
        $base = Director::baseFolder();
210
        $themePath = $base . '/' . $themeDir;
211
212
        $listTemplatePath = (file_exists($themePath . '/templates/location-list-description.html')) ?
213
            $themeDir . '/templates/location-list-description.html' :
214
            'locator/templates/location-list-description.html';
215
        $infowindowTemplatePath = (file_exists($themePath . '/templates/infowindow-description.html')) ?
216
            $themeDir . '/templates/infowindow-description.html' :
217
            'locator/templates/infowindow-description.html';
218
219
        // in page or modal
220
        $modal = ($this->data()->ModalWindow) ? 'modalWindow: true' : 'modalWindow: false';
221
222
        $kilometer = ($this->data()->Unit == 'km') ? 'lengthUnit: "km"' : 'lengthUnit: "m"';
223
224
        // pass GET variables to xml action
225
        $vars = $this->request->getVars();
226
        unset($vars['url']);
227
        unset($vars['action_index']);
228
        $url = '';
229
        if (count($vars)) {
230
            $url .= '?' . http_build_query($vars);
231
        }
232
        $link = $this->Link() . 'xml.xml' . $url;
233
234
        // init map
235
        if ($locations) {
236
            Requirements::customScript("
237
                $(function($) {
238
                    $('#map-container').storeLocator({
239
                        " . $load . "
240
                        dataLocation: '" . $link . "',
241
                        listTemplatePath: '" . $listTemplatePath . "',
242
                        infowindowTemplatePath: '" . $infowindowTemplatePath . "',
243
                        originMarker: true,
244
                        " . $modal . ',
245
                        ' . $featured . ",
246
                        slideMap: false,
247
                        zoomLevel: 0,
248
                        noForm: true,
249
                        formID: 'Form_LocationSearch',
250
                        inputID: 'Form_LocationSearch_Address',
251
                        categoryID: 'Form_LocationSearch_category',
252
                        distanceAlert: -1,
253
                        " . $kilometer . '
254
                    });
255
                });
256
            ');
257
        }
258
    }
259
260
    /**
261
     * @param SS_HTTPRequest $request
262
     *
263
     * @return ViewableData_Customised
264
     */
265
    public function index(SS_HTTPRequest $request)
266
    {
267
        $locations = $this->Items($request);
268
269
        return $this->customise(array(
270
            'Locations' => $locations,
271
        ));
272
    }
273
274
    /**
275
     * Return a XML feed of all locations marked "show in locator"
276
     *
277
     * @param SS_HTTPRequest $request
278
     * @return HTMLText
279
     */
280
    public function xml(SS_HTTPRequest $request)
281
    {
282
        $locations = $this->Items($request);
283
284
        return $this->customise(array(
285
            'Locations' => $locations,
286
        ))->renderWith('LocationXML');
287
    }
288
289
    /**
290
     * @param SS_HTTPRequest $request
291
     *
292
     * @return ArrayList
293
     */
294
    public function Items(SS_HTTPRequest $request)
295
    {
296
        $request = ($request) ? $request : $this->request;
297
298
        $filter = array();
299
        $filterAny = array();
300
        $exclude = ['Lat' => 0.00000, 'Lng' => 0.00000];
301
302
        // only show locations marked as ShowInLocator
303
        $filter['ShowInLocator'] = 1;
304
305
        // search across all address related fields
306
        $address = ($request->getVar('Address')) ? $request->getVar('Address') : false;
307
        if ($address && $this->data()->AutoGeocode == 0) {
308
            $filterAny['Address:PartialMatch'] = $address;
309
            $filterAny['Suburb:PartialMatch'] = $address;
310
            $filterAny['State:PartialMatch'] = $address;
311
            $filterAny['Postcode:PartialMatch'] = $address;
312
            $filterAny['Country:PartialMatch'] = $address;
313
        } else {
314
            unset($filter['Address']);
315
        }
316
317
        // search for category from form, else categories from Locator
318
        $category = ($request->getVar('CategoryID')) ? $request->getVar('CategoryID') : false;
319
        if ($category) {
320
            $filter['CategoryID:ExactMatch'] = $category;
321
        } elseif ($this->Categories()->exists()) {
322
            $categories = $this->Categories();
323
            $categoryArray = array();
324
            foreach ($categories as $category) {
325
                array_push($categoryArray, $category->ID);
326
            }
327
            $filter['CategoryID'] = $categoryArray;
328
        }
329
330
        $locations = Locator::locations($filter, $filterAny, $exclude);
331
332
        return $locations;
333
    }
334
335
    /**
336
     * LocationSearch form.
337
     *
338
     * Search form for locations, updates map and results list via AJAX
339
     *
340
     * @return Form
341
     */
342
    public function LocationSearch()
343
    {
344
        $fields = FieldList::create(
345
            $address = TextField::create('Address', '')
346
                ->setAttribute('placeholder', 'address or zip code')
347
        );
348
349
        $filterCategories = Locator::getPageCategories($this->ID);
350
        $allCategories = Locator::getAllCategories();
351
352
        if ($allCategories->Count() > 0) {
353
            $categories = ArrayList::create();
354
            if ($filterCategories->Count() > 0) {
355
                if ($filterCategories->Count() != 1) {
356
                    $categories = $filterCategories;
357
                }
358
            } else {
359
                $categories = $allCategories;
360
            }
361
362
            if ($categories->count() > 0) {
363
                $fields->push(
364
                    DropdownField::create(
365
                        'CategoryID',
366
                        '',
367
                        $categories->map()
368
                    )->setEmptyString('All Categories'));
369
            }
370
        }
371
372
        $actions = FieldList::create(
373
            FormAction::create('index', 'Search')
374
        );
375
376
        if (class_exists('BootstrapForm')) {
377
            $form = BootstrapForm::create($this, 'LocationSearch', $fields, $actions);
378
        } else {
379
            $form = Form::create($this, 'LocationSearch', $fields, $actions);
380
        }
381
382
        return $form
383
            ->setFormMethod('GET')
384
            ->setFormAction($this->Link())
385
            ->disableSecurityToken()
386
            ->loadDataFrom($this->request->getVars());
387
    }
388
389
}
390