From 6312f6657bb6d1cd0b6b35aa72d2e4da3930321e Mon Sep 17 00:00:00 2001 From: Daniel Spitzer Date: Sun, 1 Mar 2026 20:06:25 +0100 Subject: [PATCH] =?UTF-8?q?Pop=20Erweiterung=20Adressen=20nun=20mit=20Stra?= =?UTF-8?q?=C3=9Fenschl=C3=BCssel=20*=20Bugfix=20filtern=20und=20sortieren?= =?UTF-8?q?=20auf=20Adressenbasis=20funktioniert=20nun?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Layout/default/Pop/Form.php | 92 ++++++++++++++++++++--------- application/Pop/PopController.php | 96 +++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 26 deletions(-) diff --git a/Layout/default/Pop/Form.php b/Layout/default/Pop/Form.php index b3e71457d..106fb8c87 100644 --- a/Layout/default/Pop/Form.php +++ b/Layout/default/Pop/Form.php @@ -117,8 +117,47 @@ if (isset($_GET['returnto']) && $_GET['returnto'] == "pop-detail") { +
+ +
+ street) { + $addrDisplay = $pop->street; + if ($pop->number) $addrDisplay .= ' ' . $pop->number; + if ($pop->zip || $pop->city) $addrDisplay .= ', ' . trim($pop->zip . ' ' . $pop->city); + } + ?> + +
+
+
+
+
+ Straße +
+ +
+
+
+
+
+ Nr. +
+ +
+
+
+
+
@@ -139,32 +178,7 @@ if (isset($_GET['returnto']) && $_GET['returnto'] == "pop-detail") {
-
- - - -street ?> - - -
-
-
- Straße -
- -
-
-
-
-
- Nr. -
- -
-
-
+
@@ -280,6 +294,32 @@ if (isset($_GET['returnto']) && $_GET['returnto'] == "pop-detail") { }); + // combined address search with select2 + $('#address_search').select2({ + placeholder: 'Straße Hausnummer, PLZ Ort eingeben...', + allowClear: true, + minimumInputLength: 2, + ajax: { + url: "", + dataType: 'json', + delay: 300, + data: function(params) { return { do: 'searchAddress', q: params.term }; }, + processResults: function(data) { return { results: data.results || [] }; } + } + }); + + $('#address_search').on('select2:select', function(e) { + var d = e.params.data; + $('#street').val(d.street || ''); + $('#number').val(d.number || ''); + $('#zip').val(d.zip || ''); + $('#city').val(d.city || ''); + }); + + $('#address_search').on('select2:clear', function() { + $('#street, #number, #zip, #city').val(''); + }); + // network_id // owner_id // if get parameter network_id is set, select it if found const urlParams = new URLSearchParams(window.location.search); diff --git a/application/Pop/PopController.php b/application/Pop/PopController.php index 49b5f8ffc..fec304094 100644 --- a/application/Pop/PopController.php +++ b/application/Pop/PopController.php @@ -56,6 +56,7 @@ class PopController extends mfBaseController "city" => $pop->city, "street" => $pop->street, "number" => $pop->number, + "address" => trim($pop->street . ' ' . $pop->number . ', ' . $pop->zip . ' ' . $pop->city, ', '), "state" => $pop->state, "folder_link" => $pop->folder_link, "doku_date" => $pop->doku_date, @@ -1411,6 +1412,8 @@ class PopController extends mfBaseController case "getSplicePlanForElement": return $this->getSplicePlanForElementAction(); break; + case "searchAddress": + return $this->searchAddressApi(); default: $return = false; } @@ -1965,4 +1968,97 @@ class PopController extends mfBaseController 'connections' => $result ])); } + + private function searchAddressApi() + { + $q = trim($this->request->q); + if (strlen($q) < 2) { + $this->returnJson(["results" => []]); + } + + $db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME); + + // split input into parts, any order allowed: "graz alte 5" or "Alte Poststraße 5, 8010 Graz" + $parts = preg_split('/[\s,]+/', $q, -1, PREG_SPLIT_NO_EMPTY); + + // categorize: 4-digit = PLZ, short number = hausnummer, text = street or city + $text_parts = []; + $hausnummer = null; + $plz = null; + + foreach ($parts as $part) { + if (preg_match('/^\d{4}$/', $part)) { + $plz = $part; + } elseif ($hausnummer === null && preg_match('/^\d+[a-zA-Z]?$/', $part)) { + $hausnummer = $part; + } else { + $text_parts[] = $part; + } + } + + // Pre-query Gemeinde (tiny table, instant) to resolve text→gemeinde_id + $gemeinde_ids_per_part = []; + foreach ($text_parts as $tp) { + $escaped = $db->escape($tp); + $gres = $db->query("SELECT id FROM Gemeinde WHERE name LIKE '%$escaped%'"); + $ids = []; + if ($gres && $db->num_rows($gres)) { + while ($grow = $db->fetch_object($gres)) { + $ids[] = (int)$grow->id; + } + } + $gemeinde_ids_per_part[$tp] = $ids; + } + + // Build conditions: text parts match Strasse.name OR pre-resolved gemeinde_id (uses index) + $conditions = []; + foreach ($text_parts as $tp) { + $escaped = $db->escape($tp); + if (!empty($gemeinde_ids_per_part[$tp])) { + $ids_str = implode(',', $gemeinde_ids_per_part[$tp]); + $conditions[] = "(Strasse.name LIKE '%$escaped%' OR Strasse.gemeinde_id IN ($ids_str))"; + } else { + $conditions[] = "Strasse.name LIKE '%$escaped%'"; + } + } + if ($hausnummer !== null) { + $hn = $db->escape($hausnummer); + $conditions[] = "Hausnummer.hausnummer LIKE '$hn%'"; + } + if ($plz !== null) { + $pz = $db->escape($plz); + $conditions[] = "Plz.plzstring LIKE '$pz%'"; + } + + $where = count($conditions) ? implode(' AND ', $conditions) : '1=0'; + + $sql = "SELECT Strasse.name as strasse, Hausnummer.hausnummer, Plz.plz, Gemeinde.name as gemeinde + FROM Strasse + STRAIGHT_JOIN Hausnummer ON (Hausnummer.strasse_id = Strasse.id) + LEFT JOIN Plz ON (Plz.id = Hausnummer.plz_id) + LEFT JOIN Gemeinde ON (Gemeinde.id = Strasse.gemeinde_id) + WHERE $where + GROUP BY Strasse.name, Hausnummer.hausnummer, Plz.plz, Gemeinde.name + ORDER BY Strasse.name, Hausnummer.hausnummer + 0, Plz.plz + LIMIT 25"; + $results = []; + $res = $db->query($sql); + if ($db->num_rows($res)) { + while ($row = $db->fetch_object($res)) { + $text = $row->strasse; + if ($row->hausnummer) $text .= ' ' . $row->hausnummer; + if ($row->plz || $row->gemeinde) $text .= ', ' . trim($row->plz . ' ' . $row->gemeinde); + $results[] = [ + "id" => $text, + "text" => $text, + "street" => $row->strasse, + "number" => $row->hausnummer, + "zip" => $row->plz, + "city" => $row->gemeinde, + ]; + } + } + + $this->returnJson(["results" => $results]); + } } \ No newline at end of file