diff options
Diffstat (limited to 'app/Module/OpenStreetMapModule.php')
| -rw-r--r-- | app/Module/OpenStreetMapModule.php | 2911 |
1 files changed, 1539 insertions, 1372 deletions
diff --git a/app/Module/OpenStreetMapModule.php b/app/Module/OpenStreetMapModule.php index 13b2479eb1..f37bf5a62a 100644 --- a/app/Module/OpenStreetMapModule.php +++ b/app/Module/OpenStreetMapModule.php @@ -39,1193 +39,1346 @@ use Symfony\Component\HttpFoundation\Request; /** * Class OpenStreetMapModule */ -class OpenStreetMapModule extends AbstractModule implements ModuleConfigInterface, ModuleTabInterface, ModuleChartInterface { +class OpenStreetMapModule extends AbstractModule implements ModuleConfigInterface, ModuleTabInterface, ModuleChartInterface +{ - const OSM_MIN_ZOOM = 2; - const LINE_COLORS = [ - '#FF0000', // Red - '#00FF00', // Green - '#0000FF', // Blue - '#FFB300', // Gold - '#00FFFF', // Cyan - '#FF00FF', // Purple - '#7777FF', // Light blue - '#80FF80' // Light green - ]; + const OSM_MIN_ZOOM = 2; + const LINE_COLORS = [ + '#FF0000', + // Red + '#00FF00', + // Green + '#0000FF', + // Blue + '#FFB300', + // Gold + '#00FFFF', + // Cyan + '#FF00FF', + // Purple + '#7777FF', + // Light blue + '#80FF80' + // Light green + ]; - private static $map_providers = null; - private static $map_selections = null; + private static $map_providers = null; + private static $map_selections = null; - /** {@inheritdoc} */ - public function getTitle() { - return /* I18N: Name of a module */ - I18N::translate('Event Map'); - } + /** {@inheritdoc} */ + public function getTitle() + { + return /* I18N: Name of a module */ + I18N::translate('Event Map'); + } - /** {@inheritdoc} */ - public function getDescription() { - return /* I18N: Description of the “OSM” module */ - I18N::translate('Show the location of events on a map using Open Street Maps'); - } + /** {@inheritdoc} */ + public function getDescription() + { + return /* I18N: Description of the “OSM” module */ + I18N::translate('Show the location of events on a map using Open Street Maps'); + } - /** {@inheritdoc} */ - public function defaultAccessLevel() { - # Auth::PRIV_PRIVATE actually means public. - # Auth::PRIV_NONE - no acces to anybody. - return Auth::PRIV_PRIVATE; - } + /** {@inheritdoc} */ + public function defaultAccessLevel() + { + # Auth::PRIV_PRIVATE actually means public. + # Auth::PRIV_NONE - no acces to anybody. + return Auth::PRIV_PRIVATE; + } - /** {@inheritdoc} */ - public function defaultTabOrder() { - return 4; - } + /** {@inheritdoc} */ + public function defaultTabOrder() + { + return 4; + } - /** {@inheritdoc} */ - public function hasTabContent(Individual $individual) { - return true; - } + /** {@inheritdoc} */ + public function hasTabContent(Individual $individual) + { + return true; + } - /** {@inheritdoc} */ - public function isGrayedOut(Individual $individual) { - return false; - } + /** {@inheritdoc} */ + public function isGrayedOut(Individual $individual) + { + return false; + } - /** {@inheritdoc} */ - public function canLoadAjax() { - return true; - } + /** {@inheritdoc} */ + public function canLoadAjax() + { + return true; + } - /** {@inheritdoc} */ - public function modAction($mod_action) { - } + /** {@inheritdoc} */ + public function modAction($mod_action) + { + } - /** {@inheritdoc} */ - public function getConfigLink() { - return route('admin-module', ['module' => $this->getName(), 'action' => 'AdminConfig']); - } + /** {@inheritdoc} */ + public function getConfigLink() + { + return route('admin-module', [ + 'module' => $this->getName(), + 'action' => 'AdminConfig', + ]); + } - /** - * Return a menu item for this chart. - * - * @param Individual $individual - * @return Menu - */ - public function getChartMenu(Individual $individual) { - return new Menu( - I18N::translate('Pedigree map'), - route('module', ['module' => $this->getName(), 'action' => 'PedigreeMap', 'xref' => $individual->getXref()]), - 'menu-chart-pedigreemap', - ['rel' => 'nofollow'] - ); - } + /** + * Return a menu item for this chart. + * + * @param Individual $individual + * + * @return Menu + */ + public function getChartMenu(Individual $individual) + { + return new Menu( + I18N::translate('Pedigree map'), + route('module', [ + 'module' => $this->getName(), + 'action' => 'PedigreeMap', + 'xref' => $individual->getXref(), + ]), + 'menu-chart-pedigreemap', + ['rel' => 'nofollow'] + ); + } - /** - * Return a menu item for this chart - for use in individual boxes. - * - * @param Individual $individual - * - * @return Menu - */ - public function getBoxChartMenu(Individual $individual) { - return $this->getChartMenu($individual); - } + /** + * Return a menu item for this chart - for use in individual boxes. + * + * @param Individual $individual + * + * @return Menu + */ + public function getBoxChartMenu(Individual $individual) + { + return $this->getChartMenu($individual); + } - /** - * @param string $type - * @return array - */ - public function assets($type = 'user') { - $dir = WT_MODULES_DIR . $this->getName(); - if ($type === 'admin') { - return [ - 'css' => [ - $dir . '/assets/css/osm-module.css', - ], - 'js' => [ - $dir . '/assets/js/osm-admin.js', - ], - ]; - } else { - return [ - 'css' => [ - $dir . '/assets/css/osm-module.css', - ], - 'js' => [ - $dir . '/assets/js/osm-module.js', - ], - ]; - } - } + /** + * @param string $type + * + * @return array + */ + public function assets($type = 'user') + { + $dir = WT_MODULES_DIR . $this->getName(); + if ($type === 'admin') { + return [ + 'css' => [ + $dir . '/assets/css/osm-module.css', + ], + 'js' => [ + $dir . '/assets/js/osm-admin.js', + ], + ]; + } else { + return [ + 'css' => [ + $dir . '/assets/css/osm-module.css', + ], + 'js' => [ + $dir . '/assets/js/osm-module.js', + ], + ]; + } + } - /** {@inheritdoc} */ - public function getTabContent(Individual $individual) { + /** {@inheritdoc} */ + public function getTabContent(Individual $individual) + { - return view( - 'modules/openstreetmap/map', - [ - 'assets' => $this->assets(), - 'module' => $this->getName(), - 'ref' => $individual->getXref(), - 'type' => 'individual', - ] - ); - } + return view( + 'modules/openstreetmap/map', + [ + 'assets' => $this->assets(), + 'module' => $this->getName(), + 'ref' => $individual->getXref(), + 'type' => 'individual', + ] + ); + } - /** - * @param Request $request - * @return JsonResponse - */ - public function getBaseDataAction(Request $request): JsonResponse { - $provider = $this->getMapProviderData($request); - $style = $provider['selectedStyleName'] = '' ? '' : '.' . $provider['selectedStyleName']; + /** + * @param Request $request + * + * @return JsonResponse + */ + public function getBaseDataAction(Request $request): JsonResponse + { + $provider = $this->getMapProviderData($request); + $style = $provider['selectedStyleName'] = '' ? '' : '.' . $provider['selectedStyleName']; - switch ($provider['selectedProvIndex']) { - case 'mapbox': - $providerOptions = [ - 'id' => $this->getPreference('mapbox_id'), - 'accessToken' => $this->getPreference('mapbox_token'), - ]; - break; - case 'here': - $providerOptions = [ - 'app_id' => $this->getPreference('here_appid'), - 'app_code' => $this->getPreference('here_appcode'), - ]; - break; - default: - $providerOptions = []; - }; + switch ($provider['selectedProvIndex']) { + case 'mapbox': + $providerOptions = [ + 'id' => $this->getPreference('mapbox_id'), + 'accessToken' => $this->getPreference('mapbox_token'), + ]; + break; + case 'here': + $providerOptions = [ + 'app_id' => $this->getPreference('here_appid'), + 'app_code' => $this->getPreference('here_appcode'), + ]; + break; + default: + $providerOptions = []; + }; - $options = [ - 'minZoom' => self::OSM_MIN_ZOOM, - 'providerName' => $provider['selectedProvName'] . $style, - 'providerOptions' => $providerOptions, - 'animate' => $this->getPreference('map_animate', 0), - 'I18N' => [ - 'zoomInTitle' => I18N::translate('Zoom in'), - 'zoomOutTitle' => I18N::translate('Zoom out'), - 'reset' => I18N::translate('Reset to initial map state'), - 'noData' => I18N::translate('No mappable items'), - 'error' => I18N::translate('An unknown error occurred'), - ], - ]; + $options = [ + 'minZoom' => self::OSM_MIN_ZOOM, + 'providerName' => $provider['selectedProvName'] . $style, + 'providerOptions' => $providerOptions, + 'animate' => $this->getPreference('map_animate', 0), + 'I18N' => [ + 'zoomInTitle' => I18N::translate('Zoom in'), + 'zoomOutTitle' => I18N::translate('Zoom out'), + 'reset' => I18N::translate('Reset to initial map state'), + 'noData' => I18N::translate('No mappable items'), + 'error' => I18N::translate('An unknown error occurred'), + ], + ]; - return new JsonResponse($options); - } + return new JsonResponse($options); + } - /** - * @param Request $request - * @return JsonResponse - * @throws \Exception - */ - public function getMapDataAction(Request $request): JsonResponse { - switch ($request->get('type')) { - case 'placelist': - $response = $this->placelistGetMapData($request); - break; - default: - $response = $this->getMapData($request); - } + /** + * @param Request $request + * + * @return JsonResponse + * @throws \Exception + */ + public function getMapDataAction(Request $request): JsonResponse + { + switch ($request->get('type')) { + case 'placelist': + $response = $this->placelistGetMapData($request); + break; + default: + $response = $this->getMapData($request); + } - return $response; - } + return $response; + } - /** - * @param Request $request - * @return JsonResponse - * @throws \Exception - */ - private function getMapData(Request $request): JsonResponse { - $mapType = $request->get('type'); - $xref = $request->get('reference'); - $tree = $request->attributes->get('tree'); - $indi = Individual::getInstance($xref, $tree); - $color_count = count(self::LINE_COLORS); + /** + * @param Request $request + * + * @return JsonResponse + * @throws \Exception + */ + private function getMapData(Request $request): JsonResponse + { + $mapType = $request->get('type'); + $xref = $request->get('reference'); + $tree = $request->attributes->get('tree'); + $indi = Individual::getInstance($xref, $tree); + $color_count = count(self::LINE_COLORS); - switch ($mapType) { - case 'pedigree': - $facts = $this->getPedigreeMapFacts($request); - break; - default: - $facts = $this->getPersonalFacts($request); - } + switch ($mapType) { + case 'pedigree': + $facts = $this->getPedigreeMapFacts($request); + break; + default: + $facts = $this->getPersonalFacts($request); + } - $geojson = ['type' => 'FeatureCollection', 'features' => []]; - if (empty($facts)) { - $code = 204; - } else { - $code = 200; - foreach ($facts as $id => $fact) { - $event = new FactLocation($fact, $indi); - $icon = $event->getIconDetails(); - if ($event->knownLatLon()) { - $polyline = null; - if ($mapType === 'pedigree') { - $color = self::LINE_COLORS[log($id, 2) % $color_count]; - $icon['color'] = $color; //make icon color the same as the line - $sosa_points[$id] = $event->getLatLonJSArray(); - $sosa_parent = (int)floor($id / 2); - if (array_key_exists($sosa_parent, $sosa_points)) { - // Would like to use a GeometryCollection to hold LineStrings - // rather than generate polylines but the MarkerCluster library - // doesn't seem to like them - $polyline = [ - 'points' => [ - $sosa_points[$sosa_parent], - $event->getLatLonJSArray(), - ], - 'options' => [ - 'color' => $color, - ], - ]; - } - } - $geojson['features'][] = [ - 'type' => 'Feature', - 'id' => $id, - 'valid' => true, - 'geometry' => [ - 'type' => 'Point', - 'coordinates' => $event->getGeoJsonCoords(), - ], - 'properties' => [ - 'polyline' => $polyline, - 'icon' => $icon, - 'tooltip' => $event->toolTip(), - 'summary' => view( - 'modules/openstreetmap/event-sidebar', - $event->shortSummary($mapType, $id) - ), - 'zoom' => (int)$event->getZoom(), - ], - ]; - } - } - } + $geojson = [ + 'type' => 'FeatureCollection', + 'features' => [], + ]; + if (empty($facts)) { + $code = 204; + } else { + $code = 200; + foreach ($facts as $id => $fact) { + $event = new FactLocation($fact, $indi); + $icon = $event->getIconDetails(); + if ($event->knownLatLon()) { + $polyline = null; + if ($mapType === 'pedigree') { + $color = self::LINE_COLORS[log($id, 2) % $color_count]; + $icon['color'] = $color; //make icon color the same as the line + $sosa_points[$id] = $event->getLatLonJSArray(); + $sosa_parent = (int)floor($id / 2); + if (array_key_exists($sosa_parent, $sosa_points)) { + // Would like to use a GeometryCollection to hold LineStrings + // rather than generate polylines but the MarkerCluster library + // doesn't seem to like them + $polyline = [ + 'points' => [ + $sosa_points[$sosa_parent], + $event->getLatLonJSArray(), + ], + 'options' => [ + 'color' => $color, + ], + ]; + } + } + $geojson['features'][] = [ + 'type' => 'Feature', + 'id' => $id, + 'valid' => true, + 'geometry' => [ + 'type' => 'Point', + 'coordinates' => $event->getGeoJsonCoords(), + ], + 'properties' => [ + 'polyline' => $polyline, + 'icon' => $icon, + 'tooltip' => $event->toolTip(), + 'summary' => view( + 'modules/openstreetmap/event-sidebar', + $event->shortSummary($mapType, $id) + ), + 'zoom' => (int)$event->getZoom(), + ], + ]; + } + } + } - return new JsonResponse($geojson, $code); - } + return new JsonResponse($geojson, $code); + } - /** - * @param Request $request - * @return JsonResponse - * @throws \Exception - */ - private function placelistGetMapData(Request $request): JsonResponse { - $reference = $request->get('reference'); - $tree = $request->attributes->get('tree'); - $placeObj = new Place($reference, $tree); - $places = $placeObj->getChildPlaces(); - $features = []; - $flag_path = WT_MODULES_DIR . $this->getName() . '/'; - $stats = new Stats($tree); - $showlink = true; + /** + * @param Request $request + * + * @return JsonResponse + * @throws \Exception + */ + private function placelistGetMapData(Request $request): JsonResponse + { + $reference = $request->get('reference'); + $tree = $request->attributes->get('tree'); + $placeObj = new Place($reference, $tree); + $places = $placeObj->getChildPlaces(); + $features = []; + $flag_path = WT_MODULES_DIR . $this->getName() . '/'; + $stats = new Stats($tree); + $showlink = true; - if (empty($places)) { - $places[] = $placeObj; - $showlink = false; - } + if (empty($places)) { + $places[] = $placeObj; + $showlink = false; + } - foreach ($places as $id => $place) { - $location = new Location($place->getGedcomName()); + foreach ($places as $id => $place) { + $location = new Location($place->getGedcomName()); - //Stats - $placeStats = []; - foreach (['INDI', 'FAM'] as $type) { - $tmp = $stats->statsPlaces($type, false, $place->getPlaceId()); - $placeStats[$type] = empty($tmp) ? 0 : $tmp[0]['tot']; - } + //Stats + $placeStats = []; + foreach ([ + 'INDI', + 'FAM', + ] as $type) { + $tmp = $stats->statsPlaces($type, false, $place->getPlaceId()); + $placeStats[$type] = empty($tmp) ? 0 : $tmp[0]['tot']; + } - //Flag - if ($location->getIcon() !== null && is_file($flag_path . $location->getIcon())) { - $flag = $flag_path . $location->getIcon(); - } else { - $flag = ''; - } + //Flag + if ($location->getIcon() !== null && is_file($flag_path . $location->getIcon())) { + $flag = $flag_path . $location->getIcon(); + } else { + $flag = ''; + } - $features[] = [ - 'type' => 'Feature', - 'id' => $id, - 'valid' => $location->isValid() && $location->knownLatLon(), - 'geometry' => [ - 'type' => 'Point', - 'coordinates' => $location->getGeoJsonCoords(), - ], - 'properties' => [ - 'icon' => [ - 'name' => 'globe', - 'color' => '#1e90ff', - ], - 'tooltip' => strip_tags($place->getFullName()), - 'summary' => view( - 'modules/openstreetmap/place-sidebar', - [ - 'showlink' => $showlink, - 'flag' => $flag, - 'place' => $place, - 'stats' => $placeStats, - ] - ), - 'zoom' => (int)($location->getZoom() ?? 2), - ], - ]; - } + $features[] = [ + 'type' => 'Feature', + 'id' => $id, + 'valid' => $location->isValid() && $location->knownLatLon(), + 'geometry' => [ + 'type' => 'Point', + 'coordinates' => $location->getGeoJsonCoords(), + ], + 'properties' => [ + 'icon' => [ + 'name' => 'globe', + 'color' => '#1e90ff', + ], + 'tooltip' => strip_tags($place->getFullName()), + 'summary' => view( + 'modules/openstreetmap/place-sidebar', + [ + 'showlink' => $showlink, + 'flag' => $flag, + 'place' => $place, + 'stats' => $placeStats, + ] + ), + 'zoom' => (int)($location->getZoom() ?? 2), + ], + ]; + } - $code = empty($features) ? 204 : 200; + $code = empty($features) ? 204 : 200; - return new JsonResponse(['type' => 'FeatureCollection', 'features' => $features], $code); - } + return new JsonResponse([ + 'type' => 'FeatureCollection', + 'features' => $features, + ], $code); + } - /** - * @param Request $request - * @return array - * @throws \Exception - */ - private function getPersonalFacts(Request $request) { - $xref = $request->get('reference'); - $tree = $request->attributes->get('tree'); - $individual = Individual::getInstance($xref, $tree); - $facts = $individual->getFacts(); - foreach ($individual->getSpouseFamilies() as $family) { - $facts = array_merge($facts, $family->getFacts()); - // Add birth of children from this family to the facts array - foreach ($family->getChildren() as $child) { - $childsBirth = $child->getFirstFact('BIRT'); - if ($childsBirth && !$childsBirth->getPlace()->isEmpty()) { - $facts[] = $childsBirth; - } - } - } + /** + * @param Request $request + * + * @return array + * @throws \Exception + */ + private function getPersonalFacts(Request $request) + { + $xref = $request->get('reference'); + $tree = $request->attributes->get('tree'); + $individual = Individual::getInstance($xref, $tree); + $facts = $individual->getFacts(); + foreach ($individual->getSpouseFamilies() as $family) { + $facts = array_merge($facts, $family->getFacts()); + // Add birth of children from this family to the facts array + foreach ($family->getChildren() as $child) { + $childsBirth = $child->getFirstFact('BIRT'); + if ($childsBirth && !$childsBirth->getPlace()->isEmpty()) { + $facts[] = $childsBirth; + } + } + } - Functions::sortFacts($facts); + Functions::sortFacts($facts); - $useable_facts = array_filter( - $facts, - function (Fact $item) { - return !$item->getPlace()->isEmpty(); - } - ); + $useable_facts = array_filter( + $facts, + function (Fact $item) { + return !$item->getPlace()->isEmpty(); + } + ); - return array_values($useable_facts); - } + return array_values($useable_facts); + } - /** - * @param Request $request - * @return array - * @throws \Exception - */ - private function getPedigreeMapFacts(Request $request) { - $xref = $request->get('reference'); - $tree = $request->attributes->get('tree'); - $individual = Individual::getInstance($xref, $tree); - $generations = (int)$request->get( - 'generations', - $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS') - ); - $ancestors = $this->sosaStradonitzAncestors($individual, $generations); - $facts = []; - foreach ($ancestors as $sosa => $person) { - if ($person !== null && $person->canShow()) { - /** @var Fact $birth */ - $birth = $person->getFirstFact('BIRT'); - if ($birth && !$birth->getPlace()->isEmpty()) { - $facts[$sosa] = $birth; - } - } - } + /** + * @param Request $request + * + * @return array + * @throws \Exception + */ + private function getPedigreeMapFacts(Request $request) + { + $xref = $request->get('reference'); + $tree = $request->attributes->get('tree'); + $individual = Individual::getInstance($xref, $tree); + $generations = (int)$request->get( + 'generations', + $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS') + ); + $ancestors = $this->sosaStradonitzAncestors($individual, $generations); + $facts = []; + foreach ($ancestors as $sosa => $person) { + if ($person !== null && $person->canShow()) { + /** @var Fact $birth */ + $birth = $person->getFirstFact('BIRT'); + if ($birth && !$birth->getPlace()->isEmpty()) { + $facts[$sosa] = $birth; + } + } + } - return $facts; - } + return $facts; + } - /** - * @param Request $request - * @return JsonResponse - */ - public function getProviderStylesAction(Request $request): JsonResponse { - $styles = $this->getMapProviderData($request); + /** + * @param Request $request + * + * @return JsonResponse + */ + public function getProviderStylesAction(Request $request): JsonResponse + { + $styles = $this->getMapProviderData($request); - return new JsonResponse($styles); - } + return new JsonResponse($styles); + } - /** - * @param Request $request - * @return array|null - */ - private function getMapProviderData(Request $request) { - if (self::$map_providers === null) { - $providersFile = WT_ROOT . WT_MODULES_DIR . $this->getName() . '/providers/providers.xml'; - self::$map_selections = [ - 'provider' => $this->getPreference('provider', 'openstreetmap'), - 'style' => $this->getPreference('provider_style', 'mapnik'), - ]; + /** + * @param Request $request + * + * @return array|null + */ + private function getMapProviderData(Request $request) + { + if (self::$map_providers === null) { + $providersFile = WT_ROOT . WT_MODULES_DIR . $this->getName() . '/providers/providers.xml'; + self::$map_selections = [ + 'provider' => $this->getPreference('provider', 'openstreetmap'), + 'style' => $this->getPreference('provider_style', 'mapnik'), + ]; - try { - $xml = simplexml_load_file($providersFile); - // need to convert xml structure into arrays & strings - foreach ($xml as $provider) { - $style_keys = array_map( - function ($item) { - return preg_replace('/[^a-z\d]/i', '', strtolower($item)); - }, - (array)$provider->styles - ); + try { + $xml = simplexml_load_file($providersFile); + // need to convert xml structure into arrays & strings + foreach ($xml as $provider) { + $style_keys = array_map( + function ($item) { + return preg_replace('/[^a-z\d]/i', '', strtolower($item)); + }, + (array)$provider->styles + ); - $key = preg_replace('/[^a-z\d]/i', '', strtolower((string)$provider->name)); + $key = preg_replace('/[^a-z\d]/i', '', strtolower((string)$provider->name)); - self::$map_providers[$key] = [ - 'name' => (string)$provider->name, - 'styles' => array_combine($style_keys, (array)$provider->styles), - ]; - } - } catch (\Exception $ex) { - // Default provider is OpenStreetMap - self::$map_selections = [ - 'provider' => 'openstreetmap', - 'style' => 'mapnik', - ]; - self::$map_providers = [ - 'openstreetmap' => [ - 'name' => 'OpenStreetMap', - 'styles' => ['mapnik' => 'Mapnik'], - ], - ]; - }; - } + self::$map_providers[$key] = [ + 'name' => (string)$provider->name, + 'styles' => array_combine($style_keys, (array)$provider->styles), + ]; + } + } catch (\Exception $ex) { + // Default provider is OpenStreetMap + self::$map_selections = [ + 'provider' => 'openstreetmap', + 'style' => 'mapnik', + ]; + self::$map_providers = [ + 'openstreetmap' => [ + 'name' => 'OpenStreetMap', + 'styles' => ['mapnik' => 'Mapnik'], + ], + ]; + }; + } - //Ugly!!! - switch ($request->get('action')) { - case 'BaseData': - $varName = (self::$map_selections['style'] === '') ? '' : self::$map_providers[self::$map_selections['provider']]['styles'][self::$map_selections['style']]; - $payload = ['selectedProvIndex' => self::$map_selections['provider'], - 'selectedProvName' => self::$map_providers[self::$map_selections['provider']]['name'], - 'selectedStyleName' => $varName, - ]; - break; - case 'ProviderStyles': - $provider = $request->get('provider', 'openstreetmap'); - $payload = self::$map_providers[$provider]['styles']; - break; - case 'AdminConfig': - $providers = []; - foreach (self::$map_providers as $key => $provider) { - $providers[$key] = $provider['name']; - } - $payload = ['providers' => $providers, - 'selectedProv' => self::$map_selections['provider'], - 'styles' => self::$map_providers[self::$map_selections['provider']]['styles'], - 'selectedStyle' => self::$map_selections['style'], - ]; - break; - default: - $payload = null; - } + //Ugly!!! + switch ($request->get('action')) { + case 'BaseData': + $varName = (self::$map_selections['style'] === '') ? '' : self::$map_providers[self::$map_selections['provider']]['styles'][self::$map_selections['style']]; + $payload = [ + 'selectedProvIndex' => self::$map_selections['provider'], + 'selectedProvName' => self::$map_providers[self::$map_selections['provider']]['name'], + 'selectedStyleName' => $varName, + ]; + break; + case 'ProviderStyles': + $provider = $request->get('provider', 'openstreetmap'); + $payload = self::$map_providers[$provider]['styles']; + break; + case 'AdminConfig': + $providers = []; + foreach (self::$map_providers as $key => $provider) { + $providers[$key] = $provider['name']; + } + $payload = [ + 'providers' => $providers, + 'selectedProv' => self::$map_selections['provider'], + 'styles' => self::$map_providers[self::$map_selections['provider']]['styles'], + 'selectedStyle' => self::$map_selections['style'], + ]; + break; + default: + $payload = null; + } - return $payload; - } + return $payload; + } - /** - * @param Request $request - * @return object - * @throws \Exception - */ - public function getPedigreeMapAction(Request $request) { - /** @var Tree $tree */ - $tree = $request->attributes->get('tree'); - $xref = $request->get('xref'); - $individual = Individual::getInstance($xref, $tree); - $maxgenerations = $tree->getPreference('MAX_PEDIGREE_GENERATIONS'); - $generations = $request->get('generations', $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS')); + /** + * @param Request $request + * + * @return object + * @throws \Exception + */ + public function getPedigreeMapAction(Request $request) + { + /** @var Tree $tree */ + $tree = $request->attributes->get('tree'); + $xref = $request->get('xref'); + $individual = Individual::getInstance($xref, $tree); + $maxgenerations = $tree->getPreference('MAX_PEDIGREE_GENERATIONS'); + $generations = $request->get('generations', $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS')); - return (object)[ - 'name' => 'modules/openstreetmap/pedigreemap', - 'data' => [ - 'assets' => $this->assets(), - 'module' => $this->getName(), - 'title' => /* I18N: %s is an individual’s name */ - I18N::translate('Pedigree map of %s', $individual->getFullName()), - 'tree' => $tree, - 'individual' => $individual, - 'generations' => $generations, - 'maxgenerations' => $maxgenerations, - 'map' => view( - 'modules/openstreetmap/map', - [ - 'assets' => $this->assets(), - 'module' => $this->getName(), - 'ref' => $individual->getXref(), - 'type' => 'pedigree', - 'generations' => $generations, - ] - ), - ], - ]; - } + return (object)[ + 'name' => 'modules/openstreetmap/pedigreemap', + 'data' => [ + 'assets' => $this->assets(), + 'module' => $this->getName(), + 'title' => /* I18N: %s is an individual’s name */ + I18N::translate('Pedigree map of %s', $individual->getFullName()), + 'tree' => $tree, + 'individual' => $individual, + 'generations' => $generations, + 'maxgenerations' => $maxgenerations, + 'map' => view( + 'modules/openstreetmap/map', + [ + 'assets' => $this->assets(), + 'module' => $this->getName(), + 'ref' => $individual->getXref(), + 'type' => 'pedigree', + 'generations' => $generations, + ] + ), + ], + ]; + } - /* - * Admin functions called via admin-module route - */ + /* + * Admin functions called via admin-module route + */ - /** - * @param Request $request - * @return JsonResponse - * @throws \Exception - */ - public function getAdminMapDataAction(Request $request): JsonResponse { - $id = $request->get('id', 0); - $row = Database::prepare("SELECT * FROM `##placelocation` WHERE pl_id = :id") - ->execute(['id' => $id]) - ->fetchOneRow(); + /** + * @param Request $request + * + * @return JsonResponse + * @throws \Exception + */ + public function getAdminMapDataAction(Request $request): JsonResponse + { + $id = $request->get('id', 0); + $row = Database::prepare("SELECT * FROM `##placelocation` WHERE pl_id = :id") + ->execute(['id' => $id]) + ->fetchOneRow(); - if (empty($row)) { - $json = [ - 'zoom' => self::OSM_MIN_ZOOM, - 'coordinates' => [0, 0], - ]; - } else { - $json = [ - 'zoom' => $row->pl_zoom ? $row->pl_zoom : self::OSM_MIN_ZOOM, - 'coordinates' => [ - $row->pl_lati ? strtr($row->pl_lati, ['N' => '', 'S' => '-', ',' => '.']) : 0, - $row->pl_long ? strtr($row->pl_long, ['E' => '', 'W' => '-', ',' => '.']) : 0, - ], - ]; - } + if (empty($row)) { + $json = [ + 'zoom' => self::OSM_MIN_ZOOM, + 'coordinates' => [ + 0, + 0, + ], + ]; + } else { + $json = [ + 'zoom' => $row->pl_zoom ? $row->pl_zoom : self::OSM_MIN_ZOOM, + 'coordinates' => [ + $row->pl_lati ? strtr($row->pl_lati, [ + 'N' => '', + 'S' => '-', + ',' => '.', + ]) : 0, + $row->pl_long ? strtr($row->pl_long, [ + 'E' => '', + 'W' => '-', + ',' => '.', + ]) : 0, + ], + ]; + } - return new JsonResponse($json); - } + return new JsonResponse($json); + } - /** - * @param Request $request - * @return object - */ - public function getAdminConfigAction(Request $request) { - return (object)[ - 'name' => 'modules/openstreetmap/admin-config', - 'data' => [ - 'title' => I18N::translate('Open Street Maps (Configuration)'), - 'module' => $this->getName(), - 'provider' => $this->getMapProviderData($request), - 'mapboxId' => $this->getPreference('mapbox_id'), - 'mapboxToken' => $this->getPreference('mapbox_token'), - 'here_Appid' => $this->getPreference('here_appid'), - 'here_Appcode' => $this->getPreference('here_appcode'), - 'hierarchy' => $this->getPreference('place_hierarchy', '0'), - 'animate' => $this->getPreference('map_animate', '0'), - ], - ]; - } + /** + * @param Request $request + * + * @return object + */ + public function getAdminConfigAction(Request $request) + { + return (object)[ + 'name' => 'modules/openstreetmap/admin-config', + 'data' => [ + 'title' => I18N::translate('Open Street Maps (Configuration)'), + 'module' => $this->getName(), + 'provider' => $this->getMapProviderData($request), + 'mapboxId' => $this->getPreference('mapbox_id'), + 'mapboxToken' => $this->getPreference('mapbox_token'), + 'here_Appid' => $this->getPreference('here_appid'), + 'here_Appcode' => $this->getPreference('here_appcode'), + 'hierarchy' => $this->getPreference('place_hierarchy', '0'), + 'animate' => $this->getPreference('map_animate', '0'), + ], + ]; + } - /** - * @param Request $request - * @return RedirectResponse - */ - public function postAdminUpdateConfigAction(Request $request): RedirectResponse { - $this->setPreference('mapbox_id', $request->get('mapbox_id', '')); - $this->setPreference('mapbox_token', $request->get('mapbox_token', '')); - $this->setPreference('here_appid', $request->get('here_appid', '')); - $this->setPreference('here_appcode', $request->get('here_appcode', '')); - $this->setPreference('provider', $request->get('provider')); - $this->setPreference('provider_style', $request->get('provider_style', '')); - $this->setPreference('place_hierarchy', $request->get('place_hierarchy')); - $this->setPreference('map_animate', $request->get('map_animate')); + /** + * @param Request $request + * + * @return RedirectResponse + */ + public function postAdminUpdateConfigAction(Request $request): RedirectResponse + { + $this->setPreference('mapbox_id', $request->get('mapbox_id', '')); + $this->setPreference('mapbox_token', $request->get('mapbox_token', '')); + $this->setPreference('here_appid', $request->get('here_appid', '')); + $this->setPreference('here_appcode', $request->get('here_appcode', '')); + $this->setPreference('provider', $request->get('provider')); + $this->setPreference('provider_style', $request->get('provider_style', '')); + $this->setPreference('place_hierarchy', $request->get('place_hierarchy')); + $this->setPreference('map_animate', $request->get('map_animate')); - FlashMessages::addMessage( - I18N::translate( - 'The preferences for the module “%s” have been updated.', - $this->getTitle() - ), - 'success' - ); + FlashMessages::addMessage( + I18N::translate( + 'The preferences for the module “%s” have been updated.', + $this->getTitle() + ), + 'success' + ); - return new RedirectResponse(route('admin-module', ['module' => $this->getName(), 'action' => 'AdminConfig'])); - } + return new RedirectResponse(route('admin-module', [ + 'module' => $this->getName(), + 'action' => 'AdminConfig', + ])); + } - /** - * @param Request $request - * @return object - * @throws \Exception - */ - public function postAdminPlacesAction(Request $request) { - return $this->getAdminPlacesAction($request); - } + /** + * @param Request $request + * + * @return object + * @throws \Exception + */ + public function postAdminPlacesAction(Request $request) + { + return $this->getAdminPlacesAction($request); + } - /** - * @param Request $request - * @return object - * @throws \Exception - */ - public function getAdminPlacesAction(Request $request) { - $parent_id = (int)$request->get('parent_id', 0); - $inactive = (bool)$request->get('inactive'); - $hierarchy = $this->gethierarchy($parent_id); - $title = I18N::translate('Open Street Maps (Geographic data)'); - $breadcrumbs = [ - route('admin-control-panel') => I18N::translate('Control panel'), - route('admin-modules') => I18N::translate('Module administration'), - route( - 'admin-module', - ['module' => $this->getName(), 'action' => 'AdminPlaces', 'inactive' => $inactive] - ) => $title, - ]; + /** + * @param Request $request + * + * @return object + * @throws \Exception + */ + public function getAdminPlacesAction(Request $request) + { + $parent_id = (int)$request->get('parent_id', 0); + $inactive = (bool)$request->get('inactive'); + $hierarchy = $this->gethierarchy($parent_id); + $title = I18N::translate('Open Street Maps (Geographic data)'); + $breadcrumbs = [ + route('admin-control-panel') => I18N::translate('Control panel'), + route('admin-modules') => I18N::translate('Module administration'), + route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'inactive' => $inactive, + ] + ) => $title, + ]; - foreach ($hierarchy as $row) { - $breadcrumbs[route( - 'admin-module', - ['module' => $this->getName(), - 'action' => 'AdminPlaces', - 'parent_id' => $row->pl_id, - 'inactive' => $inactive] - )] = $row->pl_place; - } - $breadcrumbs[] = array_pop($breadcrumbs); + foreach ($hierarchy as $row) { + $breadcrumbs[route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'parent_id' => $row->pl_id, + 'inactive' => $inactive, + ] + )] = $row->pl_place; + } + $breadcrumbs[] = array_pop($breadcrumbs); - return (object)[ - 'name' => 'modules/openstreetmap/admin-places', - 'data' => [ - 'title' => $title, - 'breadcrumbs' => $breadcrumbs, - 'inactive' => $inactive, - 'parent_id' => $parent_id, - 'placelist' => $this->getPlaceListLocation($parent_id, $inactive), - 'module' => $this->getName(), - ], - ]; - } + return (object)[ + 'name' => 'modules/openstreetmap/admin-places', + 'data' => [ + 'title' => $title, + 'breadcrumbs' => $breadcrumbs, + 'inactive' => $inactive, + 'parent_id' => $parent_id, + 'placelist' => $this->getPlaceListLocation($parent_id, $inactive), + 'module' => $this->getName(), + ], + ]; + } - /** - * Create or edit a geographic place. - * - * @param Request $request - * @return object - * @throws \Exception - */ - public function getAdminPlaceEditAction(Request $request) { - $parent_id = (int)$request->get('parent_id', 0); - $place_id = (int)$request->get('place_id'); - $inactive = (int)$request->get('inactive'); - $hierarchy = $this->gethierarchy($place_id); - $fqpn = empty($hierarchy) ? '' : $hierarchy[0]->fqpn; - $location = new Location($fqpn); - if ($location->isValid()) { - $lat = $location->getLat(); - $lng = $location->getLon(); - $id = $place_id; - } else { - $lat = ''; - $lng = ''; - $id = $parent_id; - } + /** + * Create or edit a geographic place. + * + * @param Request $request + * + * @return object + * @throws \Exception + */ + public function getAdminPlaceEditAction(Request $request) + { + $parent_id = (int)$request->get('parent_id', 0); + $place_id = (int)$request->get('place_id'); + $inactive = (int)$request->get('inactive'); + $hierarchy = $this->gethierarchy($place_id); + $fqpn = empty($hierarchy) ? '' : $hierarchy[0]->fqpn; + $location = new Location($fqpn); + if ($location->isValid()) { + $lat = $location->getLat(); + $lng = $location->getLon(); + $id = $place_id; + } else { + $lat = ''; + $lng = ''; + $id = $parent_id; + } - $title = I18N::translate('Open Street Maps (Geographic data)'); + $title = I18N::translate('Open Street Maps (Geographic data)'); - $breadcrumbs = [ - route('admin-control-panel') => I18N::translate('Control panel'), - route('admin-modules') => I18N::translate('Module administration'), - route( - 'admin-module', - ['module' => $this->getName(), 'action' => 'AdminPlaces', 'inactive' => $inactive] - ) => $title, - ]; + $breadcrumbs = [ + route('admin-control-panel') => I18N::translate('Control panel'), + route('admin-modules') => I18N::translate('Module administration'), + route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'inactive' => $inactive, + ] + ) => $title, + ]; - foreach ($hierarchy as $row) { - $breadcrumbs[route( - 'admin-module', - ['module' => $this->getName(), - 'action' => 'AdminPlaces', - 'parent_id' => $row->pl_id, - 'inactive' => $inactive] - )] = $row->pl_place; - } - $breadcrumbs[] = $place_id === 0 ? I18N::translate('Add') : I18N::translate('Edit'); + foreach ($hierarchy as $row) { + $breadcrumbs[route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'parent_id' => $row->pl_id, + 'inactive' => $inactive, + ] + )] = $row->pl_place; + } + $breadcrumbs[] = $place_id === 0 ? I18N::translate('Add') : I18N::translate('Edit'); - return (object)[ - 'name' => 'modules/openstreetmap/admin-place-edit', - 'data' => [ - 'module' => $this->getName(), - 'assets' => $this->assets('admin'), - 'breadcrumbs' => $breadcrumbs, - 'title' => $title, - 'location' => $location, - 'place_id' => $place_id, - 'parent_id' => $parent_id, - 'hierarchy' => $hierarchy, - 'inactive' => $inactive, - 'lat' => $lat, - 'lng' => $lng, - 'ref' => $id, - ], - ]; - } + return (object)[ + 'name' => 'modules/openstreetmap/admin-place-edit', + 'data' => [ + 'module' => $this->getName(), + 'assets' => $this->assets('admin'), + 'breadcrumbs' => $breadcrumbs, + 'title' => $title, + 'location' => $location, + 'place_id' => $place_id, + 'parent_id' => $parent_id, + 'hierarchy' => $hierarchy, + 'inactive' => $inactive, + 'lat' => $lat, + 'lng' => $lng, + 'ref' => $id, + ], + ]; + } - /** - * @param Request $request - * @return RedirectResponse - * @throws \Exception - */ - public function postAdminSaveAction(Request $request): RedirectResponse { - $parent_id = (int)$request->get('parent_id'); - $place_id = (int)$request->get('place_id'); - $inactive = (int)$request->get('inactive'); - $lat = round($request->get('new_place_lati'), 5); // 5 decimal places (locate to within about 1 metre) - $lat = ($lat < 0 ? 'S' : 'N') . abs($lat); - $lng = round($request->get('new_place_long'), 5); - $lng = ($lng < 0 ? 'W' : 'E') . abs($lng); - $hierarchy = $this->gethierarchy($parent_id); - $level = count($hierarchy); - $icon = $request->get('icon', null); - $icon = $icon === '' ? null : $icon; - $zoom = $request->get('new_zoom_factor'); - $zoom = $zoom === '' ? null : $zoom; + /** + * @param Request $request + * + * @return RedirectResponse + * @throws \Exception + */ + public function postAdminSaveAction(Request $request): RedirectResponse + { + $parent_id = (int)$request->get('parent_id'); + $place_id = (int)$request->get('place_id'); + $inactive = (int)$request->get('inactive'); + $lat = round($request->get('new_place_lati'), 5); // 5 decimal places (locate to within about 1 metre) + $lat = ($lat < 0 ? 'S' : 'N') . abs($lat); + $lng = round($request->get('new_place_long'), 5); + $lng = ($lng < 0 ? 'W' : 'E') . abs($lng); + $hierarchy = $this->gethierarchy($parent_id); + $level = count($hierarchy); + $icon = $request->get('icon', null); + $icon = $icon === '' ? null : $icon; + $zoom = $request->get('new_zoom_factor'); + $zoom = $zoom === '' ? null : $zoom; - if ($place_id === 0) { - Database::prepare( - "INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) + if ($place_id === 0) { + Database::prepare( + "INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) VALUES (:id, :parent, :level, :place, :lng, :lat, :zoom, :icon)" - )->execute( - [ - 'id' => (int)Database::prepare("SELECT MAX(pl_id)+1 FROM `##placelocation`")->fetchOne(), - 'parent' => $parent_id, - 'level' => $level, - 'place' => $request->get('new_place_name'), - 'lat' => $request->get('lati_control') . $lat, - 'lng' => $request->get('long_control') . $lng, - 'zoom' => $zoom, - 'icon' => $icon, - ] - ); - } else { - Database::prepare( - "UPDATE `##placelocation` SET pl_place = :place, pl_lati = :lat, pl_long = :lng, pl_zoom = :zoom, pl_icon = :icon WHERE pl_id = :id" - )->execute( - [ - 'id' => $place_id, - 'place' => $request->get('new_place_name'), - 'lat' => $request->get('lati_control') . $lat, - 'lng' => $request->get('long_control') . $lng, - 'zoom' => (int)$request->get('new_zoom_factor'), - 'icon' => $icon, - ] - ); - } - FlashMessages::addMessage( - I18N::translate( - 'The details for “%s” have been updated.', - $request->get('new_place_name') - ), - 'success' - ); + )->execute( + [ + 'id' => (int)Database::prepare("SELECT MAX(pl_id)+1 FROM `##placelocation`")->fetchOne(), + 'parent' => $parent_id, + 'level' => $level, + 'place' => $request->get('new_place_name'), + 'lat' => $request->get('lati_control') . $lat, + 'lng' => $request->get('long_control') . $lng, + 'zoom' => $zoom, + 'icon' => $icon, + ] + ); + } else { + Database::prepare( + "UPDATE `##placelocation` SET pl_place = :place, pl_lati = :lat, pl_long = :lng, pl_zoom = :zoom, pl_icon = :icon WHERE pl_id = :id" + )->execute( + [ + 'id' => $place_id, + 'place' => $request->get('new_place_name'), + 'lat' => $request->get('lati_control') . $lat, + 'lng' => $request->get('long_control') . $lng, + 'zoom' => (int)$request->get('new_zoom_factor'), + 'icon' => $icon, + ] + ); + } + FlashMessages::addMessage( + I18N::translate( + 'The details for “%s” have been updated.', + $request->get('new_place_name') + ), + 'success' + ); - return new RedirectResponse( - route( - 'admin-module', - ['module' => $this->getName(), 'action' => 'AdminPlaces', 'inactive' => $inactive] - ) - ); - } + return new RedirectResponse( + route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'inactive' => $inactive, + ] + ) + ); + } - /** - * Delete a geographic place. - * - * @param Request $request - * @return RedirectResponse - * @throws \Exception - */ - public function postAdminDeleteRecordAction(Request $request): RedirectResponse { - $place_id = (int)$request->get('place_id'); - $parent_id = (int)$request->get('parent_id'); - $inactive = (int)$request->get('inactive'); + /** + * Delete a geographic place. + * + * @param Request $request + * + * @return RedirectResponse + * @throws \Exception + */ + public function postAdminDeleteRecordAction(Request $request): RedirectResponse + { + $place_id = (int)$request->get('place_id'); + $parent_id = (int)$request->get('parent_id'); + $inactive = (int)$request->get('inactive'); - try { - Database::prepare( - "DELETE FROM `##placelocation` WHERE pl_id = :id" - )->execute( - [ - 'id' => $place_id, - ] - ); - } catch (\Exception $ex) { - DebugBar::addThrowable($ex); + try { + Database::prepare( + "DELETE FROM `##placelocation` WHERE pl_id = :id" + )->execute( + [ + 'id' => $place_id, + ] + ); + } catch (\Exception $ex) { + DebugBar::addThrowable($ex); - FlashMessages::addMessage( - I18N::translate('Location not removed: this location contains sub-locations'), - 'danger' - ); - } - // If after deleting there are no more places at this level then go up a level - $children = (int)Database::prepare( - "SELECT COUNT(pl_id) FROM `##placelocation` WHERE pl_parent_id = :parent_id" - ) - ->execute(['parent_id' => $parent_id]) - ->fetchOne(); + FlashMessages::addMessage( + I18N::translate('Location not removed: this location contains sub-locations'), + 'danger' + ); + } + // If after deleting there are no more places at this level then go up a level + $children = (int)Database::prepare( + "SELECT COUNT(pl_id) FROM `##placelocation` WHERE pl_parent_id = :parent_id" + ) + ->execute(['parent_id' => $parent_id]) + ->fetchOne(); - if ($children === 0) { - $row = Database::prepare('SELECT pl_parent_id FROM `##placelocation` WHERE pl_id = :parent_id') - ->execute(['parent_id' => $parent_id]) - ->fetchOneRow(); - $parent_id = $row->pl_parent_id; - } + if ($children === 0) { + $row = Database::prepare('SELECT pl_parent_id FROM `##placelocation` WHERE pl_id = :parent_id') + ->execute(['parent_id' => $parent_id]) + ->fetchOneRow(); + $parent_id = $row->pl_parent_id; + } - return new RedirectResponse( - route( - 'admin-module', - ['module' => $this->getName(), - 'action' => 'AdminPlaces', - 'parent_id' => $parent_id, - 'inactive' => $inactive] - ) - ); - } + return new RedirectResponse( + route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'parent_id' => $parent_id, + 'inactive' => $inactive, + ] + ) + ); + } - /** - * @param Request $request - * @return RedirectResponse - * @throws \Exception - */ - public function getAdminExportAction(Request $request): RedirectResponse { - $parent_id = (int)$request->get('parent_id'); - $format = $request->get('format', 'csv'); - $maxlevel = (int)Database::prepare("SELECT max(pl_level) FROM `##placelocation`")->execute()->fetchOne(); - $startfqpn = []; - $hierarchy = $this->gethierarchy($parent_id); - $geojson = []; + /** + * @param Request $request + * + * @return RedirectResponse + * @throws \Exception + */ + public function getAdminExportAction(Request $request): RedirectResponse + { + $parent_id = (int)$request->get('parent_id'); + $format = $request->get('format', 'csv'); + $maxlevel = (int)Database::prepare("SELECT max(pl_level) FROM `##placelocation`")->execute()->fetchOne(); + $startfqpn = []; + $hierarchy = $this->gethierarchy($parent_id); + $geojson = []; - // Create the file name - $place_name = empty($hierarchy) ? 'Global' : $hierarchy[0]->fqpn; // $hierarchy[0] always holds the full placename - $place_name = str_replace(Place::GEDCOM_SEPARATOR, '-', $place_name); - $filename = 'Places-' . preg_replace('/[^a-zA-Z0-9\-\.]/', '', $place_name) . '.' . $format; + // Create the file name + $place_name = empty($hierarchy) ? 'Global' : $hierarchy[0]->fqpn; // $hierarchy[0] always holds the full placename + $place_name = str_replace(Place::GEDCOM_SEPARATOR, '-', $place_name); + $filename = 'Places-' . preg_replace('/[^a-zA-Z0-9\-\.]/', '', $place_name) . '.' . $format; - // Fill in the place names for the starting conditions - foreach ($hierarchy as $level => $record) { - $startfqpn[$level] = $record->pl_place; - } - $startfqpn = array_pad($startfqpn, $maxlevel + 1, ''); + // Fill in the place names for the starting conditions + foreach ($hierarchy as $level => $record) { + $startfqpn[$level] = $record->pl_place; + } + $startfqpn = array_pad($startfqpn, $maxlevel + 1, ''); - // Generate an array containing the data to output - $this->buildLevel($parent_id, $startfqpn, $places); + // Generate an array containing the data to output + $this->buildLevel($parent_id, $startfqpn, $places); - if ($format === 'csv') { - // Create the header line for the output file (always English) - $placenames[] = I18N::translate('Level'); - for ($i = 0; $i <= $maxlevel; $i++) { - $placenames[] = 'Place' . $i; - } - $header = array_merge($placenames, ['Longitude', 'Latitude', 'Zoom', 'Icon']); - array_unshift($places, $header); - } else { - $geojson = ['type' => 'FeatureCollection', 'features' => []]; - } - // Output the data - try { - $fp = fopen('php://output', 'wb'); - header_remove(); - header("Content-Type: application/download charset=utf-8"); - header("Content-Disposition: attachment; filename=$filename"); + if ($format === 'csv') { + // Create the header line for the output file (always English) + $placenames[] = I18N::translate('Level'); + for ($i = 0; $i <= $maxlevel; $i++) { + $placenames[] = 'Place' . $i; + } + $header = array_merge($placenames, [ + 'Longitude', + 'Latitude', + 'Zoom', + 'Icon', + ]); + array_unshift($places, $header); + } else { + $geojson = [ + 'type' => 'FeatureCollection', + 'features' => [], + ]; + } + // Output the data + try { + $fp = fopen('php://output', 'wb'); + header_remove(); + header("Content-Type: application/download charset=utf-8"); + header("Content-Disposition: attachment; filename=$filename"); - foreach ($places as $place) { - if ($format === 'csv') { - fputcsv($fp, $place); - } else { - if (!$place['pl_long'] || !$place['pl_lati']) { - continue; - } - $fqpn = implode( - Place::GEDCOM_SEPARATOR, - array_reverse( - array_filter( - array_slice($place, 1, $maxlevel + 1) - ) - ) - ); - $long = (float)strtr($place['pl_long'], ['E' => '', 'W' => '-', ',' => '.']); - $lati = (float)strtr($place['pl_lati'], ['N' => '', 'S' => '-', ',' => '.']); + foreach ($places as $place) { + if ($format === 'csv') { + fputcsv($fp, $place); + } else { + if (!$place['pl_long'] || !$place['pl_lati']) { + continue; + } + $fqpn = implode( + Place::GEDCOM_SEPARATOR, + array_reverse( + array_filter( + array_slice($place, 1, $maxlevel + 1) + ) + ) + ); + $long = (float)strtr($place['pl_long'], [ + 'E' => '', + 'W' => '-', + ',' => '.', + ]); + $lati = (float)strtr($place['pl_lati'], [ + 'N' => '', + 'S' => '-', + ',' => '.', + ]); - $geojson['features'][] = [ - 'type' => 'Feature', - 'geometry' => [ - 'type' => 'Point', - 'coordinates' => [$long, $lati], - ], - 'properties' => [ - 'level' => $place[0], - 'name' => $fqpn, - 'zoom' => $place['pl_zoom'], - 'icon' => $place['pl_icon'], - ], - ]; - } - } - if ($format === 'geojson') { - $jsonstr = json_encode($geojson, JSON_PRETTY_PRINT); - header("Content-Length: " . strlen($jsonstr)); - fwrite($fp, $jsonstr); - } - fclose($fp); - } catch (\Exception $e) { - Log::addErrorLog($e->getMessage()); - FlashMessages::addMessage($e->getMessage(), 'error'); - } + $geojson['features'][] = [ + 'type' => 'Feature', + 'geometry' => [ + 'type' => 'Point', + 'coordinates' => [ + $long, + $lati, + ], + ], + 'properties' => [ + 'level' => $place[0], + 'name' => $fqpn, + 'zoom' => $place['pl_zoom'], + 'icon' => $place['pl_icon'], + ], + ]; + } + } + if ($format === 'geojson') { + $jsonstr = json_encode($geojson, JSON_PRETTY_PRINT); + header("Content-Length: " . strlen($jsonstr)); + fwrite($fp, $jsonstr); + } + fclose($fp); + } catch (\Exception $e) { + Log::addErrorLog($e->getMessage()); + FlashMessages::addMessage($e->getMessage(), 'error'); + } - return new RedirectResponse(route('admin-module', ['module' => $this->getName(), 'action' => 'AdminPlaces'])); - } + return new RedirectResponse(route('admin-module', [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + ])); + } - /** - * @param Request $request - * @return object - */ - public function getAdminImportFormAction(Request $request) { - $parent_id = (int)$request->get('parent_id'); - $inactive = (int)$request->get('inactive'); - $breadcrumbs = [ - route('admin-control-panel') => I18N::translate('Control panel'), - route('admin-modules') => I18N::translate('Module administration'), - route( - 'admin-module', - [ - 'module' => $this->getName(), - 'action' => 'AdminPlaces', - 'parent_id' => 0, - 'inactive' => $inactive, - ] - ) => $this->getTitle() . ' (' . I18N::translate('Geographic data') . ')', - I18N::translate('Import file'), - ]; - $files = $this->findFiles(WT_MODULES_DIR . $this->getName() . '/extra', ['csv', 'geojson', 'json']); - uasort( - $files, - function ($a, $b) { - $la = strlen($a); - $lb = strlen($b); + /** + * @param Request $request + * + * @return object + */ + public function getAdminImportFormAction(Request $request) + { + $parent_id = (int)$request->get('parent_id'); + $inactive = (int)$request->get('inactive'); + $breadcrumbs = [ + route('admin-control-panel') => I18N::translate('Control panel'), + route('admin-modules') => I18N::translate('Module administration'), + route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'parent_id' => 0, + 'inactive' => $inactive, + ] + ) => $this->getTitle() . ' (' . I18N::translate('Geographic data') . ')', + I18N::translate('Import file'), + ]; + $files = $this->findFiles(WT_MODULES_DIR . $this->getName() . '/extra', [ + 'csv', + 'geojson', + 'json', + ]); + uasort( + $files, + function ($a, $b) { + $la = strlen($a); + $lb = strlen($b); - return $la === $lb ? I18N::strcasecmp($a, $b) : $la - $lb; - } - ); + return $la === $lb ? I18N::strcasecmp($a, $b) : $la - $lb; + } + ); - return (object)[ - 'name' => 'modules/openstreetmap/admin-import-form', - 'data' => [ - 'title' => I18N::translate('Import geographic data'), - 'module' => $this->getName(), - 'breadcrumbs' => $breadcrumbs, - 'parent_id' => $parent_id, - 'inactive' => $inactive, - 'files' => $files, - ], - ]; - } + return (object)[ + 'name' => 'modules/openstreetmap/admin-import-form', + 'data' => [ + 'title' => I18N::translate('Import geographic data'), + 'module' => $this->getName(), + 'breadcrumbs' => $breadcrumbs, + 'parent_id' => $parent_id, + 'inactive' => $inactive, + 'files' => $files, + ], + ]; + } - /** - * This function assumes the input file layout is - * level followed by a variable number of placename fields - * followed by Longitude, Latitude, Zoom & Icon - * - * @param Request $request - * @return RedirectResponse - * @throws \Exception - */ - public function postAdminImportAction(Request $request): RedirectResponse { - $serverfile = $request->get('serverfile'); - $options = $request->get('import-options'); - $inactive = $request->get('inactive'); - $filename = ''; - $places = []; - $input_array = []; - $fields = 0; - $delimiter = ''; - $field_names = ['pl_level', 'pl_long', 'pl_lati', 'pl_zoom', 'pl_icon', 'fqpn']; + /** + * This function assumes the input file layout is + * level followed by a variable number of placename fields + * followed by Longitude, Latitude, Zoom & Icon + * + * @param Request $request + * + * @return RedirectResponse + * @throws \Exception + */ + public function postAdminImportAction(Request $request): RedirectResponse + { + $serverfile = $request->get('serverfile'); + $options = $request->get('import-options'); + $inactive = $request->get('inactive'); + $filename = ''; + $places = []; + $input_array = []; + $fields = 0; + $delimiter = ''; + $field_names = [ + 'pl_level', + 'pl_long', + 'pl_lati', + 'pl_zoom', + 'pl_icon', + 'fqpn', + ]; - if ($serverfile !== '') { // first choice is file on server - $filename = WT_MODULES_DIR . $this->getName() . '/extra/' . $serverfile; - } elseif ($_FILES['localfile']['error'] === UPLOAD_ERR_OK) { // 2nd choice is local file - $filename = $_FILES['localfile']['tmp_name']; - } + if ($serverfile !== '') { // first choice is file on server + $filename = WT_MODULES_DIR . $this->getName() . '/extra/' . $serverfile; + } elseif ($_FILES['localfile']['error'] === UPLOAD_ERR_OK) { // 2nd choice is local file + $filename = $_FILES['localfile']['tmp_name']; + } - if (is_file($filename)) { - $string = file_get_contents($filename); - $filetype = '?'; + if (is_file($filename)) { + $string = file_get_contents($filename); + $filetype = '?'; - // Check the filetype - if (stripos($string, 'FeatureCollection') !== false) { - $filetype = 'geojson'; - } else { - $input_array = preg_split("/\r?\n/", $string, -1, PREG_SPLIT_NO_EMPTY); - $record = $input_array[0]; + // Check the filetype + if (stripos($string, 'FeatureCollection') !== false) { + $filetype = 'geojson'; + } else { + $input_array = preg_split("/\r?\n/", $string, -1, PREG_SPLIT_NO_EMPTY); + $record = $input_array[0]; - if (strpos($record, ';') !== false) { - $delimiter = ';'; - } elseif (strpos($record, ',') !== false) { - $delimiter = ','; - } - if ($delimiter !== '') { - if (!is_numeric($record[0])) { // lose the header - array_shift($input_array); - } + if (strpos($record, ';') !== false) { + $delimiter = ';'; + } elseif (strpos($record, ',') !== false) { + $delimiter = ','; + } + if ($delimiter !== '') { + if (!is_numeric($record[0])) { // lose the header + array_shift($input_array); + } - // are the records in a format we can read - $row = explode($delimiter, $input_array[0]); - $fields = count($row); - if ($fields >= 6 && - (bool)preg_match("/[SN][0-9]*\.?[0-9]*/", $row[$fields - 3]) && - (bool)preg_match("/[EW][0-9]*\.?[0-9]*/", $row[$fields - 4])) { - $filetype = 'csv'; - } - } - } + // are the records in a format we can read + $row = explode($delimiter, $input_array[0]); + $fields = count($row); + if ($fields >= 6 && + (bool)preg_match("/[SN][0-9]*\.?[0-9]*/", $row[$fields - 3]) && + (bool)preg_match("/[EW][0-9]*\.?[0-9]*/", $row[$fields - 4])) { + $filetype = 'csv'; + } + } + } - switch ($filetype) { - case 'geojson': - $input_array = json_decode($string); - foreach ($input_array->features as $feature) { - $places[] = array_combine( - $field_names, - [ - isset($feature->properties->level) ? $feature->properties->level : substr_count( - $feature->properties->name, - ',' - ), - ($feature->geometry->coordinates[0] < 0 ? 'W' : 'E') . abs( - $feature->geometry->coordinates[0] - ), - ($feature->geometry->coordinates[1] < 0 ? 'S' : 'N') . abs( - $feature->geometry->coordinates[1] - ), - isset($feature->properties->zoom) ? $feature->properties->zoom : null, - isset($feature->properties->icon) ? $feature->properties->icon : null, - $feature->properties->name, - ] - ); - } - break; - case 'csv': - foreach ($input_array as $line) { - $row = explode($delimiter, $line); - array_walk( - $row, - function (&$item) { - $item = ($item === '') ? null : trim($item, '"\''); - } - ); - // convert separate place fields into a comma separated placename - $row[] = implode( - Place::GEDCOM_SEPARATOR, - array_filter( - array_reverse( - array_splice($row, 1, $fields - 5) - ) - ) - ); - $places[] = array_combine($field_names, $row); - } - break; - default: - //invalid file type - } + switch ($filetype) { + case 'geojson': + $input_array = json_decode($string); + foreach ($input_array->features as $feature) { + $places[] = array_combine( + $field_names, + [ + isset($feature->properties->level) ? $feature->properties->level : substr_count( + $feature->properties->name, + ',' + ), + ($feature->geometry->coordinates[0] < 0 ? 'W' : 'E') . abs( + $feature->geometry->coordinates[0] + ), + ($feature->geometry->coordinates[1] < 0 ? 'S' : 'N') . abs( + $feature->geometry->coordinates[1] + ), + isset($feature->properties->zoom) ? $feature->properties->zoom : null, + isset($feature->properties->icon) ? $feature->properties->icon : null, + $feature->properties->name, + ] + ); + } + break; + case 'csv': + foreach ($input_array as $line) { + $row = explode($delimiter, $line); + array_walk( + $row, + function (&$item) { + $item = ($item === '') ? null : trim($item, '"\''); + } + ); + // convert separate place fields into a comma separated placename + $row[] = implode( + Place::GEDCOM_SEPARATOR, + array_filter( + array_reverse( + array_splice($row, 1, $fields - 5) + ) + ) + ); + $places[] = array_combine($field_names, $row); + } + break; + default: + //invalid file type + } - if ($filetype !== '?') { - if ((bool)$request->get('cleardatabase')) { - Database::exec("TRUNCATE TABLE `##placelocation`"); - } - //process places - $added = 0; - $updated = 0; + if ($filetype !== '?') { + if ((bool)$request->get('cleardatabase')) { + Database::exec("TRUNCATE TABLE `##placelocation`"); + } + //process places + $added = 0; + $updated = 0; - //sort places by level - usort( - $places, - function (array $a, array $b) { - if ((int)$a['pl_level'] === (int)$b['pl_level']) { - return I18N::strcasecmp($a['fqpn'], $b['fqpn']); - } else { - return (int)$a['pl_level'] - (int)$b['pl_level']; - } - } - ); + //sort places by level + usort( + $places, + function (array $a, array $b) { + if ((int)$a['pl_level'] === (int)$b['pl_level']) { + return I18N::strcasecmp($a['fqpn'], $b['fqpn']); + } else { + return (int)$a['pl_level'] - (int)$b['pl_level']; + } + } + ); - foreach ($places as $place) { - $location = new Location($place['fqpn']); - $valid = $location->isValid(); + foreach ($places as $place) { + $location = new Location($place['fqpn']); + $valid = $location->isValid(); - // can't match data type here because default table values are null - // but csv file return empty string - if ($valid && $options !== 'add' && ( - $place['pl_level'] != $location->getLevel() || - $place['pl_long'] != $location->getLon('DMS+') || - $place['pl_lati'] != $location->getLat('DMS+') || - $place['pl_zoom'] != $location->getZoom() || - $place['pl_icon'] != $location->getIcon() - )) { + // can't match data type here because default table values are null + // but csv file return empty string + if ($valid && $options !== 'add' && ( + $place['pl_level'] != $location->getLevel() || + $place['pl_long'] != $location->getLon('DMS+') || + $place['pl_lati'] != $location->getLat('DMS+') || + $place['pl_zoom'] != $location->getZoom() || + $place['pl_icon'] != $location->getIcon() + )) { - // overwrite - $location->update((object)$place); - $updated++; - } elseif (!$valid && $options !== 'update') { - //add - $place_parts = explode(Place::GEDCOM_SEPARATOR, $place['fqpn']); - // work throught the place parts starting at level 0, - // looking for a record in the database, if not found then add it - $parent_id = 0; - for ($i = count($place_parts) - 1; $i >= 0; $i--) { - $new_parts = array_slice($place_parts, $i); - $new_fqpn = implode(Place::GEDCOM_SEPARATOR, $new_parts); - $new_location = new Location($new_fqpn, - [ - 'fqpn' => $new_fqpn, - 'pl_id' => 0, - 'pl_parent_id' => $parent_id, - 'pl_level' => count($new_parts) - 1, - 'pl_place' => $new_parts[0], - 'pl_long' => $i === 0 ? $place['pl_long'] : null, - 'pl_lati' => $i === 0 ? $place['pl_lati'] : null, - 'pl_zoom' => $i === 0 ? $place['pl_zoom'] : null, - 'pl_icon' => $i === 0 ? $place['pl_icon'] : null, - ] - ); + // overwrite + $location->update((object)$place); + $updated++; + } elseif (!$valid && $options !== 'update') { + //add + $place_parts = explode(Place::GEDCOM_SEPARATOR, $place['fqpn']); + // work throught the place parts starting at level 0, + // looking for a record in the database, if not found then add it + $parent_id = 0; + for ($i = count($place_parts) - 1; $i >= 0; $i--) { + $new_parts = array_slice($place_parts, $i); + $new_fqpn = implode(Place::GEDCOM_SEPARATOR, $new_parts); + $new_location = new Location($new_fqpn, + [ + 'fqpn' => $new_fqpn, + 'pl_id' => 0, + 'pl_parent_id' => $parent_id, + 'pl_level' => count($new_parts) - 1, + 'pl_place' => $new_parts[0], + 'pl_long' => $i === 0 ? $place['pl_long'] : null, + 'pl_lati' => $i === 0 ? $place['pl_lati'] : null, + 'pl_zoom' => $i === 0 ? $place['pl_zoom'] : null, + 'pl_icon' => $i === 0 ? $place['pl_icon'] : null, + ] + ); - if ($new_location->isValid()) { - $parent_id = $new_location->getId(); - } else { - $parent_id = $new_location->add(); - $added++; - } - } - } - } - FlashMessages::addMessage( - I18N::translate( - 'locations updated: %s, locations added: %s', - I18N::number($updated), - I18N::number($added) - ), - $added + $updated === 0 ? 'info' : 'success' - ); - } else { - FlashMessages::addMessage(I18N::translate('Unable to detect the file format: %s', $filename), 'danger'); - } - } else { - FlashMessages::addMessage(I18N::translate('Unable to open file: %s', $filename), 'danger'); - } + if ($new_location->isValid()) { + $parent_id = $new_location->getId(); + } else { + $parent_id = $new_location->add(); + $added++; + } + } + } + } + FlashMessages::addMessage( + I18N::translate( + 'locations updated: %s, locations added: %s', + I18N::number($updated), + I18N::number($added) + ), + $added + $updated === 0 ? 'info' : 'success' + ); + } else { + FlashMessages::addMessage(I18N::translate('Unable to detect the file format: %s', $filename), 'danger'); + } + } else { + FlashMessages::addMessage(I18N::translate('Unable to open file: %s', $filename), 'danger'); + } - return new RedirectResponse( - route( - 'admin-module', - ['module' => $this->getName(), 'action' => 'AdminPlaces', 'inactive' => $inactive] - ) - ); - } + return new RedirectResponse( + route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'inactive' => $inactive, + ] + ) + ); + } - /** - * @param Request $request - * @return RedirectResponse - * @throws \Exception - */ - public function postAdminImportPlacesAction(Request $request): RedirectResponse { - $gedcomName = $request->get('ged'); - $inactive = (int)$request->get('inactive'); - $tree = Tree::findByName($gedcomName); + /** + * @param Request $request + * + * @return RedirectResponse + * @throws \Exception + */ + public function postAdminImportPlacesAction(Request $request): RedirectResponse + { + $gedcomName = $request->get('ged'); + $inactive = (int)$request->get('inactive'); + $tree = Tree::findByName($gedcomName); - // Get all the places from the places table ... - $places = Database::prepare( - " + // Get all the places from the places table ... + $places = Database::prepare( + " SELECT CONCAT_WS(:separator, t1.p_place, t2.p_place, t3.p_place, t4.p_place, t5.p_place, t6.p_place, t7.p_place, t8.p_place) AS fqpn FROM `##places` t1 @@ -1239,17 +1392,17 @@ class OpenStreetMapModule extends AbstractModule implements ModuleConfigInterfac WHERE t1.p_file = :gedcom ORDER BY t1.p_parent_id " - )->execute( - [ - 'separator' => Place::GEDCOM_SEPARATOR, - 'gedcom' => $tree->getTreeId(), - ] - ) - ->fetchOneColumn(); + )->execute( + [ + 'separator' => Place::GEDCOM_SEPARATOR, + 'gedcom' => $tree->getTreeId(), + ] + ) + ->fetchOneColumn(); - // ... and the placelocation table - $locations = Database::prepare( - " + // ... and the placelocation table + $locations = Database::prepare( + " SELECT CONCAT_WS(:separator, t1.pl_place, t2.pl_place, t3.pl_place, t4.pl_place, t5.pl_place, t6.pl_place, t7.pl_place, t8.pl_place) AS fqpn FROM `##placelocation` AS t1 @@ -1262,310 +1415,324 @@ class OpenStreetMapModule extends AbstractModule implements ModuleConfigInterfac LEFT JOIN `##placelocation` AS t8 ON t8.pl_parent_id = t8.pl_id ORDER BY t1.pl_parent_id " - )->execute(['separator' => Place::GEDCOM_SEPARATOR]) - ->fetchOneColumn(); + )->execute(['separator' => Place::GEDCOM_SEPARATOR]) + ->fetchOneColumn(); - // Compare the two ... - $diff = array_diff($places, $locations); - // ... and process the differences - if (!empty($diff)) { - unset($places, $locations); - $inserted = 0; - $nextRecordId = Database::prepare("SELECT MAX(pl_id)+1 FROM `##placelocation`")->fetchOne(); - $insertRecordQry = Database::prepare( - "INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place)" . - " VALUES (:id, :parent, :level, :place)" - ); - $checkRecordQry = Database::prepare( - "SELECT pl1.pl_id" . - " FROM `##placelocation` AS pl1" . - " LEFT JOIN `##placelocation` AS pl2 ON (pl1.pl_parent_id = pl2.pl_id)" . - " LEFT JOIN `##placelocation` AS pl3 ON (pl2.pl_parent_id = pl3.pl_id)" . - " LEFT JOIN `##placelocation` AS pl4 ON (pl3.pl_parent_id = pl4.pl_id)" . - " LEFT JOIN `##placelocation` AS pl5 ON (pl4.pl_parent_id = pl5.pl_id)" . - " LEFT JOIN `##placelocation` AS pl6 ON (pl5.pl_parent_id = pl6.pl_id)" . - " LEFT JOIN `##placelocation` AS pl7 ON (pl6.pl_parent_id = pl7.pl_id)" . - " LEFT JOIN `##placelocation` AS pl8 ON (pl7.pl_parent_id = pl8.pl_id)" . - " LEFT JOIN `##placelocation` AS pl9 ON (pl8.pl_parent_id = pl9.pl_id)" . - " WHERE CONCAT_WS(:separator1, pl1.pl_place, pl2.pl_place, pl3.pl_place, pl4.pl_place, pl5.pl_place, pl6.pl_place, pl7.pl_place, pl8.pl_place, pl9.pl_place) LIKE CONCAT('%', :f1, '%')" . - " AND CONCAT_WS(:separator2, pl1.pl_place, pl2.pl_place, pl3.pl_place, pl4.pl_place, pl5.pl_place, pl6.pl_place, pl7.pl_place, pl8.pl_place, pl9.pl_place) NOT LIKE CONCAT('%,%', :f1, '%')" - ); + // Compare the two ... + $diff = array_diff($places, $locations); + // ... and process the differences + if (!empty($diff)) { + unset($places, $locations); + $inserted = 0; + $nextRecordId = Database::prepare("SELECT MAX(pl_id)+1 FROM `##placelocation`")->fetchOne(); + $insertRecordQry = Database::prepare( + "INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place)" . + " VALUES (:id, :parent, :level, :place)" + ); + $checkRecordQry = Database::prepare( + "SELECT pl1.pl_id" . + " FROM `##placelocation` AS pl1" . + " LEFT JOIN `##placelocation` AS pl2 ON (pl1.pl_parent_id = pl2.pl_id)" . + " LEFT JOIN `##placelocation` AS pl3 ON (pl2.pl_parent_id = pl3.pl_id)" . + " LEFT JOIN `##placelocation` AS pl4 ON (pl3.pl_parent_id = pl4.pl_id)" . + " LEFT JOIN `##placelocation` AS pl5 ON (pl4.pl_parent_id = pl5.pl_id)" . + " LEFT JOIN `##placelocation` AS pl6 ON (pl5.pl_parent_id = pl6.pl_id)" . + " LEFT JOIN `##placelocation` AS pl7 ON (pl6.pl_parent_id = pl7.pl_id)" . + " LEFT JOIN `##placelocation` AS pl8 ON (pl7.pl_parent_id = pl8.pl_id)" . + " LEFT JOIN `##placelocation` AS pl9 ON (pl8.pl_parent_id = pl9.pl_id)" . + " WHERE CONCAT_WS(:separator1, pl1.pl_place, pl2.pl_place, pl3.pl_place, pl4.pl_place, pl5.pl_place, pl6.pl_place, pl7.pl_place, pl8.pl_place, pl9.pl_place) LIKE CONCAT('%', :f1, '%')" . + " AND CONCAT_WS(:separator2, pl1.pl_place, pl2.pl_place, pl3.pl_place, pl4.pl_place, pl5.pl_place, pl6.pl_place, pl7.pl_place, pl8.pl_place, pl9.pl_place) NOT LIKE CONCAT('%,%', :f1, '%')" + ); - foreach ($diff as $place) { - $parent_id = 0; - $place_parts = array_reverse(explode(Place::GEDCOM_SEPARATOR, $place)); - $search = ''; - for ($i = 0, $count = count($place_parts); $i < $count; $i++) { - $place_part = $place_parts[$i]; - $search = $place_part . Place::GEDCOM_SEPARATOR . $search; - $search = trim($search, Place::GEDCOM_SEPARATOR); - $id = $checkRecordQry->execute( - [ - 'separator1' => Place::GEDCOM_SEPARATOR, - 'separator2' => Place::GEDCOM_SEPARATOR, - 'f1' => $search, - 'f2' => $search, - ] - )->fetchOne(); + foreach ($diff as $place) { + $parent_id = 0; + $place_parts = array_reverse(explode(Place::GEDCOM_SEPARATOR, $place)); + $search = ''; + for ($i = 0, $count = count($place_parts); $i < $count; $i++) { + $place_part = $place_parts[$i]; + $search = $place_part . Place::GEDCOM_SEPARATOR . $search; + $search = trim($search, Place::GEDCOM_SEPARATOR); + $id = $checkRecordQry->execute( + [ + 'separator1' => Place::GEDCOM_SEPARATOR, + 'separator2' => Place::GEDCOM_SEPARATOR, + 'f1' => $search, + 'f2' => $search, + ] + )->fetchOne(); - if ($id === null) { - $inserted++; - $insertRecordQry->execute( - [ - 'id' => $nextRecordId++, - 'parent' => $parent_id, - 'level' => $i, - 'place' => $place_part, - ] - ); - } else { - $parent_id = $id; - } - } - } - FlashMessages::addMessage( - I18N::translate( - '%s Records added. Now use the edit page to add the coordinates etc.', - $inserted - ), - 'success' - ); - } else { - FlashMessages::addMessage(I18N::translate('No Records added.')); - } + if ($id === null) { + $inserted++; + $insertRecordQry->execute( + [ + 'id' => $nextRecordId++, + 'parent' => $parent_id, + 'level' => $i, + 'place' => $place_part, + ] + ); + } else { + $parent_id = $id; + } + } + } + FlashMessages::addMessage( + I18N::translate( + '%s Records added. Now use the edit page to add the coordinates etc.', + $inserted + ), + 'success' + ); + } else { + FlashMessages::addMessage(I18N::translate('No Records added.')); + } - return new RedirectResponse( - route( - 'admin-module', - ['module' => $this->getName(), 'action' => 'AdminPlaces', 'inactive' => $inactive] - ) - ); - } + return new RedirectResponse( + route( + 'admin-module', + [ + 'module' => $this->getName(), + 'action' => 'AdminPlaces', + 'inactive' => $inactive, + ] + ) + ); + } - /* - * Utility Functions - */ + /* + * Utility Functions + */ - /** - * Find all of the places in the hierarchy - * - * @param int $id - * @param bool $show_inactive - * @return \stdClass[] - * @throws \Exception - */ - private function getPlaceListLocation($id, $show_inactive = false) { - $child_qry = Database::prepare( - "SELECT COUNT(*) AS child_count, SUM(" . - " p1.pl_place IS NOT NULL AND (p1.pl_lati IS NULL OR p1.pl_long IS NULL) OR " . - " p2.pl_place IS NOT NULL AND (p2.pl_lati IS NULL OR p2.pl_long IS NULL) OR " . - " p3.pl_place IS NOT NULL AND (p3.pl_lati IS NULL OR p3.pl_long IS NULL) OR " . - " p4.pl_place IS NOT NULL AND (p4.pl_lati IS NULL OR p4.pl_long IS NULL) OR " . - " p5.pl_place IS NOT NULL AND (p5.pl_lati IS NULL OR p5.pl_long IS NULL) OR " . - " p6.pl_place IS NOT NULL AND (p6.pl_lati IS NULL OR p6.pl_long IS NULL) OR " . - " p7.pl_place IS NOT NULL AND (p7.pl_lati IS NULL OR p7.pl_long IS NULL) OR " . - " p8.pl_place IS NOT NULL AND (p8.pl_lati IS NULL OR p8.pl_long IS NULL) OR " . - " p9.pl_place IS NOT NULL AND (p9.pl_lati IS NULL OR p9.pl_long IS NULL)) AS no_coord" . - " FROM `##placelocation` AS p1" . - " LEFT JOIN `##placelocation` AS p2 ON (p2.pl_parent_id = p1.pl_id)" . - " LEFT JOIN `##placelocation` AS p3 ON (p3.pl_parent_id = p2.pl_id)" . - " LEFT JOIN `##placelocation` AS p4 ON (p4.pl_parent_id = p3.pl_id)" . - " LEFT JOIN `##placelocation` AS p5 ON (p5.pl_parent_id = p4.pl_id)" . - " LEFT JOIN `##placelocation` AS p6 ON (p6.pl_parent_id = p5.pl_id)" . - " LEFT JOIN `##placelocation` AS p7 ON (p7.pl_parent_id = p6.pl_id)" . - " LEFT JOIN `##placelocation` AS p8 ON (p8.pl_parent_id = p7.pl_id)" . - " LEFT JOIN `##placelocation` AS p9 ON (p9.pl_parent_id = p8.pl_id)" . - " WHERE p1.pl_parent_id = :parent_id" - ); + /** + * Find all of the places in the hierarchy + * + * @param int $id + * @param bool $show_inactive + * + * @return \stdClass[] + * @throws \Exception + */ + private function getPlaceListLocation($id, $show_inactive = false) + { + $child_qry = Database::prepare( + "SELECT COUNT(*) AS child_count, SUM(" . + " p1.pl_place IS NOT NULL AND (p1.pl_lati IS NULL OR p1.pl_long IS NULL) OR " . + " p2.pl_place IS NOT NULL AND (p2.pl_lati IS NULL OR p2.pl_long IS NULL) OR " . + " p3.pl_place IS NOT NULL AND (p3.pl_lati IS NULL OR p3.pl_long IS NULL) OR " . + " p4.pl_place IS NOT NULL AND (p4.pl_lati IS NULL OR p4.pl_long IS NULL) OR " . + " p5.pl_place IS NOT NULL AND (p5.pl_lati IS NULL OR p5.pl_long IS NULL) OR " . + " p6.pl_place IS NOT NULL AND (p6.pl_lati IS NULL OR p6.pl_long IS NULL) OR " . + " p7.pl_place IS NOT NULL AND (p7.pl_lati IS NULL OR p7.pl_long IS NULL) OR " . + " p8.pl_place IS NOT NULL AND (p8.pl_lati IS NULL OR p8.pl_long IS NULL) OR " . + " p9.pl_place IS NOT NULL AND (p9.pl_lati IS NULL OR p9.pl_long IS NULL)) AS no_coord" . + " FROM `##placelocation` AS p1" . + " LEFT JOIN `##placelocation` AS p2 ON (p2.pl_parent_id = p1.pl_id)" . + " LEFT JOIN `##placelocation` AS p3 ON (p3.pl_parent_id = p2.pl_id)" . + " LEFT JOIN `##placelocation` AS p4 ON (p4.pl_parent_id = p3.pl_id)" . + " LEFT JOIN `##placelocation` AS p5 ON (p5.pl_parent_id = p4.pl_id)" . + " LEFT JOIN `##placelocation` AS p6 ON (p6.pl_parent_id = p5.pl_id)" . + " LEFT JOIN `##placelocation` AS p7 ON (p7.pl_parent_id = p6.pl_id)" . + " LEFT JOIN `##placelocation` AS p8 ON (p8.pl_parent_id = p7.pl_id)" . + " LEFT JOIN `##placelocation` AS p9 ON (p9.pl_parent_id = p8.pl_id)" . + " WHERE p1.pl_parent_id = :parent_id" + ); - // We know the id of the place in the placelocation table, - // now get the id of the same place in the places table - if ($id === 0) { - $place_id = 0; - } else { - $hierarchy = $this->gethierarchy($id); - $fqpn = preg_quote($hierarchy[0]->fqpn); - $place_id = Database::prepare( - "SELECT p1.p_id" . - " FROM `##places` AS p1" . - " LEFT JOIN `##places` AS p2 ON (p1.p_parent_id = p2.p_id)" . - " LEFT JOIN `##places` AS p3 ON (p2.p_parent_id = p3.p_id)" . - " LEFT JOIN `##places` AS p4 ON (p3.p_parent_id = p4.p_id)" . - " LEFT JOIN `##places` AS p5 ON (p4.p_parent_id = p5.p_id)" . - " LEFT JOIN `##places` AS p6 ON (p5.p_parent_id = p6.p_id)" . - " LEFT JOIN `##places` AS p7 ON (p6.p_parent_id = p7.p_id)" . - " LEFT JOIN `##places` AS p8 ON (p7.p_parent_id = p8.p_id)" . - " LEFT JOIN `##places` AS p9 ON (p8.p_parent_id = p9.p_id)" . - " WHERE CONCAT_WS(', ', p1.p_place, p2.p_place, p3.p_place, p4.p_place, p5.p_place, p6.p_place, p7.p_place, p8.p_place, p9.p_place)=:place_name" - )->execute( - [ - 'place_name' => $fqpn, - ] - )->fetchOne(); - } + // We know the id of the place in the placelocation table, + // now get the id of the same place in the places table + if ($id === 0) { + $place_id = 0; + } else { + $hierarchy = $this->gethierarchy($id); + $fqpn = preg_quote($hierarchy[0]->fqpn); + $place_id = Database::prepare( + "SELECT p1.p_id" . + " FROM `##places` AS p1" . + " LEFT JOIN `##places` AS p2 ON (p1.p_parent_id = p2.p_id)" . + " LEFT JOIN `##places` AS p3 ON (p2.p_parent_id = p3.p_id)" . + " LEFT JOIN `##places` AS p4 ON (p3.p_parent_id = p4.p_id)" . + " LEFT JOIN `##places` AS p5 ON (p4.p_parent_id = p5.p_id)" . + " LEFT JOIN `##places` AS p6 ON (p5.p_parent_id = p6.p_id)" . + " LEFT JOIN `##places` AS p7 ON (p6.p_parent_id = p7.p_id)" . + " LEFT JOIN `##places` AS p8 ON (p7.p_parent_id = p8.p_id)" . + " LEFT JOIN `##places` AS p9 ON (p8.p_parent_id = p9.p_id)" . + " WHERE CONCAT_WS(', ', p1.p_place, p2.p_place, p3.p_place, p4.p_place, p5.p_place, p6.p_place, p7.p_place, p8.p_place, p9.p_place)=:place_name" + )->execute( + [ + 'place_name' => $fqpn, + ] + )->fetchOne(); + } - $rows = Database::prepare( - "SELECT pl_id, pl_parent_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon," . - " (t1.p_place IS NULL) AS inactive" . - " FROM `##placelocation`" . - " LEFT JOIN (SELECT p_place" . - " FROM `##places`" . - " WHERE p_parent_id = :p_id) AS t1 ON pl_place = t1.p_place" . - " WHERE pl_parent_id=:id" . - " ORDER BY pl_place COLLATE :collation" - ) - ->execute( - [ - 'id' => $id, - 'p_id' => $place_id, - 'collation' => I18N::collation(), - ] - )->fetchAll(\PDO::FETCH_ASSOC); + $rows = Database::prepare( + "SELECT pl_id, pl_parent_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon," . + " (t1.p_place IS NULL) AS inactive" . + " FROM `##placelocation`" . + " LEFT JOIN (SELECT p_place" . + " FROM `##places`" . + " WHERE p_parent_id = :p_id) AS t1 ON pl_place = t1.p_place" . + " WHERE pl_parent_id=:id" . + " ORDER BY pl_place COLLATE :collation" + ) + ->execute( + [ + 'id' => $id, + 'p_id' => $place_id, + 'collation' => I18N::collation(), + ] + )->fetchAll(\PDO::FETCH_ASSOC); - $list = []; - /** @var array $rows */ - foreach ($rows as $row) { - if ($row['inactive'] && !$show_inactive) { - continue; - } + $list = []; + /** @var array $rows */ + foreach ($rows as $row) { + if ($row['inactive'] && !$show_inactive) { + continue; + } - // Find/count places without co-ordinates - $children = $child_qry->execute( - [ - 'parent_id' => $row['pl_id'], - ] - )->fetchOneRow(); + // Find/count places without co-ordinates + $children = $child_qry->execute( + [ + 'parent_id' => $row['pl_id'], + ] + )->fetchOneRow(); - if ($row['inactive']) { - $badge = 'danger'; - } elseif ((int)$children->no_coord > 0) { - $badge = 'warning'; - } elseif ((int)$children->child_count > 0) { - $badge = 'info'; - } else { - $badge = 'secondary'; - } + if ($row['inactive']) { + $badge = 'danger'; + } elseif ((int)$children->no_coord > 0) { + $badge = 'warning'; + } elseif ((int)$children->child_count > 0) { + $badge = 'info'; + } else { + $badge = 'secondary'; + } - $list[] = (object)array_merge( - $row, - [ - 'child_count' => (int)$children->child_count, - 'badge' => $badge, - ] - ); - } + $list[] = (object)array_merge( + $row, + [ + 'child_count' => (int)$children->child_count, + 'badge' => $badge, + ] + ); + } - return $list; - } + return $list; + } - /** - * @param $id - * @return array - * @throws \Exception - */ - private function gethierarchy($id) { - $statement = Database::prepare("SELECT pl_id, pl_parent_id, pl_place FROM `##placelocation` WHERE pl_id=:id"); - $arr = []; - $fqpn = []; - while ($id !== 0) { - $row = $statement->execute(['id' => $id])->fetchOneRow(); - $fqpn[] = $row->pl_place; - $row->fqpn = implode(Place::GEDCOM_SEPARATOR, $fqpn); - $id = (int)$row->pl_parent_id; - $arr[] = $row; - } + /** + * @param $id + * + * @return array + * @throws \Exception + */ + private function gethierarchy($id) + { + $statement = Database::prepare("SELECT pl_id, pl_parent_id, pl_place FROM `##placelocation` WHERE pl_id=:id"); + $arr = []; + $fqpn = []; + while ($id !== 0) { + $row = $statement->execute(['id' => $id])->fetchOneRow(); + $fqpn[] = $row->pl_place; + $row->fqpn = implode(Place::GEDCOM_SEPARATOR, $fqpn); + $id = (int)$row->pl_parent_id; + $arr[] = $row; + } - return array_reverse($arr); - } + return array_reverse($arr); + } - /** - * @param $parent_id - * @param $placename - * @param $places - * @throws \Exception - */ - private function buildLevel($parent_id, $placename, &$places) { - $level = array_search('', $placename); - $rows = (array)Database::prepare( - "SELECT pl_level, pl_id, pl_place, pl_long, pl_lati, pl_zoom, pl_icon FROM `##placelocation` WHERE pl_parent_id=? ORDER BY pl_place" - ) - ->execute([$parent_id]) - ->fetchAll(\PDO::FETCH_ASSOC); + /** + * @param $parent_id + * @param $placename + * @param $places + * + * @throws \Exception + */ + private function buildLevel($parent_id, $placename, &$places) + { + $level = array_search('', $placename); + $rows = (array)Database::prepare( + "SELECT pl_level, pl_id, pl_place, pl_long, pl_lati, pl_zoom, pl_icon FROM `##placelocation` WHERE pl_parent_id=? ORDER BY pl_place" + ) + ->execute([$parent_id]) + ->fetchAll(\PDO::FETCH_ASSOC); - if (!empty($rows)) { - foreach ($rows as $row) { - $index = $row['pl_id']; - $placename[$level] = $row['pl_place']; - $places[] = array_merge([$row['pl_level']], $placename, array_splice($row, 3)); - $this->buildLevel($index, $placename, $places); - } - } - } + if (!empty($rows)) { + foreach ($rows as $row) { + $index = $row['pl_id']; + $placename[$level] = $row['pl_place']; + $places[] = array_merge([$row['pl_level']], $placename, array_splice($row, 3)); + $this->buildLevel($index, $placename, $places); + } + } + } - /** - * recursively find all of the files of specified types on the server - * - * @param string $path - * @param string[] $filetypes - * @return array - */ - private function findFiles($path, $filetypes) { - $placefiles = []; + /** + * recursively find all of the files of specified types on the server + * + * @param string $path + * @param string[] $filetypes + * + * @return array + */ + private function findFiles($path, $filetypes) + { + $placefiles = []; - try { - $di = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS); - $it = new \RecursiveIteratorIterator($di); + try { + $di = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS); + $it = new \RecursiveIteratorIterator($di); - foreach ($it as $file) { - if (in_array($file->getExtension(), $filetypes)) { - $placefiles[] = $file->getFilename(); - } - } - } catch (\Exception $ex) { - DebugBar::addThrowable($ex); - Log::addErrorLog(basename($ex->getFile()) . ' - line: ' . $ex->getLine() . ' - ' . $ex->getMessage()); - } + foreach ($it as $file) { + if (in_array($file->getExtension(), $filetypes)) { + $placefiles[] = $file->getFilename(); + } + } + } catch (\Exception $ex) { + DebugBar::addThrowable($ex); + Log::addErrorLog(basename($ex->getFile()) . ' - line: ' . $ex->getLine() . ' - ' . $ex->getMessage()); + } - return $placefiles; - } + return $placefiles; + } - // @TODO shift the following function to somewhere more appropriate during restructure + // @TODO shift the following function to somewhere more appropriate during restructure - /** - * Copied from AbstractChartController.php - * - * Find the ancestors of an individual, and generate an array indexed by - * Sosa-Stradonitz number. - * - * @param Individual $individual Start with this individual - * @param int $generations Fetch this number of generations - * @return Individual[] - */ - private function sosaStradonitzAncestors(Individual $individual, int $generations): array { - /** @var Individual[] $ancestors */ - $ancestors = [ - 1 => $individual, - ]; + /** + * Copied from AbstractChartController.php + * + * Find the ancestors of an individual, and generate an array indexed by + * Sosa-Stradonitz number. + * + * @param Individual $individual Start with this individual + * @param int $generations Fetch this number of generations + * + * @return Individual[] + */ + private function sosaStradonitzAncestors(Individual $individual, int $generations): array + { + /** @var Individual[] $ancestors */ + $ancestors = [ + 1 => $individual, + ]; - for ($i = 1, $max = 2 ** ($generations - 1); $i < $max; $i++) { - $ancestors[$i * 2] = null; - $ancestors[$i * 2 + 1] = null; + for ($i = 1, $max = 2 ** ($generations - 1); $i < $max; $i++) { + $ancestors[$i * 2] = null; + $ancestors[$i * 2 + 1] = null; - $individual = $ancestors[$i]; + $individual = $ancestors[$i]; - if ($individual !== null) { - $family = $individual->getPrimaryChildFamily(); - if ($family !== null) { - if ($family->getHusband() !== null) { - $ancestors[$i * 2] = $family->getHusband(); - } - if ($family->getWife() !== null) { - $ancestors[$i * 2 + 1] = $family->getWife(); - } - } - } - } + if ($individual !== null) { + $family = $individual->getPrimaryChildFamily(); + if ($family !== null) { + if ($family->getHusband() !== null) { + $ancestors[$i * 2] = $family->getHusband(); + } + if ($family->getWife() !== null) { + $ancestors[$i * 2 + 1] = $family->getWife(); + } + } + } + } - return $ancestors; - } + return $ancestors; + } } |
