crash backup
Some checks failed
CI / general_module_workflow_php (push) Has been cancelled

This commit is contained in:
Dennis Eichhorn 2025-03-21 02:48:21 +00:00
parent a02ebcb17e
commit ade92f3735
11 changed files with 178 additions and 123 deletions

View File

@ -31,4 +31,6 @@ abstract class AssetType extends Enum
public const JS = 1; public const JS = 1;
public const JSLATE = 2; public const JSLATE = 2;
public const LINK = 3;
} }

View File

@ -165,14 +165,14 @@ final class EventManager implements \Countable
* @param string $id Sub-requirement for event (can be regex) * @param string $id Sub-requirement for event (can be regex)
* @param mixed $data Data to pass to the callback * @param mixed $data Data to pass to the callback
* *
* @return bool returns true on successfully triggering ANY event, false if NO event could be triggered which also includes sub-requirements missing * @return array
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function triggerSimilar(string $group, string $id = '', mixed $data = null) : bool public function triggerSimilar(string $group, string $id = '', mixed $data = null) : array
{ {
if (empty($this->callbacks)) { if (empty($this->callbacks)) {
return false; return [];
} }
$groupIsRegex = \str_starts_with($group, '/'); $groupIsRegex = \str_starts_with($group, '/');
@ -219,14 +219,14 @@ final class EventManager implements \Countable
$data['@triggerGroup'] ??= $group; $data['@triggerGroup'] ??= $group;
$triggerValue = false; $result = [];
foreach ($groups as $groupName => $ids) { foreach ($groups as $groupName => $ids) {
foreach ($ids as $id) { foreach ($ids as $id) {
$triggerValue = $this->trigger($groupName, $id, $data) || $triggerValue; \array_merge($result, $this->trigger($groupName, $id, $data));
} }
} }
return $triggerValue; return $result;
} }
/** /**
@ -236,14 +236,14 @@ final class EventManager implements \Countable
* @param string $id Sub-requirement for event * @param string $id Sub-requirement for event
* @param mixed $data Data to pass to the callback * @param mixed $data Data to pass to the callback
* *
* @return bool returns true on successfully triggering the event, false if the event couldn't be triggered which also includes sub-requirements missing * @return array
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function trigger(string $group, string $id = '', mixed $data = null) : bool public function trigger(string $group, string $id = '', mixed $data = null) : array
{ {
if (!isset($this->callbacks[$group])) { if (!isset($this->callbacks[$group])) {
return false; return [];
} }
if (isset($this->groups[$group])) { if (isset($this->groups[$group])) {
@ -251,9 +251,10 @@ final class EventManager implements \Countable
} }
if ($this->hasOutstanding($group)) { if ($this->hasOutstanding($group)) {
return false; return [];
} }
$result = [];
foreach ($this->callbacks[$group]['callbacks'] as $func) { foreach ($this->callbacks[$group]['callbacks'] as $func) {
if (\is_array($data)) { if (\is_array($data)) {
$data['@triggerGroup'] ??= $group; $data['@triggerGroup'] ??= $group;
@ -267,7 +268,7 @@ final class EventManager implements \Countable
$data['@triggerId'] = $id; $data['@triggerId'] = $id;
} }
$this->dispatcher->dispatch($func, ...\array_values($data)); \array_merge($result, $this->dispatcher->dispatch($func, ...\array_values($data)));
} }
if ($this->callbacks[$group]['remove']) { if ($this->callbacks[$group]['remove']) {
@ -276,7 +277,7 @@ final class EventManager implements \Countable
$this->reset($group); $this->reset($group);
} }
return true; return $result;
} }
/** /**

View File

@ -199,6 +199,8 @@ final class Kernel
\imagepng($im, $outPath); \imagepng($im, $outPath);
} elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) { } elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) {
\imagejpeg($im, $outPath); \imagejpeg($im, $outPath);
} elseif (\strripos($outPath, 'webp') !== false) {
\imagewebp($im, $outPath);
} else { } else {
\imagegif($im, $outPath); \imagegif($im, $outPath);
} }

View File

@ -115,6 +115,8 @@ final class Skew
\imagepng($im, $outPath); \imagepng($im, $outPath);
} elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) { } elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) {
\imagejpeg($im, $outPath); \imagejpeg($im, $outPath);
} elseif (\strripos($outPath, 'webp') !== false) {
\imagewebp($im, $outPath);
} else { } else {
\imagegif($im, $outPath); \imagegif($im, $outPath);
} }

View File

@ -124,6 +124,8 @@ final class Thresholding
\imagepng($out, $outPath); \imagepng($out, $outPath);
} elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) { } elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) {
\imagejpeg($out, $outPath); \imagejpeg($out, $outPath);
} elseif (\strripos($outPath, 'webp') !== false) {
\imagewebp($im, $outPath);
} else { } else {
\imagegif($out, $outPath); \imagegif($out, $outPath);
} }

View File

@ -111,7 +111,7 @@ final class Head implements RenderableInterface
*/ */
public function addAsset(int $type, string $uri, array $attributes = []) : void public function addAsset(int $type, string $uri, array $attributes = []) : void
{ {
$this->assets[$uri] = ['type' => $type, 'attributes' => $attributes]; $this->assets[] = ['uri' => $uri, 'type' => $type, 'attributes' => $attributes];
} }
/** /**
@ -279,9 +279,19 @@ final class Head implements RenderableInterface
public function renderAssets() : string public function renderAssets() : string
{ {
$rendered = ''; $rendered = '';
foreach ($this->assets as $uri => $asset) { foreach ($this->assets as $asset) {
if ($asset['type'] === AssetType::CSS) { if ($asset['type'] === AssetType::CSS) {
$rendered .= '<link rel="stylesheet" type="text/css" href="' . $uri . '"'; $rendered .= '<link rel="stylesheet" type="text/css" href="' . $asset['uri'] . '"';
foreach ($asset['attributes'] as $key => $attribute) {
$rendered .= \is_string($key)
? ' ' . $key . '="' . $attribute . '"'
: ' ' . $attribute;
}
$rendered .= '>';
} elseif ($asset['type'] === AssetType::LINK) {
$rendered .= '<link href="' . $asset['uri'] . '"';
foreach ($asset['attributes'] as $key => $attribute) { foreach ($asset['attributes'] as $key => $attribute) {
$rendered .= \is_string($key) $rendered .= \is_string($key)
@ -291,7 +301,7 @@ final class Head implements RenderableInterface
$rendered .= '>'; $rendered .= '>';
} elseif ($asset['type'] === AssetType::JS) { } elseif ($asset['type'] === AssetType::JS) {
$rendered .= '<script src="' . $uri . '"'; $rendered .= '<script src="' . $asset['uri'] . '"';
foreach ($asset['attributes'] as $key => $attribute) { foreach ($asset['attributes'] as $key => $attribute) {
$rendered .= \is_string($key) $rendered .= \is_string($key)
@ -316,9 +326,9 @@ final class Head implements RenderableInterface
public function renderAssetsLate() : string public function renderAssetsLate() : string
{ {
$rendered = ''; $rendered = '';
foreach ($this->assets as $uri => $asset) { foreach ($this->assets as $asset) {
if ($asset['type'] === AssetType::JSLATE) { if ($asset['type'] === AssetType::JSLATE) {
$rendered .= '<script src="' . $uri . '"'; $rendered .= '<script src="' . $asset['uri'] . '"';
foreach ($asset['attributes'] as $key => $attribute) { foreach ($asset['attributes'] as $key => $attribute) {
$rendered .= ' ' . $key . '="' . $attribute . '"'; $rendered .= ' ' . $key . '="' . $attribute . '"';

View File

@ -787,15 +787,29 @@ abstract class ModuleAbstract
* @param string $trigger Trigger for the event manager * @param string $trigger Trigger for the event manager
* @param string $ip Ip * @param string $ip Ip
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function createModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : void protected function createModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : bool
{ {
$trigger = static::NAME . '-' . $trigger . '-create'; $trigger = static::NAME . '-' . $trigger . '-create';
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $obj); $data = [
$account,
null, $obj,
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
static::NAME,
null,
null,
$ip,
];
$eventResult = $this->app->eventManager->triggerSimilar('PRE:' . $trigger, '', $data);
if ($eventResult !== [] && \in_array(-1, $eventResult, true)) {
return false;
}
$id = 0; $id = 0;
if (\is_string($mapper)) { if (\is_string($mapper)) {
@ -804,19 +818,13 @@ abstract class ModuleAbstract
$mapper(); $mapper();
} }
$data = [ $data[6] = (string) $id;
$account,
null, $obj,
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
static::NAME,
(string) $id,
null,
$ip,
];
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
self::$auditor?->eventLogCreate(...$data); self::$auditor?->eventLogCreate(...$data);
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); $this->app->eventManager->triggerSimilar('POST:' . $trigger, '', $data);
return true;
} }
/** /**
@ -832,38 +840,45 @@ abstract class ModuleAbstract
* @param string $trigger Trigger for the event manager * @param string $trigger Trigger for the event manager
* @param string $ip Ip * @param string $ip Ip
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function createModels(int $account, array $objs, string | \Closure $mapper, string $trigger, string $ip) : void protected function createModels(int $account, array $objs, string | \Closure $mapper, string $trigger, string $ip) : bool
{ {
$trigger = static::NAME . '-' . $trigger . '-create'; $trigger = static::NAME . '-' . $trigger . '-create';
foreach ($objs as $obj) { foreach ($objs as $obj) {
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $obj); $data = [
$id = 0; $account,
null, $obj,
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
static::NAME,
'',
null,
$ip,
];
$eventResult = $this->app->eventManager->triggerSimilar('PRE:' . $trigger, '', $data);
if ($eventResult !== [] && \in_array(-1, $eventResult, true)) {
continue;
}
$id = 0;
if (\is_string($mapper)) { if (\is_string($mapper)) {
$id = $mapper::create()->execute($obj); $id = $mapper::create()->execute($obj);
} else { } else {
$mapper(); $mapper();
} }
$data = [ $data[6] = (string) $id;
$account,
null, $obj,
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
static::NAME,
(string) $id,
null,
$ip,
];
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
self::$auditor?->eventLogCreate(...$data); self::$auditor?->eventLogCreate(...$data);
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); $this->app->eventManager->triggerSimilar('POST:' . $trigger, '', $data);
} }
return true;
} }
/** /**
@ -880,36 +895,43 @@ abstract class ModuleAbstract
* @param string $trigger Trigger for the event manager * @param string $trigger Trigger for the event manager
* @param string $ip Ip * @param string $ip Ip
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function updateModel(int $account, mixed $old, mixed $new, string | \Closure $mapper, string $trigger, string $ip) : void protected function updateModel(int $account, mixed $old, mixed $new, string | \Closure $mapper, string $trigger, string $ip) : bool
{ {
$trigger = static::NAME . '-' . $trigger . '-update'; $trigger = static::NAME . '-' . $trigger . '-update';
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $old);
$id = 0;
if (\is_string($mapper)) {
$id = $mapper::update()->execute($new);
} else {
$mapper();
}
$data = [ $data = [
$account, $account,
$old, $new, $old, $new,
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
static::NAME, static::NAME,
(string) $id, null,
null, null,
$ip, $ip,
]; ];
$eventResult = $this->app->eventManager->triggerSimilar('PRE:' . $trigger, '', $data);
if ($eventResult !== [] && \in_array(-1, $eventResult, true)) {
return false;
}
$id = 0;
if (\is_string($mapper)) {
$id = $mapper::update()->execute($new);
} else {
$mapper();
}
$data[6] = (string) $id;
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
self::$auditor?->eventLogUpdate(...$data); self::$auditor?->eventLogUpdate(...$data);
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); $this->app->eventManager->triggerSimilar('POST:' . $trigger, '', $data);
return true;
} }
/** /**
@ -925,36 +947,43 @@ abstract class ModuleAbstract
* @param string $trigger Trigger for the event manager * @param string $trigger Trigger for the event manager
* @param string $ip Ip * @param string $ip Ip
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function deleteModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : void protected function deleteModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : bool
{ {
$trigger = static::NAME . '-' . $trigger . '-delete'; $trigger = static::NAME . '-' . $trigger . '-delete';
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $obj);
$id = 0;
if (\is_string($mapper)) {
$id = $mapper::delete()->execute($obj);
} else {
$mapper();
}
$data = [ $data = [
$account, $account,
$obj, null, $obj, null,
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
static::NAME, static::NAME,
(string) $id, '',
null, null,
$ip, $ip,
]; ];
$eventResult = $this->app->eventManager->triggerSimilar('PRE:' . $trigger, '', $data);
if ($eventResult !== [] && \in_array(-1, $eventResult, true)) {
return false;
}
$id = 0;
if (\is_string($mapper)) {
$id = $mapper::delete()->execute($obj);
} else {
$mapper();
}
$data[6] = (string) $id;
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
self::$auditor?->eventLogDelete(...$data); self::$auditor?->eventLogDelete(...$data);
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); $this->app->eventManager->triggerSimilar('POST:' . $trigger, '', $data);
return true;
} }
/** /**
@ -996,7 +1025,7 @@ abstract class ModuleAbstract
* @param string $trigger Trigger for the event manager * @param string $trigger Trigger for the event manager
* @param string $ip Ip * @param string $ip Ip
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@ -1008,17 +1037,14 @@ abstract class ModuleAbstract
string $field, string $field,
string $trigger, string $trigger,
string $ip string $ip
) : void ) : bool
{ {
if (empty($rel1) || empty($rel2)) { if (empty($rel1) || empty($rel2)) {
return; return false;
} }
$trigger = static::NAME . '-' . $trigger . '-relation-create'; $trigger = static::NAME . '-' . $trigger . '-relation-create';
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1);
$mapper::writer()->createRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1);
$data = [ $data = [
$account, $account,
'', [$rel1 => $rel2], '', [$rel1 => $rel2],
@ -1029,9 +1055,18 @@ abstract class ModuleAbstract
$ip, $ip,
]; ];
$eventResult = $this->app->eventManager->triggerSimilar('PRE:' . $trigger, '', $data);
if ($eventResult !== [] && \in_array(-1, $eventResult, true)) {
return false;
}
$mapper::writer()->createRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1);
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
self::$auditor?->eventLogRelationCreate(...$data); self::$auditor?->eventLogRelationCreate(...$data);
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); $this->app->eventManager->triggerSimilar('POST:' . $trigger, '', $data);
return true;
} }
/** /**
@ -1049,23 +1084,14 @@ abstract class ModuleAbstract
* @param string $trigger Trigger for the event manager * @param string $trigger Trigger for the event manager
* @param string $ip Ip * @param string $ip Ip
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function deleteModelRelation(int $account, mixed $rel1, mixed $rel2, string $mapper, string $field, string $trigger, string $ip) : void protected function deleteModelRelation(int $account, mixed $rel1, mixed $rel2, string $mapper, string $field, string $trigger, string $ip) : bool
{ {
$trigger = static::NAME . '-' . $trigger . '-relation-delete'; $trigger = static::NAME . '-' . $trigger . '-relation-delete';
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1);
$mapper::remover()->deleteRelationTable(
$field,
$rel2 === null
? null
: (\is_array($rel2) ? $rel2 : [$rel2]),
$rel1
);
$data = [ $data = [
$account, $account,
[$rel1 => $rel2], '', [$rel1 => $rel2], '',
@ -1076,8 +1102,23 @@ abstract class ModuleAbstract
$ip, $ip,
]; ];
$eventResult = $this->app->eventManager->triggerSimilar('PRE:' . $trigger, '', $data);
if ($eventResult !== [] && \in_array(-1, $eventResult, true)) {
return false;
}
$mapper::remover()->deleteRelationTable(
$field,
$rel2 === null
? null
: (\is_array($rel2) ? $rel2 : [$rel2]),
$rel1
);
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
self::$auditor?->eventLogRelationDelete(...$data); self::$auditor?->eventLogRelationDelete(...$data);
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); $this->app->eventManager->triggerSimilar('POST:' . $trigger, '', $data);
return true;
} }
} }

View File

@ -225,6 +225,26 @@ abstract class CodeAbstract
\imagedestroy($res); \imagedestroy($res);
} }
/**
* Save to file
*
* @param string $file File path/name
*
* @return void
*
* @since 1.0.0
*/
public function saveToWebpFile(string $file) : void
{
$res = $this->get();
if ($res === null) {
return;
}
\imagewebp($res, $file);
\imagedestroy($res);
}
/** /**
* Save to file * Save to file
* *

View File

@ -180,6 +180,8 @@ final class ImageUtils
\imagepng($dst, $dstPath); \imagepng($dst, $dstPath);
} elseif (\stripos($srcPath, '.gif')) { } elseif (\stripos($srcPath, '.gif')) {
\imagegif($dst, $dstPath); \imagegif($dst, $dstPath);
} elseif (\stripos($srcPath, '.webp')) {
\imagewebp($dst, $dstPath);
} }
\imagedestroy($src); \imagedestroy($src);
@ -347,6 +349,8 @@ final class ImageUtils
\imagepng($dst, $out); \imagepng($dst, $out);
} elseif (\stripos($out, '.gif')) { } elseif (\stripos($out, '.gif')) {
\imagegif($dst, $out); \imagegif($dst, $out);
} elseif (\stripos($out, '.webp')) {
\imagewebp($dst, $out);
} }
\imagedestroy($src1); \imagedestroy($src1);

View File

@ -106,34 +106,6 @@ class View extends ViewAbstract
$this->l11n = $response !== null ? $response->header->l11n : new Localization(); $this->l11n = $response !== null ? $response->header->l11n : new Localization();
} }
/**
* Check if data exists
*
* @param string $id Data Id
*
* @return bool
*
* @since 1.0.0
*/
public function hasData(string $id) : bool
{
return isset($this->data[$id]);
}
/**
* Get data attached to view
*
* @param string $id Data Id
*
* @return mixed
*
* @since 1.0.0
*/
public function getData(string $id) : mixed
{
return $this->data[$id] ?? null;
}
/** /**
* Set data of view * Set data of view
* *

View File

@ -63,10 +63,9 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
self::assertEmpty($view->getTemplate()); self::assertEmpty($view->getTemplate());
self::assertEmpty($view->getViews()); self::assertEmpty($view->getViews());
self::assertIsArray($view->getViews()); self::assertIsArray($view->getViews());
self::assertFalse($view->hasData('0'));
self::assertFalse($view->getView('0')); self::assertFalse($view->getView('0'));
self::assertFalse($view->removeView('0')); self::assertFalse($view->removeView('0'));
self::assertNull($view->getData('0')); self::assertNull($view->data['0']);
self::assertFalse($view->removeData('0')); self::assertFalse($view->removeData('0'));
self::assertEmpty($view->toArray()); self::assertEmpty($view->toArray());
} }
@ -174,7 +173,7 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
$view = new View($this->app->l11nManager); $view = new View($this->app->l11nManager);
$view->data['key'] = 'value'; $view->data['key'] = 'value';
self::assertEquals('value', $view->getData('key')); self::assertEquals('value', $view->data['key']);
} }
#[\PHPUnit\Framework\Attributes\Group('framework')] #[\PHPUnit\Framework\Attributes\Group('framework')]
@ -184,7 +183,7 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
$view = new View($this->app->l11nManager); $view = new View($this->app->l11nManager);
$view->data['key2'] = 'valu2'; $view->data['key2'] = 'valu2';
self::assertEquals('valu2', $view->getData('key2')); self::assertEquals('valu2', $view->data['key2']);
} }
#[\PHPUnit\Framework\Attributes\Group('framework')] #[\PHPUnit\Framework\Attributes\Group('framework')]
@ -195,7 +194,7 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
$view->data['key2'] = 'valu2'; $view->data['key2'] = 'valu2';
self::assertTrue($view->removeData('key2')); self::assertTrue($view->removeData('key2'));
self::assertNull($view->getData('key2')); self::assertNull($view->data['key2']);
} }
#[\PHPUnit\Framework\Attributes\Group('framework')] #[\PHPUnit\Framework\Attributes\Group('framework')]