Skip to content

feat(model): make translation auto-creation on read configurable - #87

Merged
paullla merged 1 commit into
Locastic:masterfrom
paullla:feat/no-write-on-read
Jul 28, 2026
Merged

feat(model): make translation auto-creation on read configurable#87
paullla merged 1 commit into
Locastic:masterfrom
paullla:feat/no-write-on-read

Conversation

@paullla

@paullla paullla commented Jul 28, 2026

Copy link
Copy Markdown
Member
Q A
Branch? master
Bug fix? yes, opt-in (the write-on-read footgun)
New feature? yes, auto_create_translations option + getOrCreateTranslation()
BC breaks? no (default keeps the 2.0 behavior)
Deprecations? yes, leaving auto_create_translations unset (default flips in 3.0)
Issues Fix #55 (also the root cause behind the closed #34, #32)
License MIT

Problem

getTranslation() creates and attaches a translation whenever both the requested and the fallback locale are missing. With the documented cascade: persist mapping, a plain read can then insert empty translation rows on the next flush, or die on not-null columns (#55, #34, #32).

Changes

  • New auto_create_translations config option. true (default) keeps the 2.0 behavior; false makes getTranslation() return a detached translation for a missing locale: reads still see empty fields, but nothing is attached, cached or persisted. Leaving the option unset triggers a deprecation; the default flips to false in 3.0.
  • New TranslatableTrait::getOrCreateTranslation(?string $locale): the explicit write target for virtual setters. Targets the exact locale and never falls back (so setters can no longer overwrite the fallback translation's content), attaches regardless of the option. README setter example and context7 rules updated to it.
  • AssignLocaleListener stamps the flag onto loaded/persisted translatables (same conduit as the locales), method_exists-guarded so TranslatableInterface gains no method.
  • The deprecated ApiPlatformTranslationExtension sets the new parameter too, keeping legacy setups compiling.
  • CHANGELOG + UPGRADE-2.1 entries.

Verification

  • 92 unit/functional tests green (13 new: trait behavior for both option values, exact-locale setter semantics, listener stamping, config validation), composer validate --strict clean.
  • Verified in demo apps (API Platform 4.3 and 3.4) over real HTTP: the Automatically add translation when it does not exist #55 repro (read missing locale + flush = NOT NULL explosion) is fixed with the option off, read/write parity with the option on, getOrCreateTranslation() persists correctly, invalid config rejected, deprecation logged.

getTranslation() creates and attaches a translation whenever both the
requested and the fallback locale are missing; with the documented
cascade: persist mapping, a read can then insert empty translation
rows on the next flush or die on not-null columns (Locastic#55, Locastic#34, Locastic#32).

Add an auto_create_translations option (default true, the 2.0
behavior; the default flips to false in 3.0, and leaving the option
unset is deprecated since 2.1). AssignLocaleListener stamps it onto
loaded and persisted translatables, like it already does with the
locales. When disabled, getTranslation() returns a detached
translation for a missing locale: reads still see empty fields but
nothing is attached, cached or persisted.

Virtual setters need an explicit write target once auto-creation is
off, so the trait gains getOrCreateTranslation(): it creates and
attaches the missing translation for the exact locale, never falling
back (getTranslation()'s fallback would hand setters the fallback
translation and let them overwrite its content), regardless of the
option. The README setter example now writes through it, and the
context7 rules cover the new setter pattern and recommend disabling
auto-creation.

The deprecated ApiPlatformTranslationExtension hardcodes the bundle
parameters, so it sets the new one too, keeping legacy setups
compiling.
@paullla
paullla force-pushed the feat/no-write-on-read branch from f6005d5 to bf580a2 Compare July 28, 2026 09:47
@paullla
paullla merged commit 0d2e223 into Locastic:master Jul 28, 2026
6 checks passed
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.

Automatically add translation when it does not exist Not null violation

1 participant