From 078b6ec3e828b5017783aab3f7f2eabc1ea5233b Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Sat, 20 Jun 2026 11:27:29 +0200 Subject: [PATCH 1/2] Fix OCPI2 parking trend parsing Allow parking trend reduction to start from an empty carry value so OCPI2 short-term occupancy data parses cleanly on PHP 8. --- .../Model/SubTypeOccupancyParkingData.php | 2 +- .../ParkingData/ParseParkingDataHandler.php | 39 +++++---- .../pulp-concert/test/ParkingDataTest.php | 86 +++++++++++++++++++ 3 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 packages/pulp-concert/test/ParkingDataTest.php diff --git a/packages/pulp-concert/src/pulpconcert/ParkingData/Model/SubTypeOccupancyParkingData.php b/packages/pulp-concert/src/pulpconcert/ParkingData/Model/SubTypeOccupancyParkingData.php index 1bd307a..bb4c814 100644 --- a/packages/pulp-concert/src/pulpconcert/ParkingData/Model/SubTypeOccupancyParkingData.php +++ b/packages/pulp-concert/src/pulpconcert/ParkingData/Model/SubTypeOccupancyParkingData.php @@ -179,7 +179,7 @@ public function getAllPropertiesAsArray(): array /** * @return array */ - public function jsonSerialize() + public function jsonSerialize(): mixed { return $this->getAllPropertiesAsArray(); } diff --git a/packages/pulp-concert/src/pulpconcert/ParkingData/ParseParkingDataHandler.php b/packages/pulp-concert/src/pulpconcert/ParkingData/ParseParkingDataHandler.php index 47fde29..6e041bf 100644 --- a/packages/pulp-concert/src/pulpconcert/ParkingData/ParseParkingDataHandler.php +++ b/packages/pulp-concert/src/pulpconcert/ParkingData/ParseParkingDataHandler.php @@ -42,6 +42,27 @@ protected static function convertPHWerteTrend(string $phWerteString): ?string }; } + /** + * @param SubTypeOccupancyParkingData[] $subTypeOccupancyData + */ + private static function selectTrendSource(array $subTypeOccupancyData): ?SubTypeOccupancyParkingData + { + return array_reduce( + $subTypeOccupancyData, + static function ( + ?SubTypeOccupancyParkingData $carry, + SubTypeOccupancyParkingData $occupancyParkingData + ): SubTypeOccupancyParkingData { + if (!$carry instanceof SubTypeOccupancyParkingData || $carry->getCapacity() < $occupancyParkingData->getOccupancy()) { + return $occupancyParkingData; + } + + return $carry; + }, + null + ); + } + /** * @param SimpleXMLElement $e * @param ParkingData $parkingData @@ -87,14 +108,7 @@ protected static function mapPHWerte(SimpleXMLElement $e, ParkingData $parkingDa $parkingData->setCapacity($shortTermCapacity); $parkingData->setDriveIn($shortTermDriveIn); $parkingData->setDriveOut($shortTermDriveOut); - $parkingData->setTrend(array_reduce($subTypeOccupancyData, static function (SubTypeOccupancyParkingData $carry, SubTypeOccupancyParkingData $occupancyParkingData): SubTypeOccupancyParkingData { - /** @var SubTypeOccupancyParkingData|null $carry */ - if (!$carry instanceof SubTypeOccupancyParkingData || $carry->getCapacity() < $occupancyParkingData->getOccupancy()) { - return $occupancyParkingData; - } - - return $carry; - })->getTrend()); + $parkingData->setTrend(self::selectTrendSource($subTypeOccupancyData)?->getTrend()); $parkingData->setSubTypeOccupancyData($subTypeOccupancyData); return $parkingData; @@ -149,14 +163,7 @@ protected static function mapOcpi2(SimpleXMLElement $e, ParkingData $parkingData $parkingData->setCapacity($shortTermCapacity); $parkingData->setDriveIn($shortTermDriveIn); $parkingData->setDriveOut($shortTermDriveOut); - $parkingData->setTrend(array_reduce($subTypeOccupancyData, static function (SubTypeOccupancyParkingData $carry, SubTypeOccupancyParkingData $occupancyParkingData): SubTypeOccupancyParkingData { - /** @var SubTypeOccupancyParkingData|null $carry */ - if (!$carry instanceof SubTypeOccupancyParkingData || $carry->getCapacity() < $occupancyParkingData->getOccupancy()) { - return $occupancyParkingData; - } - - return $carry; - })->getTrend()); + $parkingData->setTrend(self::selectTrendSource($subTypeOccupancyData)?->getTrend()); $parkingData->setSubTypeOccupancyData($subTypeOccupancyData); return $parkingData; diff --git a/packages/pulp-concert/test/ParkingDataTest.php b/packages/pulp-concert/test/ParkingDataTest.php new file mode 100644 index 0000000..e6c5247 --- /dev/null +++ b/packages/pulp-concert/test/ParkingDataTest.php @@ -0,0 +1,86 @@ +content = new SimpleXMLElement(<<<'XML' + + + + parking-source-id + ocpi2 + + 2024-01-10T10:15:00Z + active + + parking-1 + + 2024-01-10T10:15:00Z + + open + ok + + shortterm + 12 + 40 + increasing + 5 + 2 + 0 + + + shortterm + 18 + 40 + decreasing + 8 + 3 + 0 + + + shortterm + 30 + 40 + constant + 13 + 5 + 15 + + + + +XML); + + $res = Pulp::start() + ->pipe(Pulp::src($file)) + ->pipe(PulpConcert::parseParkingData()) + ->run(); + + $this->assertCount(1, $res); + $parkingData = $res[0]->content['parking-1'] ?? null; + $this->assertInstanceOf(ParkingData::class, $parkingData); + $this->assertSame(30, $parkingData->getOccupancy()); + $this->assertSame(80, $parkingData->getCapacity()); + $this->assertSame(13, $parkingData->getDriveIn()); + $this->assertSame(5, $parkingData->getDriveOut()); + $this->assertSame('increasing', $parkingData->getTrend()); + } +} From 30ace809ca10ea6507f1ef117f1491d148daafac Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Sat, 20 Jun 2026 11:47:39 +0200 Subject: [PATCH 2/2] Fix traffic message SimpleXML coordinate parsing Avoid deprecated array pointer calls on SimpleXMLElement coordinate values while preserving traffic message GeoJSON output. --- .../Mapper/TrafficMessageMapper.php | 8 +- .../pulp-concert/test/TrafficMessagesTest.php | 137 ++++++++++++++++++ 2 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 packages/pulp-concert/test/TrafficMessagesTest.php diff --git a/packages/pulp-concert/src/pulpconcert/TrafficData/Mapper/TrafficMessageMapper.php b/packages/pulp-concert/src/pulpconcert/TrafficData/Mapper/TrafficMessageMapper.php index ca7cae3..c7c3026 100644 --- a/packages/pulp-concert/src/pulpconcert/TrafficData/Mapper/TrafficMessageMapper.php +++ b/packages/pulp-concert/src/pulpconcert/TrafficData/Mapper/TrafficMessageMapper.php @@ -117,14 +117,14 @@ protected static function mapGeometries(AbstractProjectionHandler $projectionHan foreach ($coordinateDescription->co as $coordinatePair) { $coordinate = []; - if (($val = reset($coordinatePair->x)) !== false) { - $coordinate['x'] = (string) $val; + if (count($coordinatePair->x) > 0) { + $coordinate['x'] = (string) $coordinatePair->x[0]; } else { continue; } - if (($val = reset($coordinatePair->y)) !== false) { - $coordinate['y'] = (string) $val; + if (count($coordinatePair->y) > 0) { + $coordinate['y'] = (string) $coordinatePair->y[0]; } else { continue; } diff --git a/packages/pulp-concert/test/TrafficMessagesTest.php b/packages/pulp-concert/test/TrafficMessagesTest.php new file mode 100644 index 0000000..2143bac --- /dev/null +++ b/packages/pulp-concert/test/TrafficMessagesTest.php @@ -0,0 +1,137 @@ +content = new SimpleXMLElement(<<<'XML' + + + + traffic-message-source-id + braunschweig + + 2024-01-10T10:15:00Z + active + + + message-1 + Roadworks A391 + roadworks + medium + traffic + + Lane closure + + 2024-01-10T10:00:00Z + 2024-01-10T12:00:00Z + + + 2024-01-10T08:00:00Z + 2024-01-10T18:00:00Z + + + + A391 + B4 + + + left lane closed + + + + 605000 + 5792000 + + + 605100 + 5792100 + + + + + + +XML); + + $deprecations = []; + set_error_handler(static function (int $severity, string $message) use (&$deprecations): bool { + if ($severity === E_DEPRECATED && str_contains($message, 'reset(): Calling reset() on an object is deprecated')) { + $deprecations[] = $message; + return true; + } + + return false; + }); + + try { + $res = Pulp::start() + ->pipe(Pulp::src($file)) + ->pipe(PulpConcert::parseTrafficMessages()) + ->pipe(PulpConcert::trafficMessagesToGeoJSON()) + ->run(); + } finally { + restore_error_handler(); + } + + $this->assertSame([], $deprecations); + $this->assertCount(1, $res); + $this->assertEqualsWithDelta( + [ + 'type' => 'FeatureCollection', + 'crs' => ['type' => 'EPSG', 'properties' => ['code' => '4326']], + 'features' => [ + [ + 'type' => 'Feature', + 'id' => 'message-1', + 'geometry' => [ + 'type' => 'GeometryCollection', + 'geometries' => [ + [ + 'type' => 'LineString', + 'coordinates' => [ + [10.538748949971936, 52.26834302487074], + [10.540245004079699, 52.26922265146747], + ], + ], + ], + ], + 'properties' => [ + 'name' => 'Roadworks A391', + 'description' => 'Lane closure', + 'subType' => 'roadworks', + 'category' => 'traffic', + 'roadName' => 'A391, B4', + 'restrictions' => 'left lane closed', + 'id' => 'message-1', + ], + 'when' => [ + 'start' => '2024-01-10T11:00:00+0100', + 'end' => '2024-01-10T13:00:00+0100', + 'dailyStartTime' => '09:00:00+01:00', + 'dailyEndTime' => '19:00:00+01:00', + ], + ], + ], + ], + $res[0]->content, + 0.00001 + ); + } +}