Skip to content

Story: Create spatial types through public factories with a shared mutability mode #46

Closed

Description

@Alexandre-T

Create spatial types through public factories with a shared mutability mode

As a developer using spatial-types directly or through a consuming library,
I want public factories that create supported spatial types according to a previously selected mutable or immutable mode,
so that application code and consumers such as spatial-decoder and spatial-transformer can construct spatial objects through a consistent public contract.

Context

Parent Epic: #38.

Depends on #39 for shared public contracts and explicit immutable naming, and on #40–#45 for the complete mutable spatial-type coverage.

The approved creation contract uses static factories organized by dimension, family and spatial type. A shared static setting selects their output representation. This replaces the earlier proposal to fix mutability on individual factory instances.

Factories construct domain objects; they do not decode external representations or transform coordinates. This Story also documents integration expectations without implementing changes in sibling repositories.

Acceptance Criteria

  • SpatialFactory::immutable() selects immutable output globally, SpatialFactory::mutable() selects mutable output globally, and SpatialFactory::isMutable(): bool reports the current setting. The initial setting is immutable.
  • Every public type-specific factory reads this shared static setting on each create() call. A mode change applies to subsequent creation calls across all factories and consuming libraries; it does not change previously created objects. Mutability is not an argument of individual creation calls.
  • Public static factories cover every currently supported instantiable spatial type, coordinate layout and family, including all supported collections. Their namespaces under LongitudeOne\SpatialTypes\Factory parallel the dimension/family/type organization, with one factory per type, dimension and family rather than separate factories for mutable and immutable output. For example, LongitudeOne\SpatialTypes\Factory\Dimension2\Geography\PointFactory::create(...) creates the corresponding immutable Geography point in immutable mode and a mutable XY point with Geography family in mutable mode.
  • Each factory exposes create() using the parameter names, types and defaults of the corresponding spatial constructor, except that family is fixed by the factory namespace rather than passed as an argument. The declared spatial reference remains a creation argument. The same factory and creation arguments serve both mutability modes.
  • Consumers can use these creation APIs through supported public symbols without constructing internal registries, hydrators or other internal factory infrastructure.
  • Factory output preserves supplied coordinates, null ordinates, EMPTY states, spatial type, coordinate layout and declared reference, with the family selected by the factory namespace. Factories preserve the technically representable states supported by the corresponding constructors.
  • Factories accept the coordinate-array forms supported by the corresponding constructors. Every spatial descendant created from those arrays uses the selected representation, including descendants of nested aggregates.
  • Heterogeneous spatial collections can be assembled from explicitly supplied spatial components created through the public factories, including nested collections. This contract does not require inferring component types from untyped coordinate arrays or introducing a new typed-tree input format.
  • Supplied spatial components retain the identity and ownership semantics established by Story: Preserve immutable types under explicit names and shared contracts #39–Story: Edit multi-objects and spatial collections in place #45. Immutable creation rejects mutable components, and mutable creation rejects immutable components, including nested opposite-representation components, without implicit cloning or conversion.
  • Documentation explains the shared global mode, its immutable default, mode switching and isMutable(), including that different consumers in the same execution observe the same current setting.
  • Documentation explains common read interfaces, immutable-only with… methods, mutable-only set…/add…/remove… operations, final immutable classes and component ownership. Documentation and factories use the renamed immutable classes directly, without deprecated aliases or a compatibility layer.
  • Documentation distinguishes family/reference relabelling from coordinate transformation and assigns dimension conversion and reprojection to spatial-transformer. It states that geometric validation is explicit and belongs to spatial-validator, with Point(0, null) as a representable example.
  • Consumer integration expectations and required follow-up work are identified for sibling libraries, including public-factory consumption by spatial-decoder and spatial-transformer, the shared global selection, and handling of in-place changes by Doctrine. This scope identifies and documents follow-up work only; implementation in sibling repositories is outside this Story.

Constraints

  • Apply the naming, namespace, read/copy/mutation and component-ownership contracts established by Epic: Support mutable and immutable spatial objects #38–Story: Edit multi-objects and spatial collections in place #45. Concrete immutable classes are final; do not add deprecated aliases for renamed classes.
  • Coordinate layout and spatial type remain fixed. Geometric validity is delegated to explicit spatial-validator use; do not introduce automatic validation, repair, reprojection or dimension conversion. Changes to declared family or reference preserve coordinates. Preserve the representable states established by Story: Allow partially null point ordinates #36.
  • Preserve the distinction between technical representation and normative geometric validity under ISO/IEC 13249-3 and applicable OGC specifications.
  • A builder is outside this Story and belongs to separate work. External-format decoding and implementation changes in sibling repositories are also outside this Story.

Definition of Done

The project's common Definition of Done applies.

  • composer test-local passes.
  • composer quality passes.
  • External-consumer examples exercise immutable and mutable creation without internal symbols, including mode selection followed by a type-specific static factory call, and repository examples use the new public class names.
  • Tests verify the initial immutable setting, both mode-selection commands, isMutable(), shared selection across different factories, switching between successive creations, and preservation of previously created objects after a switch.
  • Tests cover the supported type/layout/family factory matrix and constructor-equivalent creation arguments, including declared-reference arguments.
  • Tests cover nested coordinate-array construction, heterogeneous collections assembled from explicit components, supplied-component identity, rejection of the opposite representation, EMPTY states, null ordinates and preservation of family/reference across supported creation paths.
  • Story-specific public API documentation and sibling-library integration notes are updated.

Metadata

Metadata

Assignees

Labels

impact:apiAffects the public API

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions