Skip to content

Support immutable entities#24

Merged
alganet merged 1 commit intoRespect:masterfrom
alganet:immutable
Apr 1, 2026
Merged

Support immutable entities#24
alganet merged 1 commit intoRespect:masterfrom
alganet:immutable

Conversation

@alganet
Copy link
Copy Markdown
Member

@alganet alganet commented Apr 1, 2026

  • Add EntityFactory::create(class-string, ...props) for constructing entities without calling the constructor (readonly-safe)
  • Add EntityFactory::resolveClass(name) replacing createByName
  • Add EntityFactory::withChanges(entity, ...changes) for immutable copies
  • Add EntityFactory::isReadOnly(entity) for readonly class detection
  • Add ReadOnlyViolation exception for initialized readonly property guard
  • Remove EntityFactory::createByName, hydrate, and disableConstructor
  • Extend persist() to consult identity map for untracked entities, enabling update-by-replacement for immutable entities
  • Add Collection::persist(...$changes) with inline withChanges support
  • Change persist() return type from bool to object (returns the entity)
  • Replace resolveEntityName with Typed::resolveEntityClass using FQN
  • Lift resolveEntityClass into Base hydrator, shared by Flat and Nested
  • Cache resolveClass and detectRelationProperties results
  • Use SplObjectStorage::offsetUnset instead of deprecated detach
  • Normalize terminology: PK/FK -> identity/reference throughout

@alganet alganet requested a review from Copilot April 1, 2026 02:01
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 1, 2026

Codecov Report

❌ Patch coverage is 99.10714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 98.11%. Comparing base (8f29aff) to head (7fe67b7).

Files with missing lines Patch % Lines
src/EntityFactory.php 97.43% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master      #24      +/-   ##
============================================
+ Coverage     97.67%   98.11%   +0.43%     
- Complexity      256      283      +27     
============================================
  Files            16       16              
  Lines           516      583      +67     
============================================
+ Hits            504      572      +68     
+ Misses           12       11       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds first-class support for immutable/readonly entities by introducing constructor-less entity creation/copying in EntityFactory, updating hydrators to resolve concrete entity classes (including typed discriminators), and extending persistence to support update-by-replacement via the identity map.

Changes:

  • Introduces EntityFactory::resolveClass(), create(class-string, ...props), withChanges(), and isReadOnly(), plus a ReadOnlyViolation guard when attempting to modify initialized readonly properties.
  • Updates Flat/Nested hydrators (and shared Base) to resolve entity classes (including Typed) and instantiate entities without calling constructors.
  • Changes persistence to return the entity object and enables update-by-replacement for immutable entities by consulting/replacing entries in the identity map; adds Collection::persist(...$changes) convenience.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/EntityFactory.php Adds class resolution caching, constructor-less creation, readonly detection/guard, and immutable copying via withChanges().
src/ReadOnlyViolation.php Adds a dedicated exception for readonly-property mutation attempts.
src/AbstractMapper.php Changes persist() to return the entity and adds identity-map replacement logic for update-by-replacement.
src/Collections/Collection.php Updates persist() to return the entity and adds inline ...$changes support via withChanges().
src/Collections/Typed.php Switches typed resolution to return a concrete class-string via EntityFactory::resolveClass().
src/Collections/Filtered.php Terminology-only comment update (identifier wording).
src/Hydrators/Base.php Centralizes entity-class resolution (Typed vs non-Typed) and aligns naming to “identity”.
src/Hydrators/Flat.php Instantiates entities via create(resolveClass(...)) and converts typed entities by creating/copying without constructors.
src/Hydrators/Nested.php Instantiates entities via create(resolveEntityClass(...)) rather than name-based construction.
tests/EntityFactoryTest.php Adds coverage for readonly behavior, class resolution, and withChanges() semantics.
tests/AbstractMapperTest.php Adds coverage for identity-map replacement, readonly inserts/updates, and persist() returning the entity.
tests/Collections/CollectionTest.php Adds coverage for Collection::persist(...$changes) returning copies and flushing updates for immutable entities/graphs.
tests/Collections/TypedTest.php Updates typed resolution expectations to return FQCNs via resolveEntityClass().
tests/Hydrators/FlatTest.php Adjusts hydrator tests to new factory usage and collection stacking patterns.
tests/Hydrators/NestedTest.php Adjusts nested hydrator tests to explicit stacking (and child wiring expectations).
tests/InMemoryMapper.php Renames PK/FK variables to id/ref and updates helper naming accordingly.
tests/Stubs/ReadOnlyAuthor.php Adds readonly stub entity for tests.
tests/Stubs/ReadOnlyPost.php Adds readonly stub entity for tests.
tests/Stubs/ReadOnlyComment.php Adds readonly stub entity for tests.
tests/Stubs/Immutable/Author.php Adds immutable readonly stub entity for graph tests.
tests/Stubs/Immutable/Post.php Adds immutable readonly stub entity for graph tests.
tests/Stubs/Immutable/Comment.php Adds immutable readonly stub entity for graph tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Add EntityFactory::create(class-string, ...props) for constructing
  entities without calling the constructor (readonly-safe)
- Add EntityFactory::resolveClass(name) replacing createByName
- Add EntityFactory::withChanges(entity, ...changes) for immutable copies
- Add EntityFactory::isReadOnly(entity) for readonly class detection
- Add ReadOnlyViolation exception for initialized readonly property guard
- Remove EntityFactory::createByName, hydrate, and disableConstructor
- Extend persist() to consult identity map for untracked entities,
  enabling update-by-replacement for immutable entities
- Add Collection::persist(...$changes) with inline withChanges support
- Change persist() return type from bool to object (returns the entity)
- Replace resolveEntityName with Typed::resolveEntityClass using FQN
- Lift resolveEntityClass into Base hydrator, shared by Flat and Nested
- Cache resolveClass and detectRelationProperties results
- Use SplObjectStorage::offsetUnset instead of deprecated detach
- Normalize terminology: PK/FK -> identity/reference throughout
@alganet alganet marked this pull request as ready for review April 1, 2026 02:17
@alganet alganet merged commit d1664a8 into Respect:master Apr 1, 2026
3 checks passed
@alganet alganet deleted the immutable branch April 1, 2026 02:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants