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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ The format is based on Keep a Changelog.
## [3.1.0] - TBD

### Added
- Added boot stage lifecycle events: stages may declare `BEFORE`/`AFTER` event names and `BootPipeline` dispatches them with the `AppContext` as a named payload. The environment, config, error handler, HTTP, and modules stages declare `boot.<stage>.before` and `boot.<stage>.after` (#536)
- Added adapter-based Lang provider support with `DeepL` and `Google Translate` adapters plus shared remote request/caching infrastructure (#533)

### Changed
- **BREAKING:** Replaced the `Quantum\Hook` package with `Quantum\Event` (#536):
- `hook()` is now `event()`; `on()` and `fire()` are now `listen()` and `dispatch()`, and no aliases remain. Listeners receive one named payload array, which is empty when none is given.
- Event names no longer need to be registered, so `shared/config/hooks.php` is no longer read; dispatching a name without listeners does nothing and an empty name throws `EventException`.
- Listeners stay registered after `dispatch()` instead of being removed after the first call.
- Listeners can be registered from app helper files, which load before config and before any boot event.
- Removed the unused `hooks_dir()` helper and renamed the debugger tab constant `Debugger::HOOKS` to `Debugger::EVENTS`; the debugbar tab is now `events` and lists only events that have listeners.
- **BREAKING:** Removed `Quantum\Loader` and moved its responsibilities to their owning packages (#535):
- Moved `Setup` to `Quantum\Config\Setup`; required config failures now use `ConfigException`, and optional imports use `Config::importIfExists()`.
- Config paths resolve from the application base directory, independent of the process working directory.
Expand Down
19 changes: 19 additions & 0 deletions src/App/BootPipeline.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,26 @@ public function __construct(array $stages = [])
public function run(AppContext $context): void
{
foreach ($this->stages as $stage) {
$this->dispatchStageEvent($stage, 'BEFORE', $context);

$stage->process($context);

$this->dispatchStageEvent($stage, 'AFTER', $context);
}
}

/**
* Dispatches the event a stage declares for the given point, if any.
* Skipped while the event() helper is not loaded yet, since nothing can listen then.
*/
private function dispatchStageEvent(BootStageInterface $stage, string $point, AppContext $context): void
{
$constant = $stage::class . '::' . $point;

if (!defined($constant) || !function_exists('event')) {
return;
}

event()->dispatch((string) constant($constant), ['context' => $context]);
}
}
8 changes: 0 additions & 8 deletions src/App/Helpers/dir.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,6 @@ function assets_dir(): string
return public_dir() . DS . 'assets';
}

/**
* Gets hooks directory
*/
function hooks_dir(): string
{
return App::getBaseDir() . DS . 'hooks';
}

/**
* Recursively deletes folder
*/
Expand Down
9 changes: 4 additions & 5 deletions src/App/Stages/InitHttpStage.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@
namespace Quantum\App\Stages;

use Quantum\App\Contracts\BootStageInterface;
use Quantum\Di\Exceptions\DiException;
use Quantum\App\AppContext;
use Quantum\Http\Response;
use Quantum\Http\Request;
use ReflectionException;
use Quantum\Di\Di;

/**
Expand All @@ -24,9 +22,10 @@
*/
class InitHttpStage implements BootStageInterface
{
/**
* @throws DiException|ReflectionException
*/
public const BEFORE = 'boot.http.before';

public const AFTER = 'boot.http.after';

public function process(AppContext $context): void
{
if (!Di::isRegistered(Request::class)) {
Expand Down
4 changes: 4 additions & 0 deletions src/App/Stages/LoadAppConfigStage.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
*/
class LoadAppConfigStage implements BootStageInterface
{
public const BEFORE = 'boot.config.before';

public const AFTER = 'boot.config.after';

/**
* @throws ConfigException|DiException|ReflectionException
*/
Expand Down
4 changes: 4 additions & 0 deletions src/App/Stages/LoadEnvironmentStage.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
*/
class LoadEnvironmentStage implements BootStageInterface
{
public const BEFORE = 'boot.environment.before';

public const AFTER = 'boot.environment.after';

/**
* @throws EnvException|DiException|BaseException
*/
Expand Down
4 changes: 4 additions & 0 deletions src/App/Stages/LoadModulesStage.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
*/
class LoadModulesStage implements BootStageInterface
{
public const BEFORE = 'boot.modules.before';

public const AFTER = 'boot.modules.after';

/**
* @throws ModuleException|RouteException|DiException|ReflectionException
*/
Expand Down
4 changes: 4 additions & 0 deletions src/App/Stages/SetupErrorHandlerStage.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
*/
class SetupErrorHandlerStage implements BootStageInterface
{
public const BEFORE = 'boot.error_handler.before';

public const AFTER = 'boot.error_handler.after';

/**
* @throws ConfigException|DiException|BaseException|ReflectionException
*/
Expand Down
2 changes: 1 addition & 1 deletion src/App/Traits/WebAppTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ private function logDebugInfo(): void
$debugbar = debugbar();

if ($debugbar->isEnabled()) {
$debugbar->addToStoreCell(Debugger::HOOKS, 'info', hook()->getRegistered());
$debugbar->addToStoreCell(Debugger::EVENTS, 'info', event()->getRegistered());
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/Debugger/Debugger.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class Debugger
public const ROUTES = 'routes';

/**
* Hooks tab
* Events tab
*/
public const HOOKS = 'hooks';
public const EVENTS = 'events';

/**
* Mails tab
Expand Down Expand Up @@ -104,7 +104,7 @@ public function initStore(): void
Debugger::MESSAGES,
Debugger::QUERIES,
Debugger::ROUTES,
Debugger::HOOKS,
Debugger::EVENTS,
Debugger::MAILS,
]);
}
Expand Down Expand Up @@ -151,7 +151,7 @@ public function render(): string
return '';
}

foreach ([self::MESSAGES, self::QUERIES, self::ROUTES, self::HOOKS, self::MAILS] as $tab) {
foreach ([self::MESSAGES, self::QUERIES, self::ROUTES, self::EVENTS, self::MAILS] as $tab) {
$this->createTab($tab);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@
* @link https://quantumphp.io
*/

namespace Quantum\Hook\Enums;
namespace Quantum\Event\Enums;

use Quantum\App\Enums\ExceptionMessages as BaseExceptionMessages;

/**
* Class ExceptionMessages
* @package Quantum\Hook
* @package Quantum\Event
*/
final class ExceptionMessages extends BaseExceptionMessages
{
public const DUPLICATE_HOOK_NAME = 'The Hook `{%1}` already registered.';

public const UNREGISTERED_HOOK_NAME = 'The Hook `{%1}` was not registered.';
public const EMPTY_EVENT_NAME = 'The event name must not be empty.';
}
70 changes: 70 additions & 0 deletions src/Event/EventManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

declare(strict_types=1);

/**
* Quantum PHP Framework
* An open-source software development framework for PHP
* @link https://quantumphp.io
*/

namespace Quantum\Event;

use Quantum\Event\Exceptions\EventException;

/**
* Class EventManager
* @package Quantum\Event
*/
class EventManager
{
/**
* Registered listeners store
* @var array<string, array<int, callable>>
*/
private array $listeners = [];

/**
* Adds a listener for a given event
* @throws EventException
*/
public function listen(string $name, callable $listener): void
{
$this->assertName($name);

$this->listeners[$name][] = $listener;
}

/**
* Dispatches the event to its listeners in registration order
* @param array<string, mixed> $payload
* @throws EventException
*/
public function dispatch(string $name, array $payload = []): void
{
$this->assertName($name);

foreach ($this->listeners[$name] ?? [] as $listener) {
$listener($payload);
}
}

/**
* Gets all registered listeners by event name
* @return array<string, array<int, callable>>
*/
public function getRegistered(): array
{
return $this->listeners;
}

/**
* @throws EventException
*/
private function assertName(string $name): void
{
if ($name === '') {
throw EventException::emptyEventName();
}
}
}
29 changes: 29 additions & 0 deletions src/Event/Exceptions/EventException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

/**
* Quantum PHP Framework
* An open-source software development framework for PHP
* @link https://quantumphp.io
*/

namespace Quantum\Event\Exceptions;

use Quantum\Event\Enums\ExceptionMessages;
use Quantum\App\Exceptions\BaseException;

/**
* Class EventException
* @package Quantum\Event
*/
class EventException extends BaseException
{
public static function emptyEventName(): self
{
return new self(
ExceptionMessages::EMPTY_EVENT_NAME,
E_ERROR
);
}
}
22 changes: 22 additions & 0 deletions src/Event/Helpers/event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/**
* Quantum PHP Framework
* An open-source software development framework for PHP
* @link https://quantumphp.io
*/

use Quantum\Event\EventManager;
use Quantum\Di\Di;

/**
* Gets the EventManager instance
*/
function event(): EventManager
{
if (!Di::isRegistered(EventManager::class)) {
Di::register(EventManager::class);
}

return Di::get(EventManager::class);
}
37 changes: 0 additions & 37 deletions src/Hook/Exceptions/HookException.php

This file was deleted.

24 changes: 0 additions & 24 deletions src/Hook/Helpers/hook.php

This file was deleted.

Loading
Loading