Add PHPUnit tests and fix ORM hydration bugs
Set up PHPUnit 11 inside docker-compose (PHP 8.2 CLI image with ext-mongodb)
and use red tests to drive three fixes in the ORM layer:
- MongoHydrator::dehydrate now recurses through EntityMap so #[Field(name)]
on embedded value objects is honoured symmetrically with hydrate.
dehydrateEmbedded was reading raw property names via ReflectionClass,
which silently broke round-trip when an embedded property had a renamed
field. See ADR-001.
- MongoHydrator::hydrate now resolves missing keys as: constructor default,
then nullable null, then LogicException with the field/class. Previously
every missing key became null, leaking as a TypeError from the entity
constructor for non-nullable typed properties.
- AbstractMongoRepository::persist detects new entities via the new
EntityMetadata::isNewId helper, which treats both '' and null as "new"
(was strict === '', so #[Id] ?string $id = null left null in the upsert
filter and could collide with other null-id documents).
EntityMap also makes #[Collection] optional for non-MongoEntity classes so
embedded value objects can declare #[Field]/#[Embedded] without owning a
Mongo collection.
Tests: 20 cases covering simple/embedded/embedded-list round-trip, BSON
inputs, missing-field semantics, EntityMap building rules, isNewId.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 01:43:35 +03:00
|
|
|
<?php
|
|
|
|
|
|
2026-05-02 04:20:23 +03:00
|
|
|
namespace Tests\Pinecore\Pinecore\Fixtures\Orm;
|
Add PHPUnit tests and fix ORM hydration bugs
Set up PHPUnit 11 inside docker-compose (PHP 8.2 CLI image with ext-mongodb)
and use red tests to drive three fixes in the ORM layer:
- MongoHydrator::dehydrate now recurses through EntityMap so #[Field(name)]
on embedded value objects is honoured symmetrically with hydrate.
dehydrateEmbedded was reading raw property names via ReflectionClass,
which silently broke round-trip when an embedded property had a renamed
field. See ADR-001.
- MongoHydrator::hydrate now resolves missing keys as: constructor default,
then nullable null, then LogicException with the field/class. Previously
every missing key became null, leaking as a TypeError from the entity
constructor for non-nullable typed properties.
- AbstractMongoRepository::persist detects new entities via the new
EntityMetadata::isNewId helper, which treats both '' and null as "new"
(was strict === '', so #[Id] ?string $id = null left null in the upsert
filter and could collide with other null-id documents).
EntityMap also makes #[Collection] optional for non-MongoEntity classes so
embedded value objects can declare #[Field]/#[Embedded] without owning a
Mongo collection.
Tests: 20 cases covering simple/embedded/embedded-list round-trip, BSON
inputs, missing-field semantics, EntityMap building rules, isNewId.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 01:43:35 +03:00
|
|
|
|
2026-05-02 04:20:23 +03:00
|
|
|
use Pinecore\Pinecore\Model\MongoEntity;
|
|
|
|
|
use Pinecore\Pinecore\Orm\Attributes\Collection;
|
|
|
|
|
use Pinecore\Pinecore\Orm\Attributes\Field;
|
|
|
|
|
use Pinecore\Pinecore\Orm\Attributes\Id;
|
Add PHPUnit tests and fix ORM hydration bugs
Set up PHPUnit 11 inside docker-compose (PHP 8.2 CLI image with ext-mongodb)
and use red tests to drive three fixes in the ORM layer:
- MongoHydrator::dehydrate now recurses through EntityMap so #[Field(name)]
on embedded value objects is honoured symmetrically with hydrate.
dehydrateEmbedded was reading raw property names via ReflectionClass,
which silently broke round-trip when an embedded property had a renamed
field. See ADR-001.
- MongoHydrator::hydrate now resolves missing keys as: constructor default,
then nullable null, then LogicException with the field/class. Previously
every missing key became null, leaking as a TypeError from the entity
constructor for non-nullable typed properties.
- AbstractMongoRepository::persist detects new entities via the new
EntityMetadata::isNewId helper, which treats both '' and null as "new"
(was strict === '', so #[Id] ?string $id = null left null in the upsert
filter and could collide with other null-id documents).
EntityMap also makes #[Collection] optional for non-MongoEntity classes so
embedded value objects can declare #[Field]/#[Embedded] without owning a
Mongo collection.
Tests: 20 cases covering simple/embedded/embedded-list round-trip, BSON
inputs, missing-field semantics, EntityMap building rules, isNewId.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 01:43:35 +03:00
|
|
|
|
|
|
|
|
#[Collection(name: 'mixed_props')]
|
|
|
|
|
final class MixedPropsEntity implements MongoEntity
|
|
|
|
|
{
|
|
|
|
|
public function __construct(
|
|
|
|
|
#[Id] public readonly string $id,
|
|
|
|
|
#[Field] public readonly string $email,
|
|
|
|
|
public readonly string $untagged = 'ignored',
|
|
|
|
|
) {}
|
|
|
|
|
}
|