Construction & persistence customisation
ORM::Factory is ORM-agnostic at its core — every build strategy routes
instantiation and persistence through the Persistence adapter.
Three hooks override that adapter when the default behaviour does not fit:
initialize-with— replaces the constructor (theinstantiatecall).to-create— replaces the persistence (thepersistcall oncreate).skip-create— turnscreateintobuild(no persistence at all).
Each hook can be set per-factory (inside the factory block), globally
(at the top level of define), or both. Per-factory wins over
global; child factories inherit the parent hook but can override it.
initialize-with
By default build / create / build-stubbed instantiate via the
adapter's instantiate, which calls $class.new(|%attrs). Override that with
a per-factory hook:
1 2 3 4 5 6 7 8 9 10 11 12 | |
The block receives the evaluator and returns the instance.
attributes-for deliberately bypasses the hook — it returns a plain hash.
The attributes helper
Inside the hook, $eval.attributes is the resolved persisted-attribute hash
(transients and association attributes excluded — the same view
attributes-for returns). Use it to delegate to a constructor that expects
positional args or a different keyword shape:
1 2 3 | |
Global initialize-with
A top-level initialize-with applies to every factory that has no
per-factory hook:
1 2 3 4 5 6 7 8 9 | |
ORM::Factory.global-initialize-with returns the registered global hook;
ORM::Factory.reload clears it.
to-create
to-create replaces the persistence step in create. The default adapter
calls .save-bang (or .save) on the instance; the hook takes the instance
and the evaluator and is responsible for persisting it however the target
store wants:
1 2 3 4 5 6 7 8 9 10 | |
before-create fires before to-create; after-create fires after. build
and build-stubbed never consult to-create.
Global to-create
1 2 3 4 5 6 7 | |
ORM::Factory.global-to-create returns the registered global hook;
ORM::Factory.reload clears it.
skip-create
skip-create makes create behave like build — no persistence happens, but
every callback still fires:
1 2 3 4 5 6 7 8 9 | |
A common shape is a global skip-create plus the few factories that do
persist via an explicit to-create:
1 2 3 4 5 6 7 8 9 10 | |
ORM::Factory.global-skip-create returns the global flag (or undefined);
ORM::Factory.reload clears it.
Resolution order
For each build, the hook is resolved by walking child → parent → global. The first match wins:
- The factory's own hook;
- each parent factory's hook, child-first;
- the global hook from
define; - the adapter default (
instantiate/persist).
For create, to-create and skip-create share the same chain — whichever
appears first wins, so a child to-create can override a parent skip-create
(or vice versa).
Interaction with callbacks
The callback timeline is the same as the default path, with the hooks substituted in:
| Strategy | Step 1 | Step 2 | Step 3 | Step 4 |
|---|---|---|---|---|
build |
initialize-with |
after build |
— | — |
create |
initialize-with |
after build |
before create→ persistence (to-create / skip-create / adapter) → after create |
|
build-stubbed |
initialize-with |
stub (adapter) |
after stub |
— |
attributes-for |
(bypassed — returns the attribute hash directly) |