Skip to content

Commit

Permalink
v1.2.0!
Browse files Browse the repository at this point in the history
- **Added search and sorting support.**
- Added optional Google API Server Key setting
- **_WARNING:_** This update will break any map fields that are NOT standalone (global) or in a Matrix field.
  • Loading branch information
Tam committed Jun 7, 2016
1 parent 364af9a commit b2aa642
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 16 deletions.
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
![Simple Map](resources/banner.jpg)

# Simple Map
A beautifully simple Google Map field type for Craft CMS. Full localization support, and compatible with Matrix.
A beautifully simple Google Map field type for Craft CMS. Full localization support, compatible with Matrix, supports
searching by location and sorting by distance.

## Installation
Clone this repo into `craft/plugins/simplemap`.
Expand All @@ -15,15 +16,32 @@ The field type will return an array containing `lat`, `lng`, `zoom`, `address`,
This contains the locations address, broken down into its constituent parts. All values are optional so you'll need to have checks on any you use to make sure they exist.
A list of the available values can be found [here](https://developers.google.com/maps/documentation/geocoding/intro#Types).

**Searching and Sorting**

You can search for elements using the location specified in your map field. When searching by your map field you also have the option to sort the results by distance.

```twig
{% set entries = craft.entries.myMapField({
location: 'Maidstone, Kent, UK',
radius: 100,
unit: 'mi'
}).order('distance') %}
```

- `location`: Can either be an address string (requires a Google Maps Geocoding API key) or a Lat Lng Array (`{ 'lat': 51.27219908, 'lng': 0.51545620 }` or `craft.simpleMap.latLng(51.27219908, 0.51545620)`).
- `radius`: The radius around the location to search. Defaults to `50`.
- `unit`: The unit of measurement for the search. Can be either `km` (kilometers) or `mi` (miles). Defaults to `km`.

![How it looks](resources/preview.png)

## Changelog

### 1.2.0 [DEV - Work In Progress]
- Added optional Google API Server Key setting
### 1.2.0
- **Added search and sorting support.**
- Added optional Google API Server Key setting
- **_WARNING:_** This update will break any map fields that are NOT standalone (global) or in a Matrix field.

### 1.1.2 [RELEASE]
### 1.1.2
- Fix \#5 via @jripmeester - Fixed Lat / Lng being populated with function, not number.

### 1.1.1
Expand Down
6 changes: 3 additions & 3 deletions SimpleMapPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public function getDescription()

public function getVersion()
{
return '1.1.3';
return '1.2.0';
}

public function getSchemaVersion()
{
return '0.0.2';
return '0.0.5';
}

public function getDeveloper()
Expand Down Expand Up @@ -66,4 +66,4 @@ public function getSettingsHtml()
));
}

}
}
2 changes: 2 additions & 0 deletions fieldtypes/SimpleMap_MapFieldType.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public function modifyElementsQuery(DbCommand $query, $value)
{
if ($value !== null)
craft()->simpleMap->modifyQuery($query, $value);

return $query;
}

}
59 changes: 59 additions & 0 deletions migrations/m160606_162300_simpleMap_updateFieldStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Craft;

class m160606_162300_simpleMap_updateFieldStorage extends BaseMigration
{
public function safeUp()
{
if (!craft()->db->tableExists('simplemap_maps'))
craft()->plugins->getPlugin('simpleMap')->createTables();

$fields = craft()->fields->getAllFields();

foreach ($fields as $field)
{
if ($field->type === 'SimpleMap_Map')
$this->_transferData($field, 'content');

if ($field->type === 'Matrix')
foreach (craft()->matrix->getBlockTypesByFieldId($field->id) as $blockType)
foreach ($blockType->getFields() as $blockTypeField)
if ($blockTypeField->type == 'SimpleMap_Map')
$this->_transferData($blockTypeField, 'matrixcontent_' . $field->handle, $blockType->handle . '_' . $blockTypeField->handle);
}

return true;
}

private function _transferData(FieldModel $field, $tableName, $fieldHandle = "")
{
if (!$fieldHandle)
$fieldHandle = $field->handle;

$tableData = craft()->db->createCommand()
->select('elementId, locale, field_' . $fieldHandle)
->from($tableName)
->where('field_' . $fieldHandle . ' IS NOT NULL')
->queryAll();

foreach ($tableData as $row) {
$record = new SimpleMap_MapRecord;
$record->ownerId = $row['elementId'];
$record->fieldId = $field->id;
$record->ownerLocale = $row['locale'];

$f = json_decode($row['field_' . $fieldHandle], true);

$record->setAttribute('lat', $f['lat']);
$record->setAttribute('lng', $f['lng']);
$record->setAttribute('zoom', $f['zoom']);
$record->setAttribute('address', $f['address']);
if ($f !== null && array_key_exists('parts', $f))
$record->setAttribute('parts', json_encode($f['parts']));

$record->save();
}
}

}
4 changes: 2 additions & 2 deletions records/SimpleMap_MapRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
class SimpleMap_MapRecord extends BaseRecord {

public static $dec = array(AttributeType::Number, 'column' => ColumnType::Decimal, 'length' => 12, 'decimals' => 8);
const TABLE_NAME = 'simplemap_maps';

public function getTableName()
{
return 'simplemap_maps';
return static::TABLE_NAME;
}

public function defineRelations()
{
return array(
// 'element' => array(static::BELONGS_TO, 'ElementRecord', 'id', 'required' => true, 'onDelete' => static::CASCADE),
'owner' => array(static::BELONGS_TO, 'ElementRecord', 'required' => true, 'onDelete' => static::CASCADE),
'ownerLocale' => array(static::BELONGS_TO, 'LocaleRecord', 'ownerLocale', 'onDelete' => static::CASCADE, 'onUpdate' => static::CASCADE),
'field' => array(static::BELONGS_TO, 'FieldRecord', 'required' => true, 'onDelete' => static::CASCADE)
Expand Down
10 changes: 10 additions & 0 deletions releases.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,15 @@
"notes": [
"Fix #5 via @jripmeester - Fixed Lat / Lng being populated with function, not number."
]
},
{
"version": "1.2.0",
"downloadUrl": "https://github.com/ethercreative/SimpleMap/archive/v1.2.0.zip",
"date": "2016-06-07T10:00:00-08:00",
"notes": [
"**Added search and sorting support.**",
"Added optional Google API Server Key setting",
"**_WARNING:_** This update will break any map fields that are NOT standalone (global) or in a Matrix field."
]
}
]
132 changes: 126 additions & 6 deletions services/SimpleMapService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,32 @@

class SimpleMapService extends BaseApplicationComponent {

public $settings;

public $searchLatLng;
public $searchEarthRad;

/// PUBLIC ///

/**
* Initialize
*/
public function init()
{
$this->settings = craft()->plugins->getPlugin('SimpleMap')->getSettings();
}

/**
* Get Map Field
*
* @param SimpleMap_MapFieldType $fieldType
* @param $value
* @return SimpleMap_MapModel
*/
public function getField (SimpleMap_MapFieldType $fieldType, $value)
{
$owner = $fieldType->element;
$field = $fieldType->model;
$field = $fieldType->model;;

$record = SimpleMap_MapRecord::model()->findByAttributes(array(
'ownerId' => $owner->id,
Expand All @@ -28,11 +50,17 @@ public function getField (SimpleMap_MapFieldType $fieldType, $value)
$model = new SimpleMap_MapModel;
}

$model->distance = null;
$model->distance = $this->_calculateDistance($model);

return $model;
}

/**
* Save Map Field
*
* @param SimpleMap_MapFieldType $fieldType
* @return bool
*/
public function saveField (SimpleMap_MapFieldType $fieldType)
{
$owner = $fieldType->element;
Expand All @@ -47,8 +75,6 @@ public function saveField (SimpleMap_MapFieldType $fieldType)
$data['lat'] = (double)$data['lat'];
$data['lng'] = (double)$data['lng'];

SimpleMapPlugin::log(print_r(gettype($data['lat']), true));

$record = SimpleMap_MapRecord::model()->findByAttributes(array(
'ownerId' => $owner->id,
'fieldId' => $field->id,
Expand All @@ -67,15 +93,109 @@ public function saveField (SimpleMap_MapFieldType $fieldType)
$save = $record->save();

if (!$save) {
SimpleMapPlugin::log(print_r($record->getErrors(), true));
SimpleMapPlugin::log(print_r($record->getErrors(), true), LogLevel::Error);
}

return $save;
}

/**
* Modify Query
*
* @param DbCommand $query
* @param array $params
*/
public function modifyQuery (DbCommand &$query, $params = array())
{
//
$query->join(SimpleMap_MapRecord::TABLE_NAME, 'elements.id=' . craft()->db->tablePrefix . SimpleMap_MapRecord::TABLE_NAME . '.ownerId');

if (array_key_exists('location', $params)) {
$this->_searchLocation($query, $params);
}
}


/// PRIVATE ///

/**
* Search for entries by location
*
* @param DbCommand $query
* @param array $params
*/
private function _searchLocation (DbCommand &$query, $params)
{
$location = $params['location'];
$radius = array_key_exists('radius', $params) ? $params['radius'] : 50;
$unit = array_key_exists('unit', $params) ? $params['unit'] : 'kilometers';

if (!is_numeric($radius)) $radius = (float)$radius;
if (!is_numeric($radius)) $radius = 50;

if (!in_array($unit, array('km', 'mi'))) $unit = 'km';

if (is_string($location)) $location = $this->_getLatLngFromAddress($location);
if (is_array($location)) {
if (!array_key_exists('lat', $location) || !array_key_exists('lng', $location))
$location = null;
} else return;

if ($location === null) return;

if ($unit === 'km') $earthRad = 6371;
else $earthRad = 3959;

$this->searchLatLng = $location;
$this->searchEarthRad = $earthRad;

$table = craft()->db->tablePrefix . SimpleMap_MapRecord::TABLE_NAME;

$haversine = "($earthRad * acos(cos(radians($location[lat])) * cos(radians($table.lat)) * cos(radians($table.lng) - radians($location[lng])) + sin(radians($location[lat])) * sin(radians($table.lat))))";

$query
->addSelect($haversine . ' AS distance')
->having('distance <= ' . $radius);
}

/**
* Find lat/lng from string address
*
* @param $address
* @return null|array
*
* TODO: Cache results?
*/
private function _getLatLngFromAddress ($address)
{
if (!$this->settings['serverApiKey']) return null;

$url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' . rawurlencode($address)
. '&key=' . $this->settings['serverApiKey'];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$resp = json_decode(curl_exec($ch), true);

if (array_key_exists('error_message', $resp) && $resp['error_message'])
SimpleMapPlugin::log($resp['error_message'], LogLevel::Error);

if (empty($resp['results'])) return null;

return $resp['results'][0]['geometry']['location'];
}

private function _calculateDistance (SimpleMap_MapModel $model)
{
if (!$this->searchLatLng || !$this->searchEarthRad) return null;

$lt1 = $this->searchLatLng['lat'];
$ln1 = $this->searchLatLng['lng'];

$lt2 = $model->lat;
$ln2 = $model->lng;

return ($this->searchEarthRad * acos(cos(deg2rad($lt1)) * cos(deg2rad($lt2)) * cos(deg2rad($ln2) - deg2rad($ln1)) + sin(deg2rad($lt1)) * sin(deg2rad($lt2))));
}

}
2 changes: 1 addition & 1 deletion templates/plugin-settings.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{{ forms.textField({
label: "Google API Server Key"|t,
instructions: '<em>Optional.</em> Used for searching and sorting by textual address / location. If left blank, only searching and sorting by Lat/Lng will be available. <a href="https://developers.google.com/places/web-service/get-api-key" target="_blank">Get an API key.</a>',
instructions: '<em>Optional.</em> Used for searching and sorting by textual address / location. If left blank, only searching and sorting by Lat/Lng will be available. <a href="https://console.developers.google.com/apis/api/geocoding_backend/overview" target="_blank">Get an API key.</a>',
id: 'serverApiKey',
name: 'serverApiKey',
value: settings.serverApiKey,
Expand Down
15 changes: 15 additions & 0 deletions variables/SimpleMapVariable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Craft;

class SimpleMapVariable {

public function latLng ($lat, $lng)
{
$lat = (float)$lat;
$lng = (float)$lng;

return compact('lat', 'lng');
}

}

0 comments on commit b2aa642

Please sign in to comment.