hook_civicrm_postCommit¶
Summary¶
This hook is called after the DB commits changes (for certain objects).
Notes¶
hook_civicrm_post
and hook_civicrm_postCommit
are nearly identical. They differ in timing and transaction management.
hook_civicrm_post
: Runs immediately after the change is sent to the DB. If there's a SQL transaction, then it runs within the transaction.hook_civicrm_postCommit
: Runs after the change is committed to the DB. It always runs outside of any SQL transactions.
For example, suppose a user submits an "Event Registration" form. Recording the registration may require writing records in
multiple tables (civicrm_contact
, civicrm_participant
, and civicrm_log
). These writes are performed atomically - grouped
into a database transaction. Loosely, the operation sends these SQL statements:
BEGIN;
INSERT INTO civicrm_contact (...) VALUES (...);
INSERT INTO civicrm_log (...) VALUES (...);
INSERT INTO civicrm_participant (...) VALUES (...);
INSERT INTO civicrm_log (...) VALUES (...);
COMMIT;
Now let's compare the hooks:
hook_civicrm_post
will fire immediately after eachINSERT
(before theCOMMIT
).hook_civicrm_postCommit
will fire after theCOMMIT
.- If an extension listens to
hook_civicrm_post
and throws an exception, then it can interrupt the transaction: the user gets an error screen, the operation is rolled back, and the user needs to retry later. - If an extension listens to
hook_civicrm_postCommit
and throws an exception, it does not affect the main operation - because that has already committed. The user may get an error screen, but there's no need to resubmit.
The choice between hooks comes down to how critical and how reliable the work is (from a busines point of view). For example:
- If you're using a hook to play a chime on the speaker in the office whenever someone registers, then it's probably not critical (because
you'd want the registration even if the chime is unplayable), and it's also rather unreliable (because a coworker might get frustrated by all
the chimes and unplug the whole speaker apparatus). Use
postCommit
. - If you're working in a regulated domain and using a hook to create a detailed audit trail in another table (
civicrm_log_plus_plus
), then it is critical (because regulators will complain if the records are missing) and fairly reliable (because it's in the same database as all the other records).
What if the use-case does not involve an explicit transaction?
If there is no active SQL transaction, then the DB is in auto-commit mode. The timing of post
and postCommit
is essentially the same.
What if I have a critical task that is also unreliable?
Consider using a queue pattern. For example:
- During
hook_civicrm_post
, add the task to the SQL-backed queue (civicrm_queue
). - The task will be queued if (and only if) the main operation commits.
- In the queue worker, look out for errors and arrange for retries.
Definition¶
hook_civicrm_postCommit($op, $objectName, $objectId, &$objectRef)
Parameters¶
$op
- the operation being performed with CiviCRM object (e.g.create
oredit
)$objectName
- the type of object being updated (e.g.Activity
or `Contact)$objectId
- the unique identifier for the object.tagID
in case ofEntityTag
$objectRef
- the reference to the object if available. For case ofEntityTag
it is an array of (entityTable
,entityIDs
)
For full details about these parameters, see hook_civicrm_post for full details.
Returns¶
- None