Replies: 5 comments 8 replies
-
Strict typingDilemaI found an interesting point that I would like. to address - the trade-off between strictness and flexibility in the new version of the library. Here's the dilemma: On one hand, if we introduce strict typing and enforce mandatory properties as per the GPX schema, we could potentially achieve more reliable and bug-free code. This would ensure that all necessary properties are present and correctly typed, leading to a more robust library. However, on the other hand, this could limit the usability of the library for GPX files that are missing minor attributes. For example, if a GPX file does not include the 'name' attribute within the copyright section, under strict rules, it would be deemed "invalid", preventing the library from processing it, despite the rest of the file being perfectly valid and usable. Let's take a look at an example GPX file: <gpx>
<metadata>
<name>Example GPX</name>
<copyright>
<!-- Missing 'name' attribute here -->
<year>2023</year>
<license>http://example.com/license</license>
</copyright>
</metadata>
<!-- More GPX data -->
</gpx>With strict typing and enforced mandatory attributes, this GPX file would be considered invalid due to the absence of the 'name' attribute in the copyright element. This could restrict the library from processing it. Hence, the challenge we face is to determine the right balance between maintaining the strictness that comes with adherence to the GPX schema, and ensuring the flexibility to handle GPX files which may not completely follow the schema. SolutionProperties will be defined as nullable for the sake of input flexibility. The values will be converted to correct type if possible. |
Beta Was this translation helpful? Give feedback.
-
MiddlewaresThe additional computational processes for statistical analysis can be managed through middleware that implement the library interface. These middleware will execute in a specified sequence, post GPX parsing, following the basic statistical computations (or the library may include some middleware for elementary stats by default). To better understand my concept, consider the code below. It is merely a rough draft, hence open to modifications. $phpgpx = new \phpGPX();
$phpgpx->middlewares->add(new \phpGPX\Middlewares\GpxReductionSmoothingMiddleware(2, 5));
$phpgpx->middlewares->add(new \phpGPX\Middlewares\TrackPointExtensionStatsMiddleware());
$phpgpx->middlewares->add(new CustomMiddleware());
$file = $phpgpx->load('example.gpx');Implementing such a layer should substantially simplify the extension or modification of the library's behavior. I aim to develop a preliminary model for this layer. This should enhance the library's configurability (I'm not particularly fond of the current use of constants for this purpose). |
Beta Was this translation helpful? Give feedback.
-
Removal of Summarizable and toArrayAs part of the new major release, I propose the removal of the The usage of arrays in this context seems antiquated and unnecessarily complex, hence it doesn't align with the direction of our project. I anticipate that the removal of these features won't be a significant loss for the users. However, I welcome any thoughts and potential concerns about this proposed change. |
Beta Was this translation helpful? Give feedback.
-
phpGPX
|
| Analyzer | What it computes |
|---|---|
DistanceAnalyzer |
Cumulative distance (with optional smoothing) |
ElevationAnalyzer |
Elevation gain/loss (with optional smoothing + spike filtering) |
AltitudeAnalyzer |
Min/max altitude with coordinates |
TimestampAnalyzer |
Start/end timestamps with coordinates, duration |
BoundsAnalyzer |
Coordinate bounds (min/max lat/lon) |
MovementAnalyzer |
Moving duration, moving average speed |
TrackPointExtensionAnalyzer |
Heart rate, cadence, temperature aggregates |
For fine-grained control you can build the engine manually and pick only the analyzers you need:
$engine = (new Engine())
->addAnalyzer(new DistanceAnalyzer(applySmoothing: true, smoothingThreshold: 3))
->addAnalyzer(new ElevationAnalyzer(applySmoothing: true, spikesThreshold: 100))
->addAnalyzer(new AltitudeAnalyzer());Extension Registry
Extensions are no longer hardcoded. A new ExtensionRegistry maps XML namespace URIs to parser classes:
ExtensionInterfaceon models — definesgetTagName(),getNamespace(),jsonSerialize()ExtensionParserInterfaceon parsers — definesparse(),toXML(),getTagName(),getNamespace()Extensionsmodel is now a keyed collection:$point->extensions->get(TrackPointExtension::class)- Default registry auto-registers Garmin TrackPointExtension v1 + v2
- Custom extensions:
$gpx = new phpGPX();
$gpx->registerExtension('http://example.com/ext/v1', MyExtensionParser::class, 'myext');Instance-based configuration
All static config properties on the phpGPX class are gone. Configuration is now split:
Configvalue object — output-only settings (prettyPrint)- Analyzer constructors — processing config (smoothing thresholds, spike filtering, etc.)
Engine::default()factory — convenient defaults with named parameters
$gpx = new phpGPX(
config: new Config(prettyPrint: true),
engine: Engine::default(
sortByTimestamp: true,
applyElevationSmoothing: true,
elevationSmoothingThreshold: 2,
),
);No more global mutable state. Multiple phpGPX instances can coexist with different configurations.
Model cleanup
Pointconstants (WAYPOINT,TRACKPOINT,ROUTEPOINT) replaced withPointTypeenumAbstractExtensionbase class removed — replaced byExtensionInterface- Constructors simplified across all models
- Strict typing on all model properties (nullable where optional per GPX spec)
- All parsers now extend
AbstractParserreducing duplicated boilerplate
Breaking changes from 1.x
| 1.x | 2.x |
|---|---|
phpGPX::load() (static) |
(new phpGPX())->load() (instance) |
phpGPX::$CALCULATE_STATS = true |
new phpGPX(engine: Engine::default()) |
phpGPX::$APPLY_ELEVATION_SMOOTHING |
Engine::default(applyElevationSmoothing: true) |
All static phpGPX::$CONFIG_* properties |
Config object + analyzer constructors |
$model->toArray() |
$model->jsonSerialize() (GeoJSON) |
Point::TRACKPOINT (constant) |
PointType::Trackpoint (enum) |
$ext->trackPointExtension |
$ext->get(TrackPointExtension::class) |
Summarizable interface |
Removed — use JsonSerializable |
GpxSerializable interface |
Removed — parsers handle XML |
StatsCalculator interface |
Removed — use Engine |
Issues addressed in 2.x
Here's the status of issues from the phpGPX 2.0 milestone and related reports:
| Issue | Title | Status | How |
|---|---|---|---|
| #5 | GeoJSON support | Done | Models implement JsonSerializable returning RFC 7946 GeoJSON |
| #15 | Create statistics from GPX extensions | Done | TrackPointExtensionAnalyzer computes HR, cadence, temperature stats |
| #28 | Statistics - get Bounds of the GPX Routes | Done | BoundsAnalyzer computes coordinate bounds for segments, tracks, and routes |
| #42 | Custom trackpoint extension (Bad-Elf) | Done | ExtensionRegistry allows registering any extension by namespace URI |
| #51 | startedAt/finishedAt missing without timestamp | Done | TimestampAnalyzer scans all points, not just first/last |
| #59 | Elevation gain/loss incorrect with GPS gaps | Done | ElevationAnalyzer with configurable smoothing + spike threshold filtering |
| #68 | Middlewares | Replaced | Single-pass Engine with pluggable analyzers (see above) |
| #69 | Removal of Summarizable and toArray | Done | Replaced by JsonSerializable returning GeoJSON |
| #70 | Min altitude is not necessarily the first point | Done | AltitudeAnalyzer tracks actual min/max with coordinates |
| #72 | Add GPX version attribute | Done | GpxFile::$version parsed and preserved on round-trip |
Still open:
| Issue | Title | Status |
|---|---|---|
| #41 | Waypoint and creation time extensions | Open — needs extension registry work |
| #75 | GPX Style Extension | Draft PR — registry is ready for it |
| #76 | Documentation | In progress — mkdocs-material site is set up |
A note on backporting to 1.x
Several of the fixes above (especially #51, #59, #70) address bugs that also exist in 1.x. We should find a way how to backport properly.
Your feedback
If you want to try it out:
composer require sibyx/phpgpx:2.0.0-beta.1
Feedback welcome — especially on the Engine API and extension registry. If you hit any issues, please open an issue or comment here.
Beta Was this translation helpful? Give feedback.
-
|
Hi @Sibyx & many Thx for this great Job!
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Motivation
Greetings, all! It's been quite a few years since the
1.xrelease of the phpGPX library, which was built upon an API from way back in 2018. That version harks back to the PHP5 era, and since then, we've seen the introduction of PHP 7.x and 8.x. It seems like the right time to begin contemplating a significant update for phpGPX, an exciting opportunity to incorporate lessons learned from past mistakes, and integrate some of the innovative features now available in PHP such as typing - a function that would be particularly fitting for this project.This discussion post serves as a platform for me to collate my thoughts and ideas, and for you to provide your invaluable feedback and suggestions. I welcome any ideas for new features, or alternative viewpoints on the plans I've proposed. This is an open discussion, so if you disagree with any aspect of the plan, feel free to voice your thoughts, and we'll take it from there.
Proposed Changes and Improvements
Summarizableinterface and it'stoArraymethod. Models will use \JsonSerializable interface and return GeoJSONInteresting Aspects
1.xand2.x.Project Roadmap
All ideas and suggestions are welcome! I'm excited to see where this journey takes us. The future 2.x version lives in
developbranch.Beta Was this translation helpful? Give feedback.
All reactions