Skip to content
Merged
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
6 changes: 3 additions & 3 deletions src/Phaseolies/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Database
/**
* Signals waiting for a transaction to settle, per connection and nesting level
*
* @var array<string, array<int, array<int, array{0: \Phaseolies\Signals\SignalBus, 1: object}>>>
* @var array<string, array<int, array<int, array{0: \Phaseolies\Signals\Contracts\SignalBusInterface, 1: object}>>>
*/
protected static $pendingSignals = [];

Expand Down Expand Up @@ -245,12 +245,12 @@ public function rollBack(): void
/**
* Hold a signal until the open transaction on a connection settles
*
* @param \Phaseolies\Signals\SignalBus $bus
* @param \Phaseolies\Signals\Contracts\SignalBusInterface $bus
* @param object $signal
* @param string|null $connection
* @return bool
*/
public static function stageSignal(\Phaseolies\Signals\SignalBus $bus, object $signal, ?string $connection = null): bool
public static function stageSignal(\Phaseolies\Signals\Contracts\SignalBusInterface $bus, object $signal, ?string $connection = null): bool
{
$connection = $connection ?: config('database.default');
$level = static::$transactions[$connection] ?? 0;
Expand Down
2 changes: 1 addition & 1 deletion src/Phaseolies/Helpers/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ function defer(callable $callback)
* Get the signal bus, or emit a signal when one is given
*
* @param object|null $signal
* @return \Phaseolies\Signals\SignalBus|void
* @return \Phaseolies\Signals\Contracts\SignalBusInterface|void
*/
function signal(?object $signal = null)
{
Expand Down
7 changes: 5 additions & 2 deletions src/Phaseolies/Launchers/FacadeLauncher.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Phaseolies\Support\Storage\StorageFileService;
use Phaseolies\Support\Storage\Contracts\StorageInterface;
use Phaseolies\Signals\SignalBus;
use Phaseolies\Signals\Contracts\SignalBusInterface;
use Phaseolies\Support\Session;
use Phaseolies\Session\Contracts\SessionInterface;
use Phaseolies\Support\Mail\MailService;
Expand Down Expand Up @@ -131,9 +132,11 @@ public function register()
// This handles db related jobs
$this->app->singleton('db', Database::class);

// Bind the 'signal' service to a singleton instance of the SignalBus class.
// Bind the signal bus contract to a singleton implementation and
// retain the existing 'signal' service name as an alias.
// This handles signals that can wait for a database transaction to settle
$this->app->singleton('signal', SignalBus::class);
$this->app->singleton(SignalBusInterface::class, SignalBus::class);
$this->app->alias(SignalBusInterface::class, 'signal');

// Bind the 'app' service to a singleton instance of the Application class.
// This handles app related jobs
Expand Down
75 changes: 75 additions & 0 deletions src/Phaseolies/Signals/Contracts/SignalBusInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace Phaseolies\Signals\Contracts;

interface SignalBusInterface
{
/**
* Register a listener for a signal class or interface.
*
* @param string $signal
* @param callable|array|string $listener
* @param int $priority
* @return self
* @throws \InvalidArgumentException
*/
public function on(string $signal, callable|array|string $listener, int $priority = 0): self;

/**
* Remove every listener of a signal, or all listeners when none is given.
*
* @param string|null $signal
* @return self
*/
public function forget(?string $signal = null): self;

/**
* Determine if any listener would receive the given signal.
*
* @param object|string $signal
* @return bool
*/
public function hasListeners(object|string $signal): bool;

/**
* Emit a signal.
*
* @param object $signal
* @return void
*/
public function emit(object $signal): void;

/**
* Emit a signal right away, ignoring #[DeliverOnSettle] and any open transaction.
*
* @param object $signal
* @return void
*/
public function emitNow(object $signal): void;

/**
* Emit a signal once the open transaction on a connection settles.
*
* @param object $signal
* @param string|null $connection
* @return bool
*/
public function emitOnSettle(object $signal, ?string $connection = null): bool;

/**
* Deliver a signal whose transaction has just committed.
*
* @param object $signal
* @return void
* @internal Called by the database layer
*/
public function settle(object $signal): void;

/**
* Set a custom reporter for listener failures that happen after a commit.
*
* @param callable(\Throwable, object): void|null $reporter
* @return self
*/
public function reportFailuresUsing(?callable $reporter): self;
}
3 changes: 2 additions & 1 deletion src/Phaseolies/Signals/SignalBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

use Phaseolies\Database\Database;
use Phaseolies\Signals\Attributes\DeliverOnSettle;
use Phaseolies\Signals\Contracts\SignalBusInterface;

class SignalBus
class SignalBus implements SignalBusInterface
{
/**
* Registered listeners, keyed by signal class or interface name
Expand Down
8 changes: 4 additions & 4 deletions src/Phaseolies/Support/Facades/Signal.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
use Phaseolies\Facade\BaseFacade;

/**
* @method static \Phaseolies\Signals\SignalBus on(string $signal, callable|array|string $listener, int $priority = 0)
* @method static \Phaseolies\Signals\SignalBus forget(?string $signal = null)
* @method static \Phaseolies\Signals\Contracts\SignalBusInterface on(string $signal, callable|array|string $listener, int $priority = 0)
* @method static \Phaseolies\Signals\Contracts\SignalBusInterface forget(?string $signal = null)
* @method static bool hasListeners(object|string $signal)
* @method static void emit(object $signal)
* @method static void emitNow(object $signal)
* @method static bool emitOnSettle(object $signal, ?string $connection = null)
* @method static \Phaseolies\Signals\SignalBus reportFailuresUsing(?callable $reporter)
* @method static \Phaseolies\Signals\Contracts\SignalBusInterface reportFailuresUsing(?callable $reporter)
*
* @see \Phaseolies\Signals\SignalBus
* @see \Phaseolies\Signals\Contracts\SignalBusInterface
*/
class Signal extends BaseFacade
{
Expand Down
33 changes: 33 additions & 0 deletions tests/Signals/SignalBusTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
namespace Tests\Unit\Signals;

use PHPUnit\Framework\TestCase;
use Phaseolies\Application;
use Phaseolies\DI\Container;
use Phaseolies\Launchers\FacadeLauncher;
use Phaseolies\Signals\Contracts\SignalBusInterface;
use Phaseolies\Signals\SignalBus;
use ReflectionClass;

interface TracksOrders {}

Expand Down Expand Up @@ -39,6 +44,34 @@ protected function setUp(): void
InvokableListener::$seen = [];
}

public function testSignalBusConformsToTheContract(): void
{
$this->assertInstanceOf(SignalBusInterface::class, $this->bus);
}

public function testApplicationBindsTheSignalContractAndLegacyServiceNameToTheSameSingleton(): void
{
$app = $this->getMockBuilder(Application::class)->disableOriginalConstructor()->onlyMethods([])->getMock();
(new ReflectionClass(Container::class))->getConstructor()->invoke($app);
$previous = Container::getInstance();
Container::setInstance($app);
$originalAppUrl = getenv('APP_URL');

try {
putenv('APP_URL=http://localhost');
(new FacadeLauncher($app))->register();

$contract = $app->get(SignalBusInterface::class);

$this->assertInstanceOf(SignalBus::class, $contract);
$this->assertSame($contract, $app->get('signal'));
$this->assertSame($contract, signal());
} finally {
Container::setInstance($previous);
$originalAppUrl === false ? putenv('APP_URL') : putenv("APP_URL={$originalAppUrl}");
}
}

public function testHigherPriorityListenersRunFirst(): void
{
$order = [];
Expand Down
Loading