function startup(&$controller) { $this->c =& $controller; if (!$this->runPlugin($controller)) { return false; } // Initialize vars $center = array(); $address = ''; $lat = 0; $lon = 0; if (!isset($controller->Config)) { $controller->Config = Configure::read('JreviewsSystem.Config'); } if (!isset($controller->Access)) { $controller->Config = Configure::read('JreviewsSystem.Access'); } $this->max_radius = Sanitize::getInt($controller->Config, 'geomaps.max_radius', $this->max_radius); $this->jr_lat = Sanitize::getString($controller->Config, 'geomaps.latitude'); $this->jr_lon = Sanitize::getString($controller->Config, 'geomaps.longitude'); if ($this->jr_lat == '' || $this->jr_lon == '') { return false; } // Setup vars used in startup and other plugin methods $this->google_url = Sanitize::getString($this->c->Config, 'geomaps.google_url', 'http://maps.google.com'); $this->google_api_key = trim(Sanitize::getString($controller->Config, 'geomaps.google_key')); $this->google_api_url = $this->google_url . "/maps?file=api&v=2&async=2&key={$this->google_api_key}&sensor=false"; $search_method = Sanitize::getString($controller->Config, 'geomaps.search_method', 'address'); // address/disabled $search_address_field = Sanitize::getString($controller->Config, 'geomaps.advsearch_input'); $default_radius = Sanitize::getString($controller->Config, 'geomaps.radius'); $this->distance_metric = array('mi' => __t("Miles", true), 'km' => __t("Km", true)); $this->distance_in = Sanitize::getString($controller->Config, 'geomaps.radius_metric', 'mi'); $this->jr_address1 = Sanitize::getString($controller->Config, 'geomaps.address1'); $this->jr_address2 = Sanitize::getString($controller->Config, 'geomaps.address2'); $this->jr_city = Sanitize::getString($controller->Config, 'geomaps.city'); $this->jr_state = Sanitize::getString($controller->Config, 'geomaps.state'); $this->jr_postal_code = Sanitize::getString($controller->Config, 'geomaps.postal_code'); $this->jr_country = Sanitize::getString($controller->Config, 'geomaps.country'); $this->country_def = Sanitize::getString($controller->Config, 'geomaps.default_country'); $this->gid = $controller->Access->gid; $this->address_fields = array_filter(array('address1' => $this->jr_address1, 'address2' => $this->jr_address2, 'city' => $this->jr_city, 'state' => $this->jr_state, 'postal_code' => $this->jr_postal_code, 'country' => $this->jr_country)); $this->geo_fields = array('lat' => $this->jr_lat, 'lon' => $this->jr_lon); $this->c->set(array('address_fields' => $this->address_fields, 'geo_fields' => $this->geo_fields)); /** * Address search checks */ if (isset($controller->data['Field']['Listing'])) { $address = Sanitize::getString($controller->data['Field']['Listing'], $search_address_field); } else { $address = Sanitize::getString($controller->params, $search_address_field); $lat = Sanitize::getFloat($controller->params, $this->jr_lat); $lon = Sanitize::getFloat($controller->params, $this->jr_lon); } /** * Plugin does different things for different controller methods */ switch ($controller->name) { case 'com_content': $this->published = true; $controller->Listing->cacheCallbacks[] = 'plgAfterAfterFind'; $controller->Listing->fields[] = "`Field`.{$this->jr_lat} AS `Geomaps.lat`"; $controller->Listing->fields[] = "`Field`.{$this->jr_lon} AS `Geomaps.lon`"; $controller->Listing->fields[] = "JreviewsCategory.marker_icon AS `Geomaps.icon`"; break; case 'listings': switch ($controller->action) { // Load the geomaps js library case 'create': // Submit a new listing // Submit a new listing case 'edit': // Edit a listing $this->published = true; $Html = new HtmlHelper(); $Html->app = 'jreviews'; $jsGlobals = 'var GeomapsGoogleApi = "' . $this->google_api_url . '";'; $jsGlobals .= 'var jr_lat = "' . $this->jr_lat . '";'; $jsGlobals .= 'var jr_lon = "' . $this->jr_lon . '";'; $jsGlobals .= 'var jr_country_def = "' . $this->country_def . '";'; $jsGlobals .= 'var geoAddressObj = {};'; foreach ($this->address_fields as $key => $field) { $jsGlobals .= "geoAddressObj.{$key} = '{$field}';"; } cmsFramework::addScript($controller->makeJS($jsGlobals), true); $Html->js('geomaps', true); if ($controller->action == 'edit') { $mapit_field = Sanitize::getString($controller->Config, 'geomaps.mapit_field'); if ($mapit_field) { $response = "jQuery(document).ready(function() { \r\n jQuery('#{$mapit_field}','#jr_listingForm').after('<span id=\"gm_geocode\">\r\n <input class=\"jrButton\" type=\"button\" onclick=\"geomaps.mapPopupSimple();\" value=\"" . __t("Map it", true) . "\" /> \r\n <input class=\"jrButton\" type=\"button\" onclick=\"geomaps.clearLatLng();\" value=\"" . __t("Clear LatLng", true) . "\" />\r\n </span>');\r\n });"; cmsFramework::addScript($controller->makeJS($response), true); } } break; // Add geomaps buttons after form is loaded // Add geomaps buttons after form is loaded case '_loadForm': // New listing - Loads submit listing form after category selection $this->published = true; $mapit_field = Sanitize::getString($controller->Config, 'geomaps.mapit_field'); if ($mapit_field) { $response = array(); $response[] = "\r\n jQuery('#gm_geocode').remove();jQuery('#{$mapit_field}','#jr_listingForm').after('<span id=\"gm_geocode\"><input class=\"jrButton\" type=\"button\" onclick=\"geomaps.mapPopupSimple();\" value=\"" . __t("Map it", true) . "\" /> <input class=\"jrButton\" type=\"button\" onclick=\"geomaps.clearLatLng();\" value=\"" . __t("Clear LatLng", true) . "\" /></span>');\r\n jQuery('#gm_geocode').find(':input').removeAttr('disabled');\r\n "; $controller->afterAjaxResponse = $response; } break; case '_save': // Checks if $isNew = Sanitize::getInt($controller->data['Listing'], 'id', 0) == 0 ? true : false; if (Sanitize::getInt($controller->Config, 'geomaps.autogeocode_new') && $isNew && isset($controller->data['Field']) && (Sanitize::getFloat($controller->data['Field']['Listing'], $this->jr_lat, null) == null || Sanitize::getFloat($controller->data['Field']['Listing'], $this->jr_lon, null) == null)) { // Build whole address from fields $address = ''; foreach ($this->address_fields as $key => $field) { ${$field} = Sanitize::getVar($controller->data['Field']['Listing'], $field, ''); if (${$field} != '') { $address .= ' ' . ${$field}; } elseif ($field == 'section') { $address .= " " . Sanitize::getString($controller->data, 'section'); } elseif ($field == 'parent_category') { $address .= " " . Sanitize::getString($controller->data, 'parent_category'); } elseif ($field == 'category') { $address .= " " . Sanitize::getString($controller->data, 'category'); } } if ($address != '' && !Sanitize::getVar($controller->data['Field']['Listing'], $this->jr_country, false) && $this->country_def != '') { $address .= ' ' . $this->country_def; } if ($address != '') { // Geocode address App::import('Component', 'geocoding'); $Geocoding = ClassRegistry::getClass('GeocodingComponent'); $Geocoding->Config =& $controller->Config; $response = $Geocoding->geocode($address); if ($response['status'] == 200) { $controller->data['Field']['Listing'][$this->jr_lat] = $response['lat']; $controller->data['__raw']['Field']['Listing'][$this->jr_lat] = $response['lat']; $controller->data['Field']['Listing'][$this->jr_lon] = $response['lon']; $controller->data['__raw']['Field']['Listing'][$this->jr_lon] = $response['lon']; } } } break; } break; case 'admin_listings': switch ($controller->action) { case 'index': case 'browse': case 'moderation': App::import('Helper', 'html'); $Html = new HtmlHelper(); $Html->app = 'jreviews'; $jsGlobals = 'var GeomapsGoogleApi = "' . $this->google_api_url . '";'; $jsGlobals .= 'var jr_lat = "' . $this->jr_lat . '";'; $jsGlobals .= 'var jr_lon = "' . $this->jr_lon . '";'; $jsGlobals .= 'var jr_country_def = "' . $this->country_def . '";'; $jsGlobals .= 'var geoAddressObj = {};'; foreach ($this->address_fields as $key => $field) { $jsGlobals .= "geoAddressObj.{$key} = '{$field}';"; } if ($controller->action == 'moderation') { ?> <script type="text/javascript"> /* <![CDATA[ */ <?php echo $jsGlobals; ?> if(null==jQuery('body').data('geomaps')){ jQuery.getScript('<?php echo $this->locateScript('geomaps'); ?> ',function(){jQuery('body').data('geomaps',1)}); } /* ]]> */ </script> <?php } else { cmsFramework::addScript($controller->makeJS($jsGlobals), true); $Html->js('geomaps', true); } break; case 'edit': $mapit_field = Sanitize::getString($controller->Config, 'geomaps.mapit_field'); if ($mapit_field) { $response = "jQuery('#{$mapit_field}').after('<span id=\"gm_geocode\"><input class=\"jrButton\" type=\"button\" onclick=\"geomaps.mapPopupSimple();\" value=\"" . __t("Map it", true) . "\" /> <input class=\"jrButton\" type=\"button\" onclick=\"geomaps.clearLatLng();\" value=\"" . __t("Clear LatLng", true) . "\" /></span>');"; $controller->pluginResponse = $response; } break; } break; // A search was performed, make distance the default ordering and copy the entered address to the search address field // A search was performed, make distance the default ordering and copy the entered address to the search address field case 'search': if ($search_method == 'disabled' || $address == '') { return; } if ($controller->action == '_process') { $this->published = true; // Enable the callbacks for this controller/method // Make distance the default ordering $controller->Config->list_order_default = 'distance'; if ($address != '' && in_array($search_method, array('address'))) { $controller->data['Field']['Listing'][$search_address_field] = $address; // Append default country if ($this->country_def != '') { $address .= ' ' . $this->country_def; } // Geocode address App::import('Component', 'geocoding'); $Geocoding = ClassRegistry::getClass('GeocodingComponent'); $Geocoding->Config =& $controller->Config; $response = $Geocoding->geocode($address); if ($response['status'] == 200) { $center = $response; } if ($center && !empty($center)) { $controller->data['Field']['Listing'][$this->jr_lat] = $center['lat']; $controller->data['Field']['Listing'][$this->jr_lon] = $center['lon']; unset($controller->data['Field']['Listing'][$this->jr_lat . '_operator']); unset($controller->data['Field']['Listing'][$this->jr_lon . '_operator']); } } } break; // Display search results // Display search results case 'categories': $controller->Listing->fields[] = "`Field`.{$this->jr_lat} AS `Geomaps.lat`"; $controller->Listing->fields[] = "`Field`.{$this->jr_lon} AS `Geomaps.lon`"; $controller->Listing->fields[] = "JreviewsCategory.marker_icon AS `Geomaps.icon`"; $this->published = true; // Enable the callbacks for this controller/method if ($search_method == 'disabled' || $lat == 0 || $lon == 0) { return; } if ($controller->action == 'search') { $radius = min(Sanitize::getFloat($controller->params, $this->radius_field, $default_radius), $this->max_radius); if ($search_method == 'disabled') { $this->published = false; return; } if ($lat != 0 && $lon != 0) { Configure::write('geomaps.enabled', true); // Used to show the Distance ordering in the jreviews.php helper in JReviews. $center = array('lat' => $lat, 'lon' => $lon); // Send center coordinates to theme $controller->set('GeomapsCenter', $center); $sort = $controller->params['order'] = Sanitize::getString($controller->params, 'order', 'distance'); // Clear address and coordinate field from parameters because it shouldn't be used on distance searches. Instead we use lat/lon via custom condition below unset($controller->params[$search_address_field], $controller->params['url'][$search_address_field], $controller->params[$this->jr_lat], $controller->params['url'][$this->jr_lat], $controller->params[$this->jr_lon], $controller->params['url'][$this->jr_lon]); $controller->passedArgs['url'] = preg_replace('/\\/' . $search_address_field . _PARAM_CHAR . '[\\p{L}-\\s0-9]+/i', '', $controller->passedArgs['url']); $controller->passedArgs['url'] = preg_replace('/\\/' . $search_address_field . _PARAM_CHAR . '[a-z0-9-\\s]+/i', '', $controller->passedArgs['url']); // One above doesn't work well in all cases, but required for non-latin characters in address $controller->passedArgs['url'] = preg_replace('/\\/' . $this->jr_lat . _PARAM_CHAR . '[\\-a-z0-9\\.\\s]+/i', '', $controller->passedArgs['url']); $controller->passedArgs['url'] = preg_replace('/\\/' . $this->jr_lon . _PARAM_CHAR . '[\\-a-z0-9\\.\\s]+/i', '', $controller->passedArgs['url']); // Create a square around the center to limite the number of rows processed in the zip code table // http://www.free-zipcodes.com/ // http://www.mysqlconf.com/mysql2008/public/schedule/detail/347 $degreeDistance = $this->distance_in == 'mi' ? 69.172 : 40076 / 360; $lat_range = $radius / $degreeDistance; $lon_range = $radius / abs(cos($center['lat'] * pi() / 180) * $degreeDistance); $min_lat = $center['lat'] - $lat_range; $max_lat = $center['lat'] + $lat_range; $min_lon = $center['lon'] - $lon_range; $max_lon = $center['lon'] + $lon_range; $squareArea = "`Field`.{$this->jr_lat} BETWEEN {$min_lat} AND {$max_lat} AND `Field`.{$this->jr_lon} BETWEEN {$min_lon} AND {$max_lon}"; // calculate the distance between two sets of longitude/latitude coordinates // From http://www.mysqlconf.com/mysql2008/public/schedule/detail/347 if ($this->distance_in == 'km') { $controller->Listing->fields['distance'] = "6371 * 2 * ASIN(SQRT( POWER(SIN(({$center['lat']} - {$this->jr_lat}) * pi()/180 / 2), 2) + \r\n COS({$center['lat']} * pi()/180) * COS({$this->jr_lat} * pi()/180) * POWER(SIN(({$center['lon']} -{$this->jr_lon}) * pi()/180 / 2), 2) )) AS `Geomaps.distance`"; } if ($this->distance_in == 'mi') { $controller->Listing->fields['distance'] = "3956 * 2 * ASIN(SQRT( POWER(SIN(({$center['lat']} - {$this->jr_lat}) * pi()/180 / 2), 2) + \r\n COS({$center['lat']} * pi()/180) * COS({$this->jr_lat} * pi()/180) * POWER(SIN(({$center['lon']} -{$this->jr_lon}) * pi()/180 / 2), 2) )) AS `Geomaps.distance`"; } $controller->Listing->conditions[] = $squareArea; if ($sort == 'distance') { $controller->Listing->order[] = '`Geomaps.distance` ASC'; } // Makes sure that only listings within given radius are shown because square limit might include further points // $controller->Listing->having[] = '`Geomaps.distance` <= ' . (int) $radius; // Override search theme suffix $theme_suffix = Sanitize::getString($controller->Config, 'geomaps.search_suffix'); if ($theme_suffix != '') { $controller->viewSuffix = $theme_suffix; } } } break; } }