Environment:
bolt/core: 6.1.3
doctrine/dbal: 4.4.3 (required by bolt/core as ^4.0)
- PHP: 8.3.31
Description
Bolt\Event\Subscriber\TimedPublishSubscriber::onKernelRequest() is supposed to run on every kernel.request and automatically:
- flip
status: timed → published once published_at has passed, and
- flip
status: published → held once depublished_at has passed.
On a project using doctrine/dbal: ^4.0 (as required by bolt/core's own composer.json), this never works, for three separate reasons, all hidden by the method's blanket catch (Throwable) { /* Fail silently */ } with no logging:
- It calls
$conn->executeUpdate(...). Connection::executeUpdate() was removed in doctrine/dbal 4.0 (only executeStatement() remains), so every call throws:
Error: Call to undefined method Doctrine\DBAL\Connection::executeUpdate()
- Even after switching to
executeStatement(), the parameter array uses colon-prefixed keys ([':now' => $now]) instead of plain keys (['now' => $now]), which throws:
Doctrine\DBAL\ArrayParameters\Exception\MissingNamedParameter: Named parameter "now" does not have a bound value.
- Once both of those are fixed, binding still fails because
$now is a Carbon/DateTime object passed without an explicit DBAL type, throwing:
Error: Object of class DateTime could not be converted to string
This requires an explicit ['now' => Doctrine\DBAL\Types\Types::DATETIME_MUTABLE] type array.
Impact
Content with a "Depublish date" in the past keeps showing on the frontend indefinitely (status stays published), since nothing ever flips it to held. This affects every content type, not just one — it's a core scheduling mechanism that is completely inert on any project using doctrine/dbal 4.x.
Steps to reproduce
- Install
bolt/core 6.1.3 with doctrine/dbal ^4.0.
- Set any content record to
status = published with a depublished_at in the past.
- Visit any page (triggers
kernel.request).
- Observe the record's status is still
published (expected: held).
- Query/log the raw SQL — the
UPDATE from TimedPublishSubscriber never even appears, because it errors out silently before executing.
Suggested fix (verified working)
// src/Event/Subscriber/TimedPublishSubscriber.php
use Doctrine\DBAL\Types\Types;
// ...
try {
$conn->executeStatement($queryPublish, ['now' => $now], ['now' => Types::DATETIME_MUTABLE]);
$conn->executeStatement($queryDepublish, ['now' => $now], ['now' => Types::DATETIME_MUTABLE]);
} catch (Throwable) {
// Fail silently, output user-friendly exception elsewhere.
}
As a secondary concern, it may be worth logging the caught Throwable (even at debug level) instead of swallowing it completely, since that's what made this bug invisible for so long.
Environment:
bolt/core: 6.1.3doctrine/dbal: 4.4.3 (required by bolt/core as^4.0)Description
Bolt\Event\Subscriber\TimedPublishSubscriber::onKernelRequest()is supposed to run on everykernel.requestand automatically:status: timed→publishedoncepublished_athas passed, andstatus: published→heldoncedepublished_athas passed.On a project using
doctrine/dbal: ^4.0(as required bybolt/core's owncomposer.json), this never works, for three separate reasons, all hidden by the method's blanketcatch (Throwable) { /* Fail silently */ }with no logging:$conn->executeUpdate(...).Connection::executeUpdate()was removed indoctrine/dbal4.0 (onlyexecuteStatement()remains), so every call throws:executeStatement(), the parameter array uses colon-prefixed keys ([':now' => $now]) instead of plain keys (['now' => $now]), which throws:$nowis aCarbon/DateTimeobject passed without an explicit DBAL type, throwing:['now' => Doctrine\DBAL\Types\Types::DATETIME_MUTABLE]type array.Impact
Content with a "Depublish date" in the past keeps showing on the frontend indefinitely (status stays
published), since nothing ever flips it toheld. This affects every content type, not just one — it's a core scheduling mechanism that is completely inert on any project using doctrine/dbal 4.x.Steps to reproduce
bolt/core6.1.3 withdoctrine/dbal ^4.0.status = publishedwith adepublished_atin the past.kernel.request).published(expected:held).UPDATEfromTimedPublishSubscribernever even appears, because it errors out silently before executing.Suggested fix (verified working)
As a secondary concern, it may be worth logging the caught
Throwable(even at debug level) instead of swallowing it completely, since that's what made this bug invisible for so long.