Known Limitations
This page tracks current library behavior and workarounds that should be rechecked as Articulate evolves. Other guides link here when a limitation affects the feature they describe.
Mapping
Section titled “Mapping”- Snake_case fields sometimes need explicit
#[Property(name: ...)]mappings until hydrator fallback behavior is rechecked. - Same-table projections are supported, but each entity class is still an independent identity-map context — two classes mapping the same row are different PHP objects.
- Projection entities still need primary-key metadata for clean hydration, identity-map registration,
find(), and second-level cache behavior.
Relations
Section titled “Relations”- Lazy relation proxies cannot currently be flushed safely in some dependency configurations — prefer explicit
loadRelation()when a relation needs to be shown or written through. EntityManager::loadRelation()currently returnsnullforMorphToManyandMorphedByManyrelation objects — query the pivot table directly as a workaround.- Relation-owned foreign key columns should not also be mapped as scalar properties on the same entity.
Query builder
Section titled “Query builder”whereRaw()should always use bound parameters, e.g.whereRaw('total > ?', [100]); concatenating user input is unsafe.
Migrations
Section titled “Migrations”- A clean checkout with checked-in migrations can run
articulate:migratewithout first runningarticulate:diff. articulate:diffmay expose current schema-comparison gaps around polymorphic pivot columns.- A polymorphic pivot may need to store
taggable_idasVARCHAR(36)if it must hold both integer and UUID identifiers — and current checked-in schemas can carry a required technicalidcolumn even though the natural pivot key istaggable_type,taggable_id, andtag_id.
Hydration
Section titled “Hydration”- Normal aggregate or specific-column query-builder selects force raw array hydration before custom hydrators can run.
ScalarHydratorcurrently returns scalar values that can still be sent to Unit of Work registration, causing type errors in some paths.PartialHydratordelegates through object hydration in a way that can temporarily register an empty-id entity before partial fields are applied.
Caching
Section titled “Caching”- Second-level cache serves
find()by class and primary key. It does not servefindBy(), query-buildergetResult(), or chunked/list reads. - Writes evict sibling classes that share the same table and primary key, but the in-memory identity map does not synchronize different projection objects already loaded in the same manager.
- Result cache can return stale aggregate data inside its TTL.