diff --git a/CHANGELOG.md b/CHANGELOG.md index 27fb235..a4f7147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.4.1 - 2019-03-20 +### Fixed +- Fixed an issue where the map field class broke after upgrading. + ## 3.4.0 - 2019-03-20 > {warning} This is a major update, we strongly recommend taking a database backup before updating! diff --git a/composer.json b/composer.json index 77d6a88..589f212 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "ether/simplemap", "description": "A beautifully simple Map field type for Craft CMS 3", - "version": "3.4.0", + "version": "3.4.1", "type": "craft-plugin", "license": "MIT", "minimum-stability": "dev", diff --git a/src/SimpleMap.php b/src/SimpleMap.php index 53a016f..590bd0a 100644 --- a/src/SimpleMap.php +++ b/src/SimpleMap.php @@ -14,7 +14,7 @@ use craft\web\twig\variables\CraftVariable; use ether\simplemap\enums\GeoService; use ether\simplemap\enums\MapTiles; -use ether\simplemap\fields\Map as MapField; +use ether\simplemap\fields\MapField as MapField; use ether\simplemap\integrations\craftql\GetCraftQLSchema; use ether\simplemap\models\Settings; use ether\simplemap\services\MapService; diff --git a/src/fields/Map.php b/src/fields/Map.php index 96dbb5d..584fbfe 100644 --- a/src/fields/Map.php +++ b/src/fields/Map.php @@ -1,6 +1,6 @@ -90, - 'max' => 90, - ]; - - $rules[] = [ - ['lng'], - 'double', - 'min' => -180, - 'max' => 180, - ]; - - return $rules; - } - - /** - * @param MapElement|null $value - * @param ElementInterface|Element|null $element - * - * @return MapElement - */ - public function normalizeValue ($value, ElementInterface $element = null) - { - if (is_array($value) && !empty($value[0])) - $value = $value[0]; - - if ($value instanceof MapElement) - return $value; - - if ($value instanceof ElementQueryInterface) - return $value->one(); - - if (is_string($value)) - $value = Json::decodeIfJson($value); - - $map = null; - - if ($element && $element->id) - { - /** @var MapElement $map */ - $map = MapElement::find() - ->fieldId($this->id) - ->siteId($element->siteId) - ->ownerId($element->id) - ->one(); - - if ($map && $value) - { - $map->lat = $value['lat']; - $map->lng = $value['lng']; - $map->zoom = $value['zoom']; - $map->address = $value['address']; - $map->parts = $value['parts']; - } - } - - if ($map === null) - { - if (is_array($value)) - $map = new MapElement($value); - else - $map = new MapElement([ - 'lat' => $this->lat, - 'lng' => $this->lng, - 'zoom' => $this->zoom, - ]); - } - - $handle = $this->handle; - $element->$handle = $map; - - return $map; - } - - /** - * @return string|\Twig_Markup|null - * @throws \Twig_Error_Loader - * @throws \yii\base\Exception - * @throws \yii\base\InvalidConfigException - */ - public function getSettingsHtml () - { - $value = new MapElement(); - - $value->lat = $this->lat; - $value->lng = $this->lng; - $value->zoom = $this->zoom; - - $originalHandle = $this->handle; - $originalCountry = $this->country; - $originalHideSearch = $this->hideSearch; - $originalHideMap = $this->hideMap; - $originalHideAddress = $this->hideAddress; - - $this->handle = '__settings__'; - $this->country = null; - $this->hideSearch = false; - $this->hideMap = false; - $this->hideAddress = true; - - $mapField = new \Twig_Markup( - $this->_renderMap($value, true), - 'utf-8' - ); - - $this->handle = $originalHandle; - $this->country = $originalCountry; - $this->hideSearch = $originalHideSearch; - $this->hideMap = $originalHideMap; - $this->hideAddress = $originalHideAddress; - - $view = \Craft::$app->getView(); - - $countries = array_merge([ - '*' => SimpleMap::t('All Countries'), - ], GeoService::$countries); - - /** @noinspection PhpComposerExtensionStubsInspection */ - return $view->renderTemplate('simplemap/field-settings', [ - 'map' => $mapField, - 'field' => $this, - 'countries' => $countries, - ]); - } - - /** - * @param MapElement $value - * @param ElementInterface|Element|null $element - * - * @return string - * @throws \yii\base\InvalidConfigException - */ - public function getInputHtml ($value, ElementInterface $element = null): string - { - if ($element !== null && $element->hasEagerLoadedElements($this->handle)) - $value = $element->getEagerLoadedElements($this->handle); - - /** @noinspection PhpComposerExtensionStubsInspection */ - return new \Twig_Markup( - $this->_renderMap($value), - 'utf-8' - ); - } - - /** - * @inheritdoc - * - * @param mixed $value - * @param ElementInterface $element - * - * @return string - */ - public function getTableAttributeHtml ($value, ElementInterface $element): string - { - return $this->normalizeValue($value, $element)->address; - } - - /** - * @inheritdoc - * - * @param array $sourceElements - * - * @return array - */ - public function getEagerLoadingMap (array $sourceElements) - { - $sourceElementIds = []; - - foreach ($sourceElements as $sourceElement) - $sourceElementIds[] = $sourceElement->id; - - $map = (new Query()) - ->select(['ownerId as source', 'id as target']) - ->from([MapRecord::TableName]) - ->where([ - 'fieldId' => $this->id, - 'ownerId' => $sourceElementIds, - ]) - ->all(); - - return [ - 'elementType' => MapElement::class, - 'map' => $map, - 'criteria' => ['fieldId' => $this->id], - ]; - } - - /** - * @param ElementQueryInterface $query - * @param $value - * - * @return bool|false|null - * @throws \yii\db\Exception - */ - public function modifyElementsQuery (ElementQueryInterface $query, $value) - { - SimpleMap::getInstance()->map->modifyElementsQuery($query, $value); - - return null; - } - - /** - * @inheritdoc - */ - public function isValueEmpty ($value, ElementInterface $element): bool - { - return empty($value->lat) && empty($value->lng); - } - - // Methods: Events - // ------------------------------------------------------------------------- - - /** - * @inheritdoc - */ - public function beforeSave (bool $isNew): bool - { - $this->lat = (float) $this->lat; - $this->lng = (float) $this->lng; - $this->zoom = (int) $this->zoom; - - if ($this->country === '*') - $this->country = null; - - return parent::beforeSave($isNew); - } - - /** - * @param ElementInterface $element - * @param bool $isNew - * - * @throws \Throwable - * @throws \yii\db\Exception - */ - public function afterElementSave (ElementInterface $element, bool $isNew) - { - SimpleMap::getInstance()->map->saveField($this, $element); - parent::afterElementSave($element, $isNew); - } - - // Helpers - // ========================================================================= - - /** - * Renders the map input - * - * @param $value - * @param bool $isSettings - * - * @return string - * @throws \yii\base\InvalidConfigException - */ - private function _renderMap ($value, $isSettings = false) - { - $view = \Craft::$app->getView(); - - $containerId = $this->id . '-container'; - $vueContainerId = $view->namespaceInputId($containerId); - $view->registerJsFile('https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CIntersectionObserver%2CIntersectionObserverEntry'); - $view->registerAssetBundle(MapAsset::class); - $view->registerJs('new Vue({ el: \'#' . $vueContainerId . '\' });'); - $view->registerTranslations('simplemap', [ - 'Search for a location', - 'Name / Number', - 'Street Address', - 'Town / City', - 'Postcode', - 'County', - 'State', - 'Country', - ]); - - /** @var Settings $settings */ - $settings = SimpleMap::getInstance()->getSettings(); - - $country = $this->country; - // Convert ISO2 to ISO3 for Here autocomplete - if ($country && $settings->geoService === GeoEnum::Here) - $country = GeoService::$countriesIso3[$country]; - - $opts = [ - 'config' => [ - 'isSettings' => $isSettings, - - 'name' => $view->namespaceInputName($this->handle), - 'country' => $country, - 'hideSearch' => $this->hideSearch, - 'hideMap' => $this->hideMap, - 'hideAddress' => $this->hideAddress, - - 'mapTiles' => $settings->mapTiles, - 'mapToken' => GeoService::getToken( - $settings->mapToken, - $settings->mapTiles - ), - - 'geoService' => $settings->geoService, - 'geoToken' => GeoService::getToken( - $settings->geoToken, - $settings->geoService - ), - - 'locale' => \Craft::$app->locale->getLanguageID(), - ], - - 'value' => [ - 'address' => $value->address, - 'lat' => $value->lat, - 'lng' => $value->lng, - 'zoom' => $value->zoom, - 'parts' => $value->parts, - ], - ]; - - // Map Services - // --------------------------------------------------------------------- - - if (strpos($settings->mapTiles, 'google') !== false) - { - $view->registerJsFile( - 'https://maps.googleapis.com/maps/api/js?libraries=places&key=' . - $settings->mapToken - ); - } - elseif (strpos($settings->mapTiles, 'mapkit') !== false) - { - $view->registerJsFile( - 'https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js' - ); - } - - // Geo Services - // --------------------------------------------------------------------- - - if ($settings->geoService === GeoEnum::GoogleMaps) - { - $view->registerJsFile( - 'https://maps.googleapis.com/maps/api/js?libraries=places&key=' . - $settings->geoToken - ); - } - elseif ($settings->geoService === GeoEnum::AppleMapKit) - { - $view->registerJsFile( - 'https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js' - ); - } - - $options = preg_replace( - '/\'/', - ''', - json_encode($opts) - ); - - return '
'; - } - -} \ No newline at end of file +class Map extends MapField +{} \ No newline at end of file diff --git a/src/fields/MapField.php b/src/fields/MapField.php new file mode 100644 index 0000000..cf07634 --- /dev/null +++ b/src/fields/MapField.php @@ -0,0 +1,472 @@ + -90, + 'max' => 90, + ]; + + $rules[] = [ + ['lng'], + 'double', + 'min' => -180, + 'max' => 180, + ]; + + return $rules; + } + + /** + * @param MapElement|null $value + * @param ElementInterface|Element|null $element + * + * @return MapElement + */ + public function normalizeValue ($value, ElementInterface $element = null) + { + if (is_array($value) && !empty($value[0])) + $value = $value[0]; + + if ($value instanceof MapElement) + return $value; + + if ($value instanceof ElementQueryInterface) + return $value->one(); + + if (is_string($value)) + $value = Json::decodeIfJson($value); + + $map = null; + + if ($element && $element->id) + { + /** @var MapElement $map */ + $map = MapElement::find() + ->fieldId($this->id) + ->siteId($element->siteId) + ->ownerId($element->id) + ->one(); + + if ($map && $value) + { + $map->lat = $value['lat']; + $map->lng = $value['lng']; + $map->zoom = $value['zoom']; + $map->address = $value['address']; + $map->parts = $value['parts']; + } + } + + if ($map === null) + { + if (is_array($value)) + $map = new MapElement($value); + else + $map = new MapElement([ + 'lat' => $this->lat, + 'lng' => $this->lng, + 'zoom' => $this->zoom, + ]); + } + + $handle = $this->handle; + $element->$handle = $map; + + return $map; + } + + /** + * @return string|\Twig_Markup|null + * @throws \Twig_Error_Loader + * @throws \yii\base\Exception + * @throws \yii\base\InvalidConfigException + */ + public function getSettingsHtml () + { + $value = new MapElement(); + + $value->lat = $this->lat; + $value->lng = $this->lng; + $value->zoom = $this->zoom; + + $originalHandle = $this->handle; + $originalCountry = $this->country; + $originalHideSearch = $this->hideSearch; + $originalHideMap = $this->hideMap; + $originalHideAddress = $this->hideAddress; + + $this->handle = '__settings__'; + $this->country = null; + $this->hideSearch = false; + $this->hideMap = false; + $this->hideAddress = true; + + $mapField = new \Twig_Markup( + $this->_renderMap($value, true), + 'utf-8' + ); + + $this->handle = $originalHandle; + $this->country = $originalCountry; + $this->hideSearch = $originalHideSearch; + $this->hideMap = $originalHideMap; + $this->hideAddress = $originalHideAddress; + + $view = \Craft::$app->getView(); + + $countries = array_merge([ + '*' => SimpleMap::t('All Countries'), + ], GeoService::$countries); + + /** @noinspection PhpComposerExtensionStubsInspection */ + return $view->renderTemplate('simplemap/field-settings', [ + 'map' => $mapField, + 'field' => $this, + 'countries' => $countries, + ]); + } + + /** + * @param MapElement $value + * @param ElementInterface|Element|null $element + * + * @return string + * @throws \yii\base\InvalidConfigException + */ + public function getInputHtml ($value, ElementInterface $element = null): string + { + if ($element !== null && $element->hasEagerLoadedElements($this->handle)) + $value = $element->getEagerLoadedElements($this->handle); + + /** @noinspection PhpComposerExtensionStubsInspection */ + return new \Twig_Markup( + $this->_renderMap($value), + 'utf-8' + ); + } + + /** + * @inheritdoc + * + * @param mixed $value + * @param ElementInterface $element + * + * @return string + */ + public function getTableAttributeHtml ($value, ElementInterface $element): string + { + return $this->normalizeValue($value, $element)->address; + } + + /** + * @inheritdoc + * + * @param array $sourceElements + * + * @return array + */ + public function getEagerLoadingMap (array $sourceElements) + { + $sourceElementIds = []; + + foreach ($sourceElements as $sourceElement) + $sourceElementIds[] = $sourceElement->id; + + $map = (new Query()) + ->select(['ownerId as source', 'id as target']) + ->from([MapRecord::TableName]) + ->where([ + 'fieldId' => $this->id, + 'ownerId' => $sourceElementIds, + ]) + ->all(); + + return [ + 'elementType' => MapElement::class, + 'map' => $map, + 'criteria' => ['fieldId' => $this->id], + ]; + } + + /** + * @param ElementQueryInterface $query + * @param $value + * + * @return bool|false|null + * @throws \yii\db\Exception + */ + public function modifyElementsQuery (ElementQueryInterface $query, $value) + { + SimpleMap::getInstance()->map->modifyElementsQuery($query, $value); + + return null; + } + + /** + * @inheritdoc + */ + public function isValueEmpty ($value, ElementInterface $element): bool + { + return empty($value->lat) && empty($value->lng); + } + + // Methods: Events + // ------------------------------------------------------------------------- + + /** + * @inheritdoc + */ + public function beforeSave (bool $isNew): bool + { + $this->lat = (float) $this->lat; + $this->lng = (float) $this->lng; + $this->zoom = (int) $this->zoom; + + if ($this->country === '*') + $this->country = null; + + return parent::beforeSave($isNew); + } + + /** + * @param ElementInterface $element + * @param bool $isNew + * + * @throws \Throwable + * @throws \yii\db\Exception + */ + public function afterElementSave (ElementInterface $element, bool $isNew) + { + SimpleMap::getInstance()->map->saveField($this, $element); + parent::afterElementSave($element, $isNew); + } + + // Helpers + // ========================================================================= + + /** + * Renders the map input + * + * @param $value + * @param bool $isSettings + * + * @return string + * @throws \yii\base\InvalidConfigException + */ + private function _renderMap ($value, $isSettings = false) + { + $view = \Craft::$app->getView(); + + $containerId = $this->id . '-container'; + $vueContainerId = $view->namespaceInputId($containerId); + $view->registerJsFile('https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CIntersectionObserver%2CIntersectionObserverEntry'); + $view->registerAssetBundle(MapAsset::class); + $view->registerJs('new Vue({ el: \'#' . $vueContainerId . '\' });'); + $view->registerTranslations('simplemap', [ + 'Search for a location', + 'Name / Number', + 'Street Address', + 'Town / City', + 'Postcode', + 'County', + 'State', + 'Country', + ]); + + /** @var Settings $settings */ + $settings = SimpleMap::getInstance()->getSettings(); + + $country = $this->country; + // Convert ISO2 to ISO3 for Here autocomplete + if ($country && $settings->geoService === GeoEnum::Here) + $country = GeoService::$countriesIso3[$country]; + + $opts = [ + 'config' => [ + 'isSettings' => $isSettings, + + 'name' => $view->namespaceInputName($this->handle), + 'country' => $country, + 'hideSearch' => $this->hideSearch, + 'hideMap' => $this->hideMap, + 'hideAddress' => $this->hideAddress, + + 'mapTiles' => $settings->mapTiles, + 'mapToken' => GeoService::getToken( + $settings->mapToken, + $settings->mapTiles + ), + + 'geoService' => $settings->geoService, + 'geoToken' => GeoService::getToken( + $settings->geoToken, + $settings->geoService + ), + + 'locale' => \Craft::$app->locale->getLanguageID(), + ], + + 'value' => [ + 'address' => $value->address, + 'lat' => $value->lat, + 'lng' => $value->lng, + 'zoom' => $value->zoom, + 'parts' => $value->parts, + ], + ]; + + // Map Services + // --------------------------------------------------------------------- + + if (strpos($settings->mapTiles, 'google') !== false) + { + $view->registerJsFile( + 'https://maps.googleapis.com/maps/api/js?libraries=places&key=' . + $settings->mapToken + ); + } + elseif (strpos($settings->mapTiles, 'mapkit') !== false) + { + $view->registerJsFile( + 'https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js' + ); + } + + // Geo Services + // --------------------------------------------------------------------- + + if ($settings->geoService === GeoEnum::GoogleMaps) + { + $view->registerJsFile( + 'https://maps.googleapis.com/maps/api/js?libraries=places&key=' . + $settings->geoToken + ); + } + elseif ($settings->geoService === GeoEnum::AppleMapKit) + { + $view->registerJsFile( + 'https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js' + ); + } + + $options = preg_replace( + '/\'/', + ''', + json_encode($opts) + ); + + return '
'; + } + +} \ No newline at end of file diff --git a/src/migrations/m190226_143809_craft3_upgrade.php b/src/migrations/m190226_143809_craft3_upgrade.php index 52f6000..e52fb10 100644 --- a/src/migrations/m190226_143809_craft3_upgrade.php +++ b/src/migrations/m190226_143809_craft3_upgrade.php @@ -13,7 +13,7 @@ use ether\simplemap\models\Settings; use ether\simplemap\records\Map; use ether\simplemap\elements\Map as MapElement; -use ether\simplemap\fields\Map as MapField; +use ether\simplemap\fields\MapField as MapField; use ether\simplemap\SimpleMap; /** diff --git a/src/services/MapService.php b/src/services/MapService.php index b61dc40..cfe8e79 100644 --- a/src/services/MapService.php +++ b/src/services/MapService.php @@ -13,7 +13,7 @@ use craft\base\ElementInterface; use craft\elements\db\ElementQuery; use craft\elements\db\ElementQueryInterface; -use ether\simplemap\fields\Map; +use ether\simplemap\fields\MapField; use ether\simplemap\elements\Map as MapElement; use ether\simplemap\records\Map as MapRecord; @@ -36,13 +36,13 @@ class MapService extends Component // ========================================================================= /** - * @param Map $field + * @param MapField $field * @param ElementInterface|Element $element * * @throws \Throwable * @throws \yii\db\Exception */ - public function saveField (Map $field, ElementInterface $element) + public function saveField (MapField $field, ElementInterface $element) { if ($element instanceof MapElement) return;