This hook is called after the DB commits changes (for certain objects).
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_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_postwill fire immediately after each
hook_civicrm_postCommitwill fire after the
- If an extension listens to
hook_civicrm_postand 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_postCommitand 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
- 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
postCommit is essentially the same.
What if I have a critical task that is also unreliable?
Consider using a queue pattern. For example:
hook_civicrm_post, add the task to the SQL-backed 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.
hook_civicrm_postCommit($op, $objectName, $objectId, &$objectRef)
$op- the operation being performed with CiviCRM object (e.g.
$objectName- the type of object being updated (e.g.
$objectId- the unique identifier for the object.
tagIDin case of
$objectRef- the reference to the object if available. For case of
EntityTagit is an array of (
For full details about these parameters, see hook_civicrm_post for full details.