├── .gitignore ├── CHANGELOG.md ├── CoordinatesPicker.php ├── CoordinatesPickerAsset.php ├── LocationPickerAsset.php ├── LocationPickerWidget.php ├── README.md ├── assets └── coordinates-picker.css ├── composer.json └── doc ├── MYSQL-SPATIAL-CONVERSION.md └── TWO-FIELDS-CONVERSION.md /.gitignore: -------------------------------------------------------------------------------- 1 | /nbproject 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | phpdevserver Change Log 2 | ======================== 3 | 4 | 0.2.5 2018-03-31 5 | - Fixed bug : location option doesn't work in coordinate picker (issue #17) 6 | 7 | 0.2.4 2018-02-24 8 | - CoordinatesPicker fix for virtual attributes , thanks @deathburger 9 | 10 | 0.2.3 2018-01-20 11 | ---------------- 12 | - Fixed bug : Issue #13 , LocationPicker value lost on update 13 | 14 | 0.2.2 2016-12-03 15 | ---------------- 16 | - Fixed bug : CoordinatesPicker attribute value lost 17 | - remove version 0.2.1 18 | - remove version 0.0.1~0.1.4 19 | 20 | 0.2.1 2016-12-02 21 | --------------- 22 | - Fixed bug : CoordinatesPicker can not set id 23 | 24 | 0.2.0 2015-12-28 25 | ---------------- 26 | - CoordinatesPicker change 27 | - 'enableMapTypeControl' is deprecated , please use 'mapOptions' 28 | - if use 'enableMapTypeControl' , browser develop console will display warning message 29 | - 'mapOptions' can set all gmap's control options 30 | - add 'searchBoxPosition' 31 | 32 | 0.1.5 2015-12-21 33 | ----------------- 34 | - Fixed bug : CoordinatesPicker can not use 'this' object in "onchanged" and "oninitialized" event 35 | 36 | 37 | 0.1.4 38 | ----------------- 39 | - I don't know why has this version .... 40 | 41 | 42 | 0.1.3 2015-12-01 43 | ------------------ 44 | - Fixed bug: CoordinatesPicker Undefined offset: 0 when coordinates is empty string 45 | 46 | 47 | 0.1.2 2015-11-17 48 | ------------------ 49 | - Fixed bug : if never moved picker on CoordinatesPicker , the ActiveField will lost value when submit 50 | - Change searchbox default hidden , when map rendered then display 51 | 52 | 0.1.1 2015-11-14 53 | ------------------ 54 | 55 | - Fixed #1 : "defined variable" can not use in Class property less than PHP 5.6 56 | 57 | 0.1.0 2015-11-12 58 | ------------------ 59 | - Add CoordinatesPicker widget 60 | 61 | 62 | 0.0.2 2015-11-11 63 | ------------------ 64 | - Fix bug : LocationPickerWidget must assign google map api key 65 | 66 | 0.0.1 2015-11-11 67 | ------------------ 68 | 69 | - First Test version 70 | 71 | -------------------------------------------------------------------------------- /CoordinatesPicker.php: -------------------------------------------------------------------------------- 1 | 40 | * [ 41 | * 'mapOptions' => [ 42 | * 'mapTypeControl' => true, 43 | * 'mapTypeControlOptions' => [ 44 | * 'style' => new JsExpression('google.maps.MapTypeControlStyle.HORIZONTAL_BAR'), 45 | * 'position' => new JsExpression('google.maps.ControlPosition.TOP_CENTER'), 46 | * ] 47 | * ] 48 | * ] 49 | * 50 | * 51 | * @var boolean 52 | * @deprecated since 0.2.0 53 | * @see https://developers.google.com/maps/documentation/javascript/controls 54 | */ 55 | public $enableMapTypeControl = true; 56 | 57 | /** 58 | * Google Map Options 59 | * @var array 60 | * @since 0.2.0 61 | */ 62 | public $mapOptions = []; 63 | 64 | 65 | /** @var map canvas html attribute */ 66 | public $options = []; 67 | /** @var jquery-locationpicker js options */ 68 | public $clientOptions = []; 69 | /** @var jquery-locationpicker js events */ 70 | public $clientEvents = []; 71 | 72 | public function init() { 73 | parent::init(); 74 | CoordinatesPickerAsset::register($this->view); 75 | } 76 | 77 | public function run() 78 | { 79 | if($this->model === null) { 80 | $inputId = $this->getId(); 81 | } else { 82 | if($this->getId(false) === null) { 83 | $inputId = Html::getInputId($this->model, $this->attribute); 84 | $this->setId($inputId); 85 | } else { 86 | $inputId = $this->getId(); 87 | } 88 | 89 | } 90 | $widgetId = $inputId . '-map'; 91 | 92 | 93 | if($this->name === null) { 94 | $inputName = $this->model===null ? null: Html::getInputName($this->model, $this->attribute); 95 | } else { 96 | $inputName = $this->name; 97 | } 98 | 99 | if($this->enableSearchBox === true) { 100 | $this->_renderSearchBox(); 101 | } 102 | 103 | // render attribute as hidden input 104 | if($this->model === null) { 105 | echo Html::hiddenInput($inputName, $this->value , ['id'=> $inputId , 'name' => $inputName]); 106 | } else { 107 | echo Html::activeHiddenInput( 108 | $this->model, 109 | $this->attribute, 110 | ['id'=> $inputId , 'name' => $inputName] 111 | ); 112 | $this->value = $this->model->{$this->attribute}; 113 | } 114 | 115 | 116 | 117 | $this->_registerOnChangedEvent($this->id); 118 | $this->_registerOnInitializedEvent(); 119 | 120 | $this->_setClientLocation(); 121 | 122 | 123 | $widgetOptions = $this->options; 124 | unset($widgetOptions['id']); 125 | echo LocationPickerWidget::widget([ 126 | 'id' => $widgetId, 127 | 'key' => $this->key , 128 | 'options' => $widgetOptions, 129 | 'clientOptions' => $this->clientOptions, 130 | 'clientEvents' => $this->clientEvents, 131 | ]); 132 | 133 | } 134 | 135 | private function _setClientLocation() { 136 | 137 | $coordinates = null; 138 | if($this->model) { 139 | $coordinates = Html::getAttributeValue($this->model, $this->attribute); 140 | } 141 | 142 | // $coordinates = $this->model->attributes[$this->attribute]; 143 | if($coordinates === null || empty($coordinates)) { 144 | return; 145 | } 146 | 147 | $latitudeIndex = strpos($this->valueTemplate , '{latitude}'); 148 | $longitudeIndex = strpos($this->valueTemplate , '{longitude}'); 149 | 150 | if($latitudeIndex === false || $longitudeIndex === false) { 151 | throw new InvalidConfigException('Property "valueTemplate" is invalid.'); 152 | } 153 | 154 | $pattern = '/' . strtr($this->valueTemplate , [ 155 | '{latitude}' => '(?P.*)' , 156 | '{longitude}' => '(?P.*)' 157 | ]). '/'; 158 | 159 | 160 | preg_match_all($pattern, $coordinates, $matches , PREG_SET_ORDER); 161 | 162 | $this->clientOptions['location'] = [ 163 | 'latitude' => floatval($matches[0]['latitude']), 164 | 'longitude' => floatval($matches[0]['longitude']), 165 | ]; 166 | } 167 | 168 | 169 | /** 170 | * Generate searchbox javascript code 171 | */ 172 | private function _renderSearchBox() { 173 | if(!isset($this->searchBoxOptions['class'])) { 174 | $this->searchBoxOptions['class'] = 'coordinates-picker searchbox'; 175 | } 176 | 177 | if(!isset($this->searchBoxOptions['id'])) { 178 | $this->searchBoxOptions['id'] = $this->getId() . '-searchbox'; 179 | } 180 | 181 | // render SearchBox 182 | echo Html::tag('input' , '' , $this->searchBoxOptions); 183 | 184 | $this->clientOptions['enableAutocomplete'] = true; 185 | 186 | 187 | if(!isset($this->clientOptions['inputBinding'])) { 188 | $this->clientOptions['inputBinding'] = []; 189 | } 190 | 191 | if(!isset($this->clientOptions['inputBinding']['locationNameInput'])) { 192 | // binding search box 193 | $this->clientOptions['inputBinding']['locationNameInput'] = new JsExpression("jQuery('#" .$this->searchBoxOptions['id']. "')"); 194 | } 195 | } 196 | 197 | private function _registerOnChangedEvent($attributeId) { 198 | 199 | $onchangedDefaultFunction = null; 200 | if(isset($this->clientOptions['onchanged'])) { 201 | $onchangedDefaultFunction = $this->clientOptions['onchanged']; 202 | } 203 | 204 | // function(c,r,i) = function(currentLocation, radius, isMarkerDropped) 205 | $onChangedJS = "function(c,r,i) { (function() {\n" 206 | . "var _t='" .$this->valueTemplate. "';\n" 207 | . "jQuery('#" .$attributeId. "').val(_t.replace('{latitude}',c.latitude ).replace('{longitude}',c.longitude));\n" 208 | . "})();\n"; 209 | 210 | // call the default onchanged function 211 | if($onchangedDefaultFunction instanceof JsExpression) { 212 | $onChangedJS .= "var _fn = " .$onchangedDefaultFunction . "\n"; 213 | $onChangedJS .= "_fn.call(this,arguments);\n"; 214 | } 215 | $onChangedJS .= "}"; 216 | 217 | $this->clientOptions['onchanged'] = new JsExpression($onChangedJS); 218 | } 219 | 220 | private function _registerOnInitializedEvent() { 221 | 222 | if($this->enableSearchBox === false && $this->enableMapTypeControl === false) { 223 | return; 224 | } 225 | 226 | if(isset($this->searchBoxOptions['id'])) { 227 | $searchBoxId = $this->searchBoxOptions['id']; 228 | } 229 | 230 | $onInitializedDefaultFunction = null; 231 | if(isset($this->clientOptions['oninitialized'])) { 232 | $onInitializedDefaultFunction = $this->clientOptions['oninitialized']; 233 | } 234 | 235 | // function(c) = function(component) 236 | $onInitializedJS = "function(c) {(function(){\n" 237 | . "var _map = jQuery(c).locationpicker('map').map;\n"; 238 | 239 | 240 | 241 | if(empty($this->value) && !isset($this->clientOptions['location'])) { 242 | // set default hidden field value 243 | $id = $this->getId(); 244 | $onInitializedJS .= "var _t='" .$this->valueTemplate. "' , _l=$.fn.locationpicker.defaults.location;\n" 245 | . "jQuery('#" .$id. "').val(_t.replace('{latitude}',_l.latitude ).replace('{longitude}',_l.longitude));"; 246 | } 247 | if($this->enableSearchBox) { 248 | 249 | $position = new JsExpression('google.maps.ControlPosition.TOP_LEFT'); 250 | if($this->searchBoxPosition !== null) { 251 | $position = $this->searchBoxPosition; 252 | } 253 | $onInitializedJS .= "jQuery('#{$searchBoxId}').show();\n"; 254 | $onInitializedJS .= "_map.controls[{$position}].push(jQuery('#{$searchBoxId}').get(0));\n"; 255 | } 256 | 257 | if($this->enableMapTypeControl === true) { 258 | 259 | $onInitializedJS .= "console.warn('yii2-jquery-locationpicker : enableMapTypeControl is deprecated since 0.2.0 , we recommand use mapOptions to define google map options.')\n"; 260 | 261 | if(!isset($this->mapOptions['mapTypeControl'])) { 262 | $this->mapOptions['mapTypeControl'] = true; 263 | } 264 | } 265 | 266 | if(count($this->mapOptions)) { 267 | $onInitializedJS .= "_map.setOptions(" . Json::htmlEncode($this->mapOptions) . ");\n"; 268 | } 269 | 270 | $onInitializedJS .= "})();\n"; 271 | 272 | // call the default oninitialized function 273 | if($onInitializedDefaultFunction instanceof JsExpression) { 274 | $onInitializedJS .= "var _fn = " .$onInitializedDefaultFunction . "\n"; 275 | $onInitializedJS .= "_fn.call(this,arguments);\n"; 276 | } 277 | $onInitializedJS .= "}"; 278 | 279 | $this->clientOptions['oninitialized'] = new JsExpression($onInitializedJS); 280 | } 281 | 282 | } 283 | -------------------------------------------------------------------------------- /CoordinatesPickerAsset.php: -------------------------------------------------------------------------------- 1 | View::POS_END, 20 | ]; 21 | 22 | public $depends = [ 23 | 'yii\web\JqueryAsset', 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /LocationPickerWidget.php: -------------------------------------------------------------------------------- 1 | options['id'])) { 26 | $this->options['id'] = $this->getId(); 27 | } 28 | 29 | $url = "//maps.googleapis.com/maps/api/js?" .http_build_query([ 30 | 'key' => $this->key , 31 | 'libraries' => 'places' 32 | ]); 33 | $this->view->registerJsFile($url, [ 34 | 'position' => View::POS_END 35 | ]); 36 | LocationPickerAsset::register($this->view); 37 | } 38 | 39 | /** 40 | * Copy from jui widget 41 | * @param string $name 42 | * @param string $id 43 | */ 44 | protected function registerClientOptions($name, $id) 45 | { 46 | if ($this->clientOptions !== false) { 47 | $options = empty($this->clientOptions) ? '' : Json::htmlEncode($this->clientOptions); 48 | $js = "jQuery('#$id').$name($options);"; 49 | $this->getView()->registerJs($js); 50 | } 51 | } 52 | 53 | /** 54 | * Copy from jui widget 55 | * @param string $name 56 | * @param string $id 57 | */ 58 | protected function registerClientEvents($name, $id) 59 | { 60 | if (!empty($this->clientEvents)) { 61 | $js = []; 62 | foreach ($this->clientEvents as $event => $handler) { 63 | if (isset($this->clientEventMap[$event])) { 64 | $eventName = $this->clientEventMap[$event]; 65 | } else { 66 | $eventName = strtolower($name . $event); 67 | } 68 | $js[] = "jQuery('#$id').on('$eventName', $handler);"; 69 | } 70 | $this->getView()->registerJs(implode("\n", $js)); 71 | } 72 | } 73 | public function run() 74 | { 75 | echo Html::tag('div','',$this->options); 76 | $this->registerClientOptions('locationpicker', $this->getId()); 77 | $this->registerClientEvents('locationpicker', $this->getId()); 78 | 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jquery location picker widget for yii2 2 | ====================================== 3 | 4 | The widget implement [jquery-locationpicker-plugin 5 | ](https://github.com/Logicify/jquery-locationpicker-plugin) 6 | 7 | Installation 8 | ------------ 9 | 10 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 11 | 12 | Either run 13 | 14 | ~~~ 15 | php composer.phar require pigochu/yii2-jquery-locationpicker ">=0.2.0" 16 | ~~~ 17 | 18 | or add 19 | 20 | ~~~ 21 | "pigochu/yii2-jquery-locationpicker": ">=0.2.0" 22 | ~~~ 23 | 24 | to the require section of your `composer.json` file. 25 | 26 | 27 | Basic Usage for Test 28 | -------------------- 29 | 30 | ~~~php 31 | 32 | ~~~ 33 | 34 | Binding UI with the widget 35 | -------------------------- 36 | 37 | This sample is transformed via [http://logicify.github.io/jquery-locationpicker-plugin/#usage](http://logicify.github.io/jquery-locationpicker-plugin/#usage) 38 | 39 | ~~~php 40 | 43 | 44 | Location: 45 |
46 | Radius: 47 |
48 | Lat.: 49 |
50 | Long.: 51 |
52 | 53 | 54 | 'abcabcabcabc ...', // require , Put your google map api key 57 | 'options' => [ 58 | 'style' => 'width: 100%; height: 400px', // map canvas width and height 59 | ] , 60 | 'clientOptions' => [ 61 | 'location' => [ 62 | 'latitude' => 46.15242437752303 , 63 | 'longitude' => 2.7470703125, 64 | ], 65 | 'radius' => 300, 66 | 'addressFormat' => 'street_number', 67 | 'inputBinding' => [ 68 | 'latitudeInput' => new JsExpression("$('#us2-lat')"), 69 | 'longitudeInput' => new JsExpression("$('#us2-lon')"), 70 | 'radiusInput' => new JsExpression("$('#us2-radius')"), 71 | 'locationNameInput' => new JsExpression("$('#us2-address')") 72 | ] 73 | ] 74 | ]); 75 | ?> 76 | 77 | ~~~ 78 | 79 | CoordinatesPicker 80 | ----------------- 81 | 82 | CoordinatesPicker let you get coordinates in ActiveForm , In addition I implemented some features not in original jquery-locationpicker-plugin : 83 | 84 | - enable/disable search box , search box will overlay on map 85 | - enable/disable all googlemap's control 86 | 87 | 88 | ![](https://i.imgur.com/SyNOXXL.png) 89 | 90 | 91 | Example : 92 | 93 | ~~~php 94 | field($model, 'coordinates')->widget('\pigolab\locationpicker\CoordinatesPicker' , [ 96 | 'key' => 'abcabcabc...' , // require , Put your google map api key 97 | 'valueTemplate' => '{latitude},{longitude}' , // Optional , this is default result format 98 | 'options' => [ 99 | 'style' => 'width: 100%; height: 400px', // map canvas width and height 100 | ] , 101 | 'enableSearchBox' => true , // Optional , default is true 102 | 'searchBoxOptions' => [ // searchBox html attributes 103 | 'style' => 'width: 300px;', // Optional , default width and height defined in css coordinates-picker.css 104 | ], 105 | 'searchBoxPosition' => new JsExpression('google.maps.ControlPosition.TOP_LEFT'), // optional , default is TOP_LEFT 106 | 'mapOptions' => [ 107 | // google map options 108 | // visit https://developers.google.com/maps/documentation/javascript/controls for other options 109 | 'mapTypeControl' => true, // Enable Map Type Control 110 | 'mapTypeControlOptions' => [ 111 | 'style' => new JsExpression('google.maps.MapTypeControlStyle.HORIZONTAL_BAR'), 112 | 'position' => new JsExpression('google.maps.ControlPosition.TOP_LEFT'), 113 | ], 114 | 'streetViewControl' => true, // Enable Street View Control 115 | ], 116 | 'clientOptions' => [ 117 | // jquery-location-picker options 118 | 'radius' => 300, 119 | 'addressFormat' => 'street_number', 120 | ] 121 | ]); 122 | ?> 123 | ~~~ 124 | 125 | Get coordinates : 126 | 127 | Default valueTemplate is '{latitude},{longtitude} , So we will get resulit like : '25.023308046766083,121.46041916878664' 128 | 129 | We can convert it via explode() : 130 | 131 | ~~~php 132 | coordinates); 134 | ?> 135 | ~~~ 136 | 137 | Deprecated options : enableMapTypeControl 138 | ----------------------------------------- 139 | 140 | Since version 0.2.0 , don't use 'enableMapTypeControl' , I added 'mapOptions' for set googlemap options. 141 | You can enable/disable all controlls or set control's style , position now. 142 | 143 | Example : enable rotateControl , streetViewControl , mapTypeControl and set style/position 144 | 145 | ~~~php 146 | field($model, 'coordinates')->widget('\pigolab\locationpicker\CoordinatesPicker' , [ 148 | 149 | 'clientOptions' => [ 'zoom' => 20 ], // rotateControl will display when zoom is 20 150 | // .... other options ... 151 | 'mapOptions' => [ 152 | // set google map optinos 153 | 'rotateControl' => true, 154 | 'scaleControl' => false, 155 | 'streetViewControl' => true, 156 | 'mapTypeId' => new JsExpression('google.maps.MapTypeId.SATELLITE'), 157 | 'heading'=> 90, 158 | 'tilt' => 45 , 159 | 160 | 'mapTypeControl' => true, 161 | 'mapTypeControlOptions' => [ 162 | 'style' => new JsExpression('google.maps.MapTypeControlStyle.HORIZONTAL_BAR'), 163 | 'position' => new JsExpression('google.maps.ControlPosition.TOP_CENTER'), 164 | ] 165 | ] 166 | ]); 167 | ?> 168 | ~~~ 169 | 170 | Please visit GoogleMaps Full Control document : 171 | https://developers.google.com/maps/documentation/javascript/controls 172 | 173 | 174 | 175 | Other DocumentS 176 | --------------- 177 | - [CoordinatesPicker with two fields Model](doc/TWO-FIELDS-CONVERSION.md) 178 | - [How to use PHP trait do simple conversion MySQL Spatial Type between ActiveRecord](doc/MYSQL-SPATIAL-CONVERSION.md) 179 | -------------------------------------------------------------------------------- /assets/coordinates-picker.css: -------------------------------------------------------------------------------- 1 | .coordinates-picker.searchbox { 2 | width: 300px; 3 | height: 32px; 4 | margin: 10px; 5 | background-color: #fff; 6 | font-family: Roboto; 7 | font-size: 15px; 8 | font-weight: 300; 9 | padding: 0 11px 0 13px; 10 | text-overflow: ellipsis; 11 | border: 1px solid transparent; 12 | border-radius: 2px; 13 | box-sizing: border-box; 14 | -moz-box-sizing: border-box; 15 | outline: none; 16 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); 17 | display: none; 18 | } 19 | 20 | .coordinates-picker.searchbox:focus { 21 | border-color: #4d90fe; 22 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pigochu/yii2-jquery-locationpicker", 3 | "description": "jquery location picker widget for yii2", 4 | "type": "yii2-extension", 5 | "keywords": ["yii2","extension","locationpicker"], 6 | "homepage": "https://github.com/pigochu/yii2-jquery-locationpicker", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Pigo Chu", 11 | "email": "pigochu@gmail.com" 12 | } 13 | ], 14 | "require": { 15 | "bower-asset/jquery-locationpicker-plugin" : ">=0.1.15" 16 | }, 17 | "autoload": { 18 | "psr-4": { 19 | "pigolab\\locationpicker\\": "" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /doc/MYSQL-SPATIAL-CONVERSION.md: -------------------------------------------------------------------------------- 1 | How to use PHP trait do simple conversion MySQL Spatial Type between ActiveRecord 2 | ================================================================================= 3 | 4 | If you are using MySQL Spatial Data Type like "Point" to save the coordinates , but YII2 ActiveRecord doesn't support MySQL Spatial Data , you can use my simple code to conversion easily. 5 | 6 | Suppose you have a ActiveRecord class named "Foo" 7 | 8 | ~~~php 9 | class Foo extends ActiveRecord { 10 | // your code ............. 11 | } 12 | ~~~ 13 | 14 | And Foo has a field named "coordinates" , In mysql real table also has a coordinates column and type is Point. 15 | 16 | 17 | ### 1. create CoordinatesTrait 18 | ~~~php 19 | _strCoordinates = $this->coordinates; 41 | list($latitude , $longitude) = explode(',' , $this->coordinates); 42 | $this->coordinates = new Expression("point({$latitude},{$longitude})"); 43 | return true; 44 | } else { 45 | return false; 46 | } 47 | } 48 | 49 | public function afterSave ($insert, $changedAttributes) { 50 | parent::afterSave($insert, $changedAttributes); 51 | $this->coordinates = $this->_strCoordinates; 52 | list($latitude , $longitude) = explode(',' , $this->coordinates); 53 | $this->latitude = $latitude; 54 | $this->longitude = $longitude; 55 | } 56 | 57 | public function afterFind() { 58 | parent::afterFind(); 59 | $this->coordinates = implode(',' , [$this->latitude , $this->longitude]); 60 | } 61 | 62 | } 63 | ~~~ 64 | ### 2. create CoordinatesQueryTrait 65 | 66 | ~~~php 67 | addSelect(new Expression("ST_X([[{$fieldName}]]) as latitude")); 79 | $this->addSelect(new Expression("ST_Y([[{$fieldName}]]) as longitude")); 80 | return $this; 81 | } 82 | } 83 | ~~~ 84 | 85 | ### 3. add CoordinatesRecordTrait to your Foo class 86 | 87 | ~~~php 88 | class Foo extends ActiveRecord { 89 | use CoordinatesRecordTrait; 90 | // your code ............. 91 | } 92 | ~~~ 93 | 94 | ### 4. if you have a FooQuery (ActiveQuery) class , add CoordinatesQueryTrait to FooQuery 95 | 96 | ~~~php 97 | class Foo extends ActiveQuery { 98 | use CoordinatesQueryTrait; 99 | // your code ............. 100 | } 101 | ~~~ 102 | 103 | Thats all, CoordinatesRecordTrait and CoordinatesQueryTrait can be reuse 104 | 105 | When you find records via Foo::find() , you can get latitude and longitude easily. 106 | 107 | ~~~php 108 | where("id=:id" , ['id'=>$id])->one(); 112 | var_dump($model1->coordinates); 113 | // you will get mysql BLOB string , but how to display it ?? 114 | 115 | // when use latlong() 116 | $model2 = Foo::find()->latlong('coordinates')->where("id=:id" , ['id'=>$id])->one(); 117 | var_dump($model2->coordinates); 118 | // you will get result like "25.040369020430944,121.5122790711639" 119 | 120 | // you can also get latitude and longitude directly 121 | var_dump($model2->latitude); 122 | var_dump($model2->longitude); 123 | 124 | // save coordinates easily,too 125 | $model2->coordinates = "26.040369020430944,120.5122790711639"; 126 | $model2->save(); 127 | // You do not need to do any conversion 128 | ~~~ 129 | 130 | -------------------------------------------------------------------------------- /doc/TWO-FIELDS-CONVERSION.md: -------------------------------------------------------------------------------- 1 | CoordinatesPicker with two fields Model 2 | ======================================= 3 | 4 | If your ActiveRecord Model has latitude and longitude and want to let ActiveField auto binding , you can create a temp Model to do this : 5 | 6 | TempMode.php 7 | ~~~php 8 | 9 | 10 | 'coordinates', 25 | ]; 26 | } 27 | ?> 28 | ~~~ 29 | 30 | 31 | 32 | In your controller and view , you need do something 33 | 34 | - create TempModel as $model2 then pass to view 35 | - create hidden fields for latitude and longitude in view. 36 | - define clientOptions['inputBinding'] of CoordinatesPicker. 37 | 38 | ## Controller's code ## 39 | 40 | ~~~php 41 | public function actionXXX($yourId) { 42 | $model = YourOriginalModel::findOne($yourId); 43 | $model2 = new TempModel(); 44 | $model2->coordinates = $model->latitude . "," . $model->longitude; 45 | return $this->render('XXX' , [ 46 | 'model' => $model , 47 | 'model2' => $model2, 48 | ]); 49 | } 50 | 51 | ~~~ 52 | 53 | ## View's code: ## 54 | 55 | ~~~php 56 | field($model, 'latitude')->hiddenInput()->label(false); 59 | echo $form->field($model, 'longitude')->hiddenInput()->label(false); 60 | // $model2 is TempModel 61 | echo $form->field($model2, 'coordinates')->widget('\pigolab\locationpicker\CoordinatesPicker' , [ 62 | // ... your other setting 63 | 'clientOptions' => [ 64 | 'radius' => 300, 65 | 'inputBinding' => [ 66 | 'latitudeInput' => new JsExpression("$('#" .Html::getInputId($model, "latitude"). "')"), 67 | 'longitudeInput' => new JsExpression("$('#" .Html::getInputId($model, "longitude"). "')"), 68 | ] 69 | ] 70 | ])->label('coordinates'); 71 | ~~~ 72 | --------------------------------------------------------------------------------