Store that collects notifications during a request and dispatches them all on shutdown via the InternalNotificationDispatcher. Should be accessed from the container (wc_get_container) to ensure store is shared by all usage.
Notifications are keyed by {type}_{resource_id} (with blog ID from get_current_blog_id()) to prevent duplicates within a single request.
No Hooks.
Usage
$PendingNotificationStore = new PendingNotificationStore();
// use class methods
class PendingNotificationStore {
/**
* Whether the store is enabled and accepting notifications.
*
* @var bool
*/
private bool $enabled = false;
/**
* The dispatcher that will be used to send notifications on shutdown.
*
* @var InternalNotificationDispatcher
*
* @phpstan-ignore property.onlyWritten (this will be read when the loopback
* controller is added)
*/
private InternalNotificationDispatcher $dispatcher;
/**
* Pending notifications keyed by identifier.
*
* @var array<string, Notification>
*/
private array $pending = array();
/**
* Whether the shutdown hook has been registered.
*
* @var bool
*/
private bool $shutdown_registered = false;
/**
* Initialize dependencies.
*
* @internal
*
* @param InternalNotificationDispatcher $dispatcher The dispatcher to use on shutdown.
*
* @since 10.7.0
*/
final public function init( InternalNotificationDispatcher $dispatcher ): void {
$this->dispatcher = $dispatcher;
}
/**
* Enables the store so it accepts notifications.
*
* Called from PushNotifications::on_init() after enablement checks pass.
*
* @return void
*
* @since 10.7.0
*/
public function register(): void {
$this->enabled = true;
}
/**
* Adds a notification to the pending store.
*
* Duplicate notifications (same type and resource ID) within a single
* request are silently ignored. The shutdown hook is registered on the
* first call.
*
* @param Notification $notification The notification to add.
* @return void
*
* @since 10.7.0
*/
public function add( Notification $notification ): void {
if ( ! $this->enabled ) {
return;
}
$key = $notification->get_identifier();
if ( isset( $this->pending[ $key ] ) ) {
return;
}
$this->pending[ $key ] = $notification;
if ( ! $this->shutdown_registered ) {
add_action( 'shutdown', array( $this, 'dispatch_all' ) );
$this->shutdown_registered = true;
}
}
/**
* Dispatches all pending notifications via the loopback endpoint.
*
* Called on shutdown. Sends all pending notifications through the
* InternalNotificationDispatcher, then clears the store.
*
* @return void
*
* @since 10.7.0
*/
public function dispatch_all(): void {
if ( empty( $this->pending ) ) {
return;
}
/**
* Fires when pending push notifications are ready to be dispatched.
*
* @param Notification[] $notifications The notifications to dispatch.
*
* @since 10.7.0
*
* The call to dispatch the notifications will go here when the
* receiving controller has been added.
*/
/**
* Store is single-use per request lifecycle, so disable it and clear
* pending notifications.
*/
$this->enabled = false;
$this->pending = array();
}
/**
* Returns the number of pending notifications.
*
* @return int
*
* @since 10.7.0
*/
public function count(): int {
return count( $this->pending );
}
/**
* Returns all pending notifications.
*
* @return Notification[]
*
* @since 10.7.0
*/
public function get_all(): array {
return array_values( $this->pending );
}
}