Repository navigation
Epic: Rename spatial-writer to spatial-encoder and redesign the public API #19
Description
Goal
Rename longitude-one/spatial-writer to longitude-one/spatial-encoder and redesign its public API to provide a generic, format-agnostic spatial encoding component.
The library must follow the Strategy design pattern, consistently with the architecture established for spatial-decoder and spatial-transformer.
The public API must expose an Encoder class responsible for encoding objects implementing SpatialInterface into various output representations.
The actual encoding behavior must be delegated to a strategy implementing EncodeStrategyInterface.
The public encoding operation must be named encode().
spatial-writer has never been used in production.
Consequently, this Epic must be implemented as a direct architectural replacement. No backward compatibility, deprecation mechanism, compatibility layer, or transitional API is required.
Scope
Repository and package renaming
Rename the existing repository:
longitude-one/spatial-writer → longitude-one/spatial-encoder
The migration must include:
- Renaming the GitHub repository.
- Renaming the Composer package to
longitude-one/spatial-encoder. - Updating the PHP namespace to
LongitudeOne\SpatialEncoder. - Updating PSR-4 autoloading and test namespaces.
- Updating the README and project documentation.
- Updating Composer dependencies and development scripts where necessary.
- Updating GitHub Actions workflows and repository configuration.
- Updating references to the former repository and package name throughout the codebase.
The existing repository history, issues, pull requests, and relevant project configuration must be preserved.
The renamed repository must remain consistent with the common LongitudeOne spatial-library architecture.
Public encoding API
Introduce a generic public encoding API using the Strategy design pattern.
The API must provide:
- A public
Encoderclass. - A public
EncodeStrategyInterface. - Constructor injection of the encoding strategy.
- A single public encoding operation named
encode().
The API must remain independent of any particular output representation.
Encoding strategy contract
Introduce the public EncodeStrategyInterface.
The interface MUST define exactly one operation:
public function execute(SpatialInterface $spatial): mixed;The input type MUST use SpatialInterface from longitude-one/spatial-types.
The output is intentionally declared as mixed.
The generic encoding API MUST NOT make assumptions about the PHP type used to represent encoded spatial data.
Each concrete encoding strategy is responsible for defining its output representation and the corresponding PHP return type.
Concrete strategies may produce representations such as:
- WKT textual representations.
- WKB binary representations.
- GeoJSON representations.
- PHP arrays or other structured representations.
- Other representations supported by future encoding strategies.
The strategy API MUST NOT assume any particular spatial encoding or serialization format.
Encoder
Introduce a public Encoder class.
The encoder MUST receive its strategy through constructor injection:
final readonly class Encoder
{
public function __construct(
private EncodeStrategyInterface $strategy,
) {
}
public function encode(SpatialInterface $spatial): mixed
{
return $this->strategy->execute($spatial);
}
}The Encoder MUST be declared final readonly.
Its strategy dependency MUST be immutable after construction and MUST NOT be replaceable through a setter or another mutable mechanism.
Concrete encoding strategies SHOULD also be declared readonly whenever they contain state.
Responsibilities
Encoder is responsible only for orchestrating encoding.
It MUST:
- Receive an
EncodeStrategyInterfacethrough its constructor. - Expose
encode(SpatialInterface $spatial): mixed. - Delegate encoding to
EncodeStrategyInterface::execute(). - Return the representation produced by the strategy.
- Make no assumption about the output format or PHP return type.
- Never modify the supplied spatial object.
EncodeStrategyInterface defines the encoding contract.
Each concrete strategy is responsible for:
- Defining its supported spatial input types.
- Defining its output representation.
- Encoding the supplied spatial object according to the applicable format specification.
- Preserving spatial information supported by the target representation.
- Explicitly rejecting unsupported geometry types, coordinate dimensions, or other unsupported spatial properties.
The encoder MUST NOT perform implicit spatial transformations.
Immutability
The encoding API MUST follow the immutable design of longitude-one/spatial-types.
The supplied SpatialInterface MUST NOT be mutated.
The Encoder itself MUST be readonly.
Concrete encoding strategies SHOULD be readonly, and any configuration required by a strategy SHOULD be supplied through constructor injection.
No mutable encoder configuration MUST be introduced through setters or similar mechanisms.
Existing encoding implementations
Existing encoding functionality developed in spatial-writer must be adapted to the new public API.
The migration must:
- Identify existing encoding implementations.
- Adapt their public interfaces to the new Strategy API.
- Preserve existing supported encoding functionality.
- Update the associated unit tests.
- Update usage examples and documentation.
- Remove obsolete public API elements that are superseded by the new architecture.
Existing implementations must not retain the former Writer API solely for backward compatibility.
Format-specific encoding behavior must remain the responsibility of concrete encoding strategies.
Any change to the supported spatial representations or their encoding semantics must be explicitly documented.
Dependency boundaries
The generic encoding API MUST depend only on the abstractions required from longitude-one/spatial-types.
It MUST NOT introduce dependencies on:
- Doctrine.
longitude-one/spatial-decoder.- WKT or WKB parsers.
- A particular database platform.
- A particular external serialization library.
Format-specific dependencies, when required, belong to concrete encoding strategies or their dedicated integrations.
The public API must remain usable independently of any particular output representation.
Testing and quality
Update the existing test suite to validate the renamed repository and redesigned public API.
Tests MUST verify that:
EncodeStrategyInterfacecan be implemented by a concrete encoding strategy.execute()accepts aSpatialInterface.execute()returns the representation produced by the strategy.Encoderreceives its strategy through constructor injection.Encoder::encode()delegates toEncodeStrategyInterface::execute().- The supplied spatial object is passed unchanged to the strategy.
- The result returned by the strategy is returned by
Encoder::encode(). Encoderis declaredfinal readonly.- The injected strategy cannot be replaced after construction.
- The generic API does not depend on a particular output format.
- Strategies producing different PHP output types can implement the same generic encoding contract.
- The supplied spatial object remains unchanged.
Existing format-specific tests must be updated to use the new public API.
The complete test suite must be executed through the standard LongitudeOne quality and continuous integration pipeline.
Documentation
Update the public documentation to describe:
- The purpose of
spatial-encoder. - The public
EncoderAPI. - The
EncodeStrategyInterfacecontract. - The responsibilities of concrete encoding strategies.
- The supported output representations.
- The immutable design of the encoding architecture.
- The relationship between
spatial-encoder,spatial-decoder, andspatial-transformer.
Provide a minimal usage example:
$strategy = new SomeEncodeStrategy(/* configuration */);
$encoder = new Encoder($strategy);
$encoded = $encoder->encode($spatial);Document that each concrete strategy defines its supported spatial input types, output representation, and format-specific configuration.
All documentation and examples must use the new repository name, Composer package, namespace, and public API.
Completion criteria
This Epic may be considered complete when:
- The GitHub repository has been renamed to
longitude-one/spatial-encoder. - The Composer package is named
longitude-one/spatial-encoder. - The production namespace is
LongitudeOne\SpatialEncoder. - PSR-4 autoloading works with the new namespace.
EncodeStrategyInterfaceexists as part of the public API.EncodeStrategyInterfacedeclares exactlyexecute(SpatialInterface $spatial): mixed.- A public
Encoderclass exists and is declaredfinal readonly. Encoderreceives anEncodeStrategyInterfacethrough constructor injection.Encoder::encode()acceptsSpatialInterfaceand returnsmixed.Encoder::encode()delegates encoding toEncodeStrategyInterface::execute().- Existing encoding implementations included in the migration scope use the new public API.
- Existing unit tests have been adapted and execute successfully.
- The obsolete Writer API has been removed.
- No backward-compatibility or deprecation mechanism has been introduced.
- Composer installation and all configured quality checks succeed.
- GitHub Actions executes the complete validation pipeline successfully.
- Public documentation describes the new encoding architecture.
- All associated Stories have been completed and accepted.
Out of scope
- WKT decoding.
- WKB decoding.
- GeoJSON decoding.
- Coordinate Reference System reprojection.
- Implicit coordinate dimension conversion.
- Implicit geometry-type conversion.
- Introduction of new encoding formats unrelated to the architectural migration.
- Implementation of additional encoding strategies unrelated to the existing functionality.
- Backward-compatibility layers for the former Writer API.
- Deprecation mechanisms or transitional support for
spatial-writer.
This Epic does not prescribe the number of implementation Stories or the internal architecture of individual encoding strategies. These decisions will be addressed during refinement.
Activity