Skip to content

2.0.0-rc.3

Pre-release
Pre-release

Choose a tag to compare

@dereuromark dereuromark released this 20 May 19:50
· 8 commits to main since this release
7a938e5

Fixes

  • Fix recycle() silently rebuilding a mid-chain required parent. Recycling a node composed via the new withRequiredParents() no longer lands in the "explicit" association bucket, so DataCompiler::mergeWithToOne() substitutes the recycled row instead of rebuilding it (#89).
  • Fix BaseFactory::collectForeignKeyColumns() FK to alias cache going stale on runtime association changes. The cache is now invalidated when a belongsTo is added, removed, or replaced, so both the strictDefinition detector and the auto-skip in DataCompiler see the current schema (#91).
  • Fix foreignKey => false belongsTo composition crashing at persist time with "Cannot set an empty field". Cake's BelongsTo::saveAssociated() can't cascade through a relation with no FK column; DataCompiler now routes that one edge through an independent save that joins the active test transaction, applies nested IS_ASSOCIATED semantics, and replays the parent factory's afterSave callbacks (#93).
  • Fix two transaction-lifecycle defects in FactoryTransactionStrategy: a failing per-connection rollback no longer aborts the cascade or leaves the strategy pointing at dead connections; BaseFactory::finalizePersistedEntities() now runs unconditionally so an associated entity saved via a parent's connection still gets clean() / setNew(false) / setSource() (#94).
  • Fix ScenarioAwareTrait::loadFixtureScenario() swallowing PHPUnit AssertionFailedError and turning a test failure into a test error. Framework exceptions now pass through untouched while PHP Errors and plumbing exceptions keep wrapping as FixtureScenarioException (#96).
  • Fix has() silently dropping pivot data when the alias is not a belongsToMany. hasOne / hasMany marshallers have no junction to populate, so the pivot was lost on save; has() now throws when $pivot is supplied for a non-BTM alias (#97).
  • Fix ->with('Alias', F1)->with('Alias', F2) losing F1's marshaller options on to-many edges. A parallel $associationHistory now merges marshaller options across every duplicate add for the same to-many alias; to-one keeps the existing last-wins semantics (#98).
  • Fix detection of custom-condition (uuid) join columns for belongsTo declared with 'foreignKey' => false. The FK-in-definition() detector and autoSkipComposeOnExplicitForeignKey now recognize legacy conditions-based joins (#82).
  • Fix with('Alias[N]', SomeFactory::new()) silently dropping the bracket count and building 1 row instead of N. The leaf-factory branch now honors the bracket count just like the array-data path (#103).
  • Fix a configure()-time withRequiredParents() regression where the composed parents survived configure() but their ids never propagated into the child's FK columns, crashing on save with NOT NULL. The demoted-to-defaults bucket from withRequiredParents() was silently overwritten by collectAssociationsFromDefaultTemplate(); now merged with the correct precedence (#105).
  • Fix three pinned-FK precedence bugs in withRequiredParents(): (a) an array-instantiation pin overridden by sequenceField() no longer skips parent composition; (b) the additive requiredParentAssociations() hook now honors the pinned-FK skip uniformly with auto-detected aliases; (c) the entity-instantiation path (Factory::new($entity)) now also composes the parent when sequence may overwrite the entity-side FK pin, and the auto-resolved parent no longer gets silently demoted-into-invisibility on entity-injected builds (#106).

Improvements

  • Add BaseFactory::withRequiredParents() — the ergonomic counterpart to FixtureFactories.strictDefinition. Composes exactly the parents a schema requires (NOT NULL belongsTo FKs) in one call, with optional shared-ancestor reuse via recycle() (#87).
  • Add excludedRequiredParentAssociations() — symmetric exclude hook at the factory class level, complementing the additive requiredParentAssociations() and the per-call $except argument. Exclude wins over both. Composite-key opt-in via the additive hook is now also covered end-to-end (#92, #102).
  • Add visibility for auto-skipped configure() associations (#86).
  • Bake: skip columns managed by TimestampBehavior on insert. Detection is by class (so aliased 'className' => 'Timestamp' loads are caught too) and only 'Model.beforeSave' writers configured with the new or always qualifier are skipped (#95).
  • Add a target type-check on the explicit-alias form of for() / has(). The previous direction guard only checked cardinality, so passing a factory whose target table didn't match the alias silently mis-wired the entity into the wrong slot. The guard now also rejects a target mismatch (#97).
  • Warn at E_USER_WARNING when FactoryTransactionStrategy::setupTest() cannot resolve its primary connection (typo in a subclass, missing test connection config). Previously the eager begin disappeared silently and mixed-style tests leaked direct $table->save() rows across methods — exactly the bug the eager default was reintroduced to fix in v2. Set $primaryConnection = '' to opt out without the warning (#99).
  • recycle($a, $b) now rejects two entities for the same source table in one call — that shape silently dropped the first entity and was almost always a typo for "I want one of these but I'm not sure which". Across separate ->recycle($a)->recycle($b) calls last-wins is preserved as intentional map update (#100).
  • TableAssertionsTrait::assertEntityMissing() now refuses entities that were never persisted — both the null-PK case and the application-assigned-PK (UUID / string) case where isNew() is still true. Previously it short-circuited to false on null PK and silently passed, proving nothing (#103).

Full Changelog: 2.0.0-rc.2...2.0.0-rc.3