Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/en/appendices/5-4-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ version is reported as `unknown`), the header is omitted.
has changed from `select` to `subquery`. If you need the previous behavior,
explicitly set `'strategy' => 'select'` when defining associations.
See [Associations](../orm/associations#has-many-associations) for more details.
- `Model.afterSaveCommit` and `Model.afterDeleteCommit` events are now fired
when `save()` or `delete()` is called inside an outer transaction. Previously,
these events were silently suppressed. They are now deferred until the
outermost transaction commits, and discarded on rollback.
See [Table Objects](../orm/table-objects#aftersavecommit) for more details.

### Controller

Expand Down Expand Up @@ -99,6 +104,9 @@ version is reported as `unknown`), the header is omitted.
See [Query Builder](../orm/query-builder#advanced-conditions).
- Added `inOrNull()` and `notInOrNull()` methods for combining `IN` conditions with `IS NULL`.
- Added `isDistinctFrom()` and `isNotDistinctFrom()` methods for null-safe comparisons.
- Added `Connection::afterCommit()` to register callbacks that run after the
outermost transaction commits. Callbacks are discarded on rollback.
See [Database Basics](../orm/database-basics#aftercommit) for more details.
- Added `except()` and `exceptAll()` methods on `SelectQuery` for `EXCEPT`
and `EXCEPT ALL` set operations. `EXCEPT ALL` is supported on PostgreSQL
and recent MySQL/MariaDB versions; it is not supported on SQLite or SQL Server.
Expand Down
47 changes: 47 additions & 0 deletions docs/en/orm/database-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,53 @@ do the following:
- If the closure returns `false`, a rollback will be issued.
- If the closure executes successfully, the transaction will be committed.

### afterCommit

`method` Cake\\Database\\Connection::**afterCommit**(callable $callback): void

You can register callbacks to run after the outermost transaction commits using
``afterCommit()``. This is useful for deferring side effects like sending
emails, dispatching jobs, or invalidating caches until you know the data has
been persisted:

```php
$connection->begin();
$connection->execute('UPDATE articles SET published = ? WHERE id = ?', [true, 2]);
$connection->afterCommit(function () {
// Send notification email — only runs if the transaction commits.
$this->mailer->send('article-published');
});
$connection->commit(); // Callback fires here.
```

Callbacks are discarded if the transaction is rolled back. When nested
transactions are in use, callbacks registered at any depth are deferred until
the outermost transaction commits:

```php
$connection->begin();
$connection->afterCommit(function () {
// This fires after the outermost commit.
});

$connection->begin(); // Nested (savepoint)
$connection->afterCommit(function () {
// Also deferred to outermost commit.
});
$connection->commit(); // Releases savepoint — callbacks don't fire yet.

$connection->commit(); // Outermost commit — both callbacks fire now.
```

If ``afterCommit()`` is called when no transaction is active, the callback
executes immediately. This matches the semantics of the ORM's
``Model.afterSaveCommit`` event, which also fires immediately for non-atomic
saves.

::: info Added in version 5.4.0
`Connection::afterCommit()` was added.
:::

## Interacting with Statements

When using the lower level database API, you will often encounter statement
Expand Down
27 changes: 23 additions & 4 deletions docs/en/orm/table-objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,18 @@ The `Model.afterSave` event is fired after an entity is saved.
The `Model.afterSaveCommit` event is fired after the transaction in which the
save operation is wrapped has been committed. It's also triggered for non atomic
saves where database operations are implicitly committed. The event is triggered
only for the primary table on which `save()` is directly called. The event is
not triggered if a transaction is started before calling save.
only for the primary table on which `save()` is directly called.

When `save()` is called inside an outer transaction (e.g. one started with
`Connection::begin()`), the event is deferred until the outermost transaction
commits. If the outer transaction is rolled back, the event is discarded. This
ensures the event only fires after data has been persisted to the database.

::: info Changed in version 5.4.0
Previously, this event was not triggered if a transaction was started before
calling `save()`. It is now deferred and fires after the outermost
transaction commits.
:::

### beforeDelete

Expand All @@ -342,10 +352,19 @@ The `Model.afterDelete` event is fired after an entity has been deleted.
`method` Cake\\ORM\\Table::**afterDeleteCommit**(EventInterface $event, EntityInterface $entity, ArrayObject $options): void

The `Model.afterDeleteCommit` event is fired after the transaction in which the
delete operation is wrapped has been is committed. It's also triggered for non
delete operation is wrapped has been committed. It's also triggered for non
atomic deletes where database operations are implicitly committed. The event is
triggered only for the primary table on which `delete()` is directly called.
The event is not triggered if a transaction is started before calling delete.

When `delete()` is called inside an outer transaction, the event is deferred
until the outermost transaction commits. If the outer transaction is rolled
back, the event is discarded.

::: info Changed in version 5.4.0
Previously, this event was not triggered if a transaction was started before
calling `delete()`. It is now deferred and fires after the outermost
transaction commits.
:::

### Stopping Table Events

Expand Down