Skip to content

Commit

Permalink
Expanded hooks a little bit (#179)
Browse files Browse the repository at this point in the history
* Expanded hooks a little bit

* Improved consistancy for event descriptions

* Renamed some of the hooks

* Make PHPStan happy
  • Loading branch information
BelleNottelling authored Nov 4, 2024
1 parent efd5b2f commit e5b3f05
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/AntCMS/AntCMS.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function renderPage(?string $page = null): string
$this->renderException("404");
}

HookController::fire('contentHit', ['contentUri' => $page]);
HookController::fire('onAfterContentHit', ['contentUri' => $page]);

$themeConfig = self::getThemeConfig();
$params = [
Expand Down
2 changes: 1 addition & 1 deletion src/AntCMS/AntYaml.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static function saveFile(string $path, array $data): bool
}

/**
* Parses a string containing YAML data and returns the content as an array.
* Parses a string containing YAML data and returns the content as an array.
* @return mixed[]
*/
public static function parseYaml(string $yaml): array
Expand Down
6 changes: 3 additions & 3 deletions src/AntCMS/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private function getApiCallData(string $plugin, string $method): array
{
// Some needed variable setup
$url = rtrim(Flight::request()->url, '/');
if($_GET !== []) {
if ($_GET !== []) {
$query = '?' . http_build_query($_GET);
$url = str_replace($query, '', $url);
}
Expand Down Expand Up @@ -91,7 +91,7 @@ private function call(string $type, string $plugin, string $method): void
}

$hookData = ['plugin' => ucfirst($plugin), 'method' => $method];
HookController::fire('beforeApiCalled', $hookData);
HookController::fire('onBeforeApiCalled', $hookData);

// Sanity checks passed, now actually process the request
try {
Expand All @@ -108,7 +108,7 @@ private function call(string $type, string $plugin, string $method): void
}

$hookData['response'] = $response;
HookController::fire('afterApiCalled', $hookData);
HookController::fire('onAfterApiCalled', $hookData);

$this->sendResponse($response);
}
Expand Down
2 changes: 1 addition & 1 deletion src/AntCMS/ApiResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class ApiResponse
{
public function __construct(private mixed $result, private readonly bool $error = false, private readonly int $code = 200, private string $message = '')
public function __construct(private readonly mixed $result, private readonly bool $error = false, private readonly int $code = 200, private readonly string $message = '')
{
}

Expand Down
12 changes: 6 additions & 6 deletions src/AntCMS/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class Cache

/**
* Configures the cache system by selecting and prioritizing specific cache adapters.
*
*
* The `$allowed` array specifies which cache types to enable. Available options are 'apcu', 'php_file', and 'filesystem'.
*
*
* @param string[] $allowed An array of allowed cache adapter names.
*/
public static function setup(array $allowed = []): void
Expand Down Expand Up @@ -49,13 +49,13 @@ public static function setup(array $allowed = []): void

/**
* Retrieves a value from the cache.
*
*
* If the value is not found in the cache, it executes the provided callable and stores the result for future retrieval.
*
*
* @param string $key The unique identifier for the cached value.
* @param callable|CallbackInterface $callable A function that returns the value to be cached.
* @param ?float $beta (Optional) Controls the cache update strategy. See Symfony documentation for details.
* @param ?mixed[] &$metadata (Optional) Stores metadata about the cached item.
* @param ?mixed[] &$metadata (Optional) Stores metadata about the cached item.
* @return mixed The cached value or the result of the callable if it's not found.
*/
public static function get(string $key, callable|CallbackInterface $callable, ?float $beta = null, ?array &$metadata = []): mixed
Expand All @@ -65,7 +65,7 @@ public static function get(string $key, callable|CallbackInterface $callable, ?f

/**
* Prunes the cache. This removes stale entries that are no longer needed.
*
*
* @return bool True if any items were pruned, false otherwise.
*/
public static function prune(): bool
Expand Down
38 changes: 36 additions & 2 deletions src/AntCMS/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ class Event
private int $paramUpdateCount = 0;
private int $paramReadCount = 0;
private int $lastCallback = 0;
private bool $defaultPrevented = false;

/**
* @param string $associatedHook The hook that this event is associated with. Hook must exist.
*
* @param mixed[] $parameters
*/
public function __construct(string $associatedHook, private array $parameters, private readonly int $totalCallbacks)
public function __construct(string $associatedHook, private array $parameters, private readonly int $totalCallbacks, private readonly bool $preventable)
{
if (!HookController::isRegistered($associatedHook)) {
throw new \Exception("Hook $associatedHook is not registered!");
Expand Down Expand Up @@ -127,7 +128,7 @@ public function setParameters(array $parameters): Event
}

/**
* Returns the number of times the event parameters were read from
* Returns the number of times the event parameters were read from.
*/
public function getReadCount(): int
{
Expand All @@ -141,4 +142,37 @@ public function getUpdateCount(): int
{
return $this->paramUpdateCount;
}

/**
* Indicates if the default behavior for an event is preventable.
*/
public function isDefaultPreventable(): bool
{
return $this->preventable;
}

/**
* Indicates if the default behavior for an event is prevented.
*/
public function isDefaultPrevented(): bool
{
return $this->defaultPrevented;
}

/**
* Sets a flag for the default behavior of this event to be prevented.
* Not all events can be prevented. Triggers a non-fatal error if the event's default behavior is not preventable.
*
* @return Event
*/
public function preventDefault(): Event
{
if (!$this->isDefaultPreventable()) {
trigger_error("The default behavior for the `$this->associatedHook` hook cannot be prevented.");
} else {
$this->defaultPrevented = true;
}

return $this;
}
}
5 changes: 3 additions & 2 deletions src/AntCMS/Hook.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ class Hook
*
* @param string $name The name of the hook
* @param string $description A description of this hook
* @param bool $isDefaultPreventable Marks if the default behavior for a hook can be prevented.
*/
public function __construct(string $name, public string $description)
public function __construct(string $name, public string $description, private readonly bool $isDefaultPreventable = false)
{
if (preg_match('/^\w+$/', $name) === 0 || preg_match('/^\w+$/', $name) === false) {
throw new \Exception("The hook name '$name' is invalid. Only a-z A-Z, 0-9, and _ are allowed to be in the hook name.");
Expand All @@ -40,7 +41,7 @@ public function fire(array $params): Event
$this->timesFired++;

// Create the new event object with the originally provided parameters
$event = new Event($this->name, $params, $this->registeredCallbacks);
$event = new Event($this->name, $params, $this->registeredCallbacks, $this->isDefaultPreventable);

// Then fire each of the callbacks and update the event instance from each one.
foreach ($this->callbacks as $callback) {
Expand Down
8 changes: 4 additions & 4 deletions src/AntCMS/HookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static function isRegistered(string $name): bool
return array_key_exists($name, self::$hooks);
}

public static function registerHook(string $name, string $description = ''): bool
public static function registerHook(string $name, string $description = '', bool $isDefaultPreventable = false): bool
{
if (self::isRegistered($name)) {
if ($description !== '') {
Expand All @@ -29,7 +29,7 @@ public static function registerHook(string $name, string $description = ''): boo
return true;
}

self::$hooks[$name] = new Hook($name, $description);
self::$hooks[$name] = new Hook($name, $description, $isDefaultPreventable);
return true;
}

Expand All @@ -42,9 +42,9 @@ public static function registerCallback(string $name, callable $callback): void
}

/**
* @param mixed[] $params
* @param mixed[] $params (Optional)
*/
public static function fire(string $name, array $params): Event
public static function fire(string $name, array $params = []): Event
{
if (self::isRegistered($name)) {
return self::$hooks[$name]->fire($params);
Expand Down
4 changes: 2 additions & 2 deletions src/AntCMS/Pages.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ private static function buildList(string $path = PATH_CONTENT): array
if (isset($directoryMeta['pageOrder'][$a]) && isset($directoryMeta['pageOrder'][$b])) {
return $directoryMeta['pageOrder'][$a] > $directoryMeta['pageOrder'][$b] ? 1 : -1;
}
if(isset($directoryMeta['pageOrder'][$a]) && !isset($directoryMeta['pageOrder'][$b])) {
if (isset($directoryMeta['pageOrder'][$a]) && !isset($directoryMeta['pageOrder'][$b])) {
return -1;
}
if(!isset($directoryMeta['pageOrder'][$a]) && isset($directoryMeta['pageOrder'][$b])) {
if (!isset($directoryMeta['pageOrder'][$a]) && isset($directoryMeta['pageOrder'][$b])) {
return 1;
}
// Ensure index items come first
Expand Down
2 changes: 2 additions & 0 deletions src/AntCMS/PluginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public static function init(): void
Twig::addLoaderPath($templateDir);
}
}

HookController::fire('onAfterPluginsInit');
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/AntCMS/Tools.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace AntCMS;

use Flight;
use HostByBelle\CompressionBuffer;
use Symfony\Contracts\Cache\ItemInterface;

Expand Down Expand Up @@ -257,7 +258,7 @@ public static function getPerformanceMetrics(): array
];
}

private static function createDebugLogLine(string $wording, bool|string $value): string
private static function createDebugLogLine(string $wording, bool|string|int $value): string
{
if (is_bool($value)) {
$value = $value ? "enabled" : "disabled";
Expand Down Expand Up @@ -291,6 +292,7 @@ public static function buildDebugInfo(): string
$result .= self::createDebugLogLine('This page was compressed with', $method);
}

$result .= self::createDebugLogLine('Page output size', Flight::response()->getContentLength());
$result .= self::createDebugLogLine('Asset compression', COMPRESS_TEXT_ASSETS);
$result .= self::createDebugLogLine('Image compression', COMPRESS_IMAGES);
$result .= self::createDebugLogLine('PHP version', PHP_VERSION);
Expand Down
1 change: 0 additions & 1 deletion src/Plugins/Robotstxt/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use AntCMS\Config;
use AntCMS\PluginController;
use AntCMS\Tools;

use Flight;

class Controller extends AbstractPlugin
Expand Down
25 changes: 19 additions & 6 deletions src/Plugins/System/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace AntCMS\Plugins\System;

use AntCMS\AbstractPlugin;
use AntCMS\AntCMS;
use AntCMS\HookController;

class Controller extends AbstractPlugin
Expand All @@ -11,13 +12,15 @@ class Controller extends AbstractPlugin
* @var array<string, string>
*/
private array $hooks = [
'contentHit' => 'This is fired when markdown content is accessed. The URI will be passed in the data.',
'performanceMetricsBuilt' => 'When fired, this event contains all performance metrics AntCMS was able to collect on a request. These are more complete & accurate than the metrics shown on the bottom of the screen.',
'beforeApiCalled' => 'This event is fired before an API endpoint is called',
'afterApiCalled' => 'This event is fired after an API endpoint is called and the response is available',
'onAfterContentHit' => 'This is fired when markdown content is accessed. The URI will be passed in the data.',
'onAfterPerformanceMetricsBuilt' => 'When fired, this event contains all performance metrics AntCMS was able to collect on a request. These are more complete & accurate than the metrics shown on the bottom of the screen.',
'onBeforeApiCalled' => 'This event is fired before an API endpoint is called.',
'onAfterApiCalled' => 'This event is fired after an API endpoint is called and the response is available.',
'onHookFireComplete' => 'This event is fired when others have completed. The data provided will include the hook name, timing data, and parameter read / update statistics.',
'onBeforeMarkdownParsed' => 'This event is fired before markdown is converted, allowing for pre-processing before the markdown is run through the parser',
'onAfterMarkdownParsed' => 'This is fired after markdown is converted, allowing you to modify generated markdown content',
'onBeforeMarkdownParsed' => 'This event is fired before markdown is converted, allowing for pre-processing before the markdown is run through the parser.',
'onAfterMarkdownParsed' => 'This is fired after markdown is converted, allowing you to modify generated markdown content.',
'onAfterPluginsInit' => 'This event is fired after all plugins have been initialized.',
'onBeforeOutputFlushed' => 'This event is fired right before the generated response is finalized (compressed) and sent to the browser. No later chances to modify the output buffer exist.',
];

public function __construct()
Expand All @@ -27,6 +30,16 @@ public function __construct()
HookController::registerHook($name, $description);
}

HookController::registerCallback('onBeforeOutputFlushed', $this->appendDebugInfo(...));

$this->addDisallow('/api/*');
}

private function appendDebugInfo(\AntCMS\Event $event): \AntCMS\Event
{
$params = $event->getParameters();
$params['output'] = str_replace('<!--AntCMS-Debug-->', \AntCMS\Tools::buildDebugInfo(), $params['output'] ?? '');
$event->setParameters($params);
return $event;
}
}
9 changes: 6 additions & 3 deletions src/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

$AntCMS = new AntCMS();

// Add a response body callback to display debug info
Flight::response()->addResponseBodyCallback(fn ($body): string => str_replace('<!--AntCMS-Debug-->', Tools::buildDebugInfo(), $body));
// Use hooks to perform any final changes to the output buffer before compressing and sending it
Flight::response()->addResponseBodyCallback(function (string $body): string {
$event = HookController::fire('onBeforeOutputFlushed', ['output' => $body]);
return $event->getParameters()['output'];
});

// Setup CompressionBuffer & enable it in Flight
CompressionBuffer::setUp(true, false, [Flight::response(), 'header']);
Expand All @@ -27,7 +30,7 @@
}

Flight::response()->addResponseBodyCallback(function ($body) {
HookController::fire('performanceMetricsBuilt', tools::getPerformanceMetrics());
HookController::fire('onAfterPerformanceMetricsBuilt', tools::getPerformanceMetrics());
return $body;
});

Expand Down

0 comments on commit e5b3f05

Please sign in to comment.