diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
new file mode 100644
index 0000000..f71bc26
--- /dev/null
+++ b/.github/workflows/lint.yaml
@@ -0,0 +1,35 @@
+name: Lint
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+
+ # 'push' runs on inner branches, 'pull_request' will run only on outer PRs
+ if: >
+ github.event_name == 'push'
+ || (github.event_name == 'pull_request'
+ && github.event.pull_request.head.repo.full_name != github.repository)
+
+ permissions:
+ contents: read
+ steps:
+ - name: Code Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: "8.2"
+ extensions: gd, zip, intl, yaml, pdo_mysql, rdkafka, imagick
+ tools: composer:v2
+ coverage: none
+
+ - name: Install dependencies
+ run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
+
+ - name: PHP CS Fixer
+ run: vendor/bin/php-cs-fixer fix --dry-run --diff
diff --git a/.gitignore b/.gitignore
index dea414f..728d2fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@
/logs/*
!/logs/.gitkeep
+
+.php-cs-fixer.cache
\ No newline at end of file
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..80031ac
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,14 @@
+in(__DIR__)
+;
+
+return (new PhpCsFixer\Config())
+ ->setRules([
+ '@PER-CS2x0' => true,
+ '@PHP8x2Migration' => true,
+ ])
+ ->setFinder($finder)
+ ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
+;
diff --git a/bin/chandler-latte-lint b/bin/chandler-latte-lint
new file mode 100755
index 0000000..0e31b07
--- /dev/null
+++ b/bin/chandler-latte-lint
@@ -0,0 +1,21 @@
+#!/usr/bin/env php
+ignite(true);
+
+$path = $argv[1] ?? '.';
+
+use Chandler\MVC\SimplePresenter;
+
+final class TestPresenter extends SimplePresenter {}
+
+$presenter = new TestPresenter();
+$latte = $presenter->getTemplatingEngine();
+$latte->addExtension(new \Latte\Essential\TranslatorExtension(tr(...)));
+$latte->setStrictParsing();
+$linter = new Latte\Tools\Linter(engine: $latte);
+
+$ok = $linter->scanDirectory($path);
+exit($ok ? 0 : 1);
diff --git a/chandler.iml b/chandler.iml
deleted file mode 100644
index c7541f9..0000000
--- a/chandler.iml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/chandler.ipr b/chandler.ipr
deleted file mode 100644
index 911bf4d..0000000
--- a/chandler.ipr
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/chandler.iws b/chandler.iws
deleted file mode 100644
index de9d8bd..0000000
--- a/chandler.iws
+++ /dev/null
@@ -1,101 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $PROJECT_DIR$/composer.json
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1660915095386
-
-
- 1660915095386
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/chandler/Bootstrap.php b/chandler/Bootstrap.php
index 9ef30ab..7269317 100644
--- a/chandler/Bootstrap.php
+++ b/chandler/Bootstrap.php
@@ -1,14 +1,16 @@
-
* @internal
*/
@@ -16,76 +18,81 @@ class Bootstrap
{
/**
* Starts Tracy debugger session and installs panels.
- *
+ *
* @internal
* @return void
*/
private function registerDebugger(): void
{
Debugger::enable((CHANDLER_ROOT_CONF["debug"] ? Debugger::DEVELOPMENT : Debugger::PRODUCTION), __DIR__ . "/../logs");
- Debugger::getBar()->addPanel(new Chandler\Debug\DatabasePanel);
+ Debugger::getBar()->addPanel(new Chandler\Debug\DatabasePanel());
}
-
+
private function loadConfig(): void
{
- if(!file_exists($conf = CHANDLER_ROOT . "/chandler.yml"))
- if(!file_exists($conf = CHANDLER_ROOT . "/../chandler.yml"))
- if(!file_exists($conf = "/etc/chandler.d/chandler.yml"))
+ if (!file_exists($conf = CHANDLER_ROOT . "/chandler.yml")) {
+ if (!file_exists($conf = CHANDLER_ROOT . "/../chandler.yml")) {
+ if (!file_exists($conf = "/etc/chandler.d/chandler.yml")) {
exit("Configuration file not found... Have you forgotten to rename it?");
-
+ }
+ }
+ }
+
define("CHANDLER_ROOT_CONF", chandler_parse_yaml($conf)["chandler"]);
}
-
+
/**
* Loads procedural APIs.
- *
+ *
* @internal
* @return void
*/
private function registerFunctions(): void
{
- foreach(glob(CHANDLER_ROOT . "/chandler/procedural/*.php") as $procDef)
+ foreach (glob(CHANDLER_ROOT . "/chandler/procedural/*.php") as $procDef) {
require $procDef;
+ }
}
-
+
/**
* Set ups autoloaders.
- *
+ *
* @internal
* @return void
*/
private function registerAutoloaders(): void
{
- spl_autoload_register(function($class): void
- {
- if(strpos($class, "Chandler\\") !== 0) return;
-
+ spl_autoload_register(function ($class): void {
+ if (strpos($class, "Chandler\\") !== 0) {
+ return;
+ }
+
require_once(str_replace("\\", "/", str_replace("Chandler\\", CHANDLER_ROOT . "/chandler/", $class)) . ".php");
}, true, true);
}
-
+
/**
* Defines constant CONNECTING_IP, that stores end user's IP address.
* Uses X-Forwarded-For if present.
- *
+ *
* @internal
* @return void
*/
private function defineIP(): void
{
- if(isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
+ if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
$path = explode(", ", $_SERVER["HTTP_X_FORWARDED_FOR"]);
- $ip = $path[0];
+ $ip = $path[0];
} else {
$ip = $_SERVER["REMOTE_ADDR"];
}
-
+
define("CONNECTING_IP", $ip, false);
}
-
+
/**
* Initializes GeoIP, sets DB directory.
- *
+ *
* @internal
* @return void
*/
@@ -93,10 +100,10 @@ private function setupGeoIP(): void
{
geoip_setup_custom_directory(CHANDLER_ROOT . "/3rdparty/maxmind/");
}
-
+
/**
* Bootstraps extensions.
- *
+ *
* @internal
* @return void
*/
@@ -104,10 +111,10 @@ private function igniteExtensions(): void
{
Chandler\Extensions\ExtensionManager::i();
}
-
+
/**
* Starts router and serves request.
- *
+ *
* @internal
* @param string $url Request URL
* @return void
@@ -115,25 +122,26 @@ private function igniteExtensions(): void
private function route(string $url): void
{
ob_start();
-
+
$router = Chandler\MVC\Routing\Router::i();
- if(($output = $router->execute($url, NULL)) !== null)
+ if (($output = $router->execute($url, null)) !== null) {
echo $output;
- else
+ } else {
chandler_http_panic(404, "Not Found", "No routes for $url.");
-
+ }
+
ob_flush();
ob_end_flush();
flush();
}
-
+
/**
* Starts framework.
- *
+ *
* @internal
* @return void
*/
- function ignite(bool $headless = false): void
+ public function ignite(bool $headless = false): void
{
$this->registerFunctions();
$this->registerAutoloaders();
@@ -141,7 +149,7 @@ function ignite(bool $headless = false): void
$this->registerDebugger();
$this->igniteExtensions();
- if(!$headless) {
+ if (!$headless) {
header("Referrer-Policy: strict-origin-when-cross-origin");
$this->defineIP();
\Chandler\Database\CurrentUser::get(CONNECTING_IP, $_SERVER["HTTP_USER_AGENT"]);
@@ -150,4 +158,4 @@ function ignite(bool $headless = false): void
}
}
-return new Bootstrap;
+return new Bootstrap();
diff --git a/chandler/ControlPanel/includes/assert_user.php b/chandler/ControlPanel/includes/assert_user.php
index 8c6449e..ba19b5b 100644
--- a/chandler/ControlPanel/includes/assert_user.php
+++ b/chandler/ControlPanel/includes/assert_user.php
@@ -1,13 +1,14 @@
-getUser();
- if(!$user) return NULL;
-
- return $user->can("access")->model("admin")->whichBelongsTo(NULL);
-});
\ No newline at end of file
+ if (!$user) {
+ return null;
+ }
+
+ return $user->can("access")->model("admin")->whichBelongsTo(null);
+});
diff --git a/chandler/Database/CurrentUser.php b/chandler/Database/CurrentUser.php
index fdc8781..daa0926 100644
--- a/chandler/Database/CurrentUser.php
+++ b/chandler/Database/CurrentUser.php
@@ -1,4 +1,6 @@
-ip = $ip;
+ }
- if ($useragent)
+ if ($useragent) {
$this->useragent = $useragent;
+ }
}
public static function get($ip, $useragent)
{
- if (self::$instance === null) self::$instance = new self($ip, $useragent);
+ if (self::$instance === null) {
+ self::$instance = new self($ip, $useragent);
+ }
return self::$instance;
}
diff --git a/chandler/Database/DBEntity.php b/chandler/Database/DBEntity.php
index 05d7069..7c3451f 100644
--- a/chandler/Database/DBEntity.php
+++ b/chandler/Database/DBEntity.php
@@ -1,4 +1,6 @@
-getTable()->getName();
- if ($_table !== $this->tableName)
+ if ($_table !== $this->tableName) {
throw new ISE("Invalid data supplied for model: table $_table is not compatible with table" . $this->tableName);
+ }
$this->record = $row;
$this->user = Authenticator::i()->getUser();
}
-
- function __call(string $fName, array $args)
+
+ public function __call(string $fName, array $args)
{
if (substr($fName, 0, 3) === "set") {
$field = mb_strtolower(substr($fName, 3));
@@ -41,46 +46,48 @@ function __call(string $fName, array $args)
throw new \Error("Call to undefined method " . get_class($this) . "::$fName");
}
}
-
+
private function getTable(): Selection
{
return DatabaseConnection::i()->getContext()->table($this->tableName);
}
-
+
protected function getRecord(): ?ActiveRow
{
return $this->record;
}
-
+
protected function stateChanges(string $column, $value): void
{
- if (!is_null($this->record))
- $t = $this->record->{$column}; #Test if column exists
-
+ if (!is_null($this->record)) {
+ $t = $this->record->{$column};
+ } #Test if column exists
+
$this->changes[$column] = $value;
}
-
- function getId()
+
+ public function getId()
{
return $this->getRecord()->id;
}
-
- function isDeleted(): bool
+
+ public function isDeleted(): bool
{
- return (bool)$this->getRecord()->deleted;
+ return (bool) $this->getRecord()->deleted;
}
-
- function unwrap(): object
+
+ public function unwrap(): object
{
- return (object)$this->getRecord()->toArray();
+ return (object) $this->getRecord()->toArray();
}
-
- function delete(bool $softly = true): void
+
+ public function delete(bool $softly = true): void
{
- if (is_null($this->record))
+ if (is_null($this->record)) {
throw new ISE("Can't delete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?");
+ }
- (new Logs)->create($this->user->getId(), $this->getTable()->getName(), get_class($this), 2, $this->record->toArray(), $this->changes);
+ (new Logs())->create($this->user->getId(), $this->getTable()->getName(), get_class($this), 2, $this->record->toArray(), $this->changes);
if ($softly) {
$this->record = $this->getTable()->where("id", $this->record->id)->update(["deleted" => true]);
@@ -89,18 +96,19 @@ function delete(bool $softly = true): void
$this->deleted = true;
}
}
-
- function undelete(): void
+
+ public function undelete(): void
{
- if (is_null($this->record))
+ if (is_null($this->record)) {
throw new ISE("Can't undelete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?");
+ }
- (new Logs)->create($this->user->getId(), $this->getTable()->getName(), get_class($this), 3, $this->record->toArray(), ["deleted" => false]);
+ (new Logs())->create($this->user->getId(), $this->getTable()->getName(), get_class($this), 3, $this->record->toArray(), ["deleted" => false]);
$this->getTable()->where("id", $this->record->id)->update(["deleted" => false]);
}
- function save(?bool $log = false): void
+ public function save(?bool $log = false): void
{
if ($log) {
$user_id = Authenticator::i()->getUser()->getId();
@@ -110,28 +118,26 @@ function save(?bool $log = false): void
$this->record = $this->getTable()->insert($this->changes);
if ($log && $this->getTable()->getName() !== "ChandlerLogs" && CHANDLER_ROOT_CONF["preferences"]["logs"]["enabled"]) {
- (new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 0, $this->record->toArray(), $this->changes);
+ (new Logs())->create($user_id, $this->getTable()->getName(), get_class($this), 0, $this->record->toArray(), $this->changes);
}
} else {
if ($log && $this->getTable()->getName() !== "ChandlerLogs" && CHANDLER_ROOT_CONF["preferences"]["logs"]["enabled"]) {
- (new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 1, $this->record->toArray(), $this->changes);
+ (new Logs())->create($user_id, $this->getTable()->getName(), get_class($this), 1, $this->record->toArray(), $this->changes);
}
if ($this->deleted) {
- $this->record = $this->getTable()->insert((array)$this->record);
+ $this->record = $this->getTable()->insert((array) $this->record);
} else {
$this->getTable()->get($this->record->id)->update($this->changes);
$this->record = $this->getTable()->get($this->record->id);
}
}
-
+
$this->changes = [];
}
- function getTableName(): string
+ public function getTableName(): string
{
return $this->getTable()->getName();
}
-
- use \Nette\SmartObject;
}
diff --git a/chandler/Database/DatabaseConnection.php b/chandler/Database/DatabaseConnection.php
index 558d3b9..182d657 100644
--- a/chandler/Database/DatabaseConnection.php
+++ b/chandler/Database/DatabaseConnection.php
@@ -1,70 +1,77 @@
-getCode() === "42000")
+ } catch (Database\ConnectionException $ex) {
+ if ($ex->getCode() === "42000") {
chandler_db_busy();
- else
+ } else {
chandler_http_panic(503, "Service Temporarily Unavailable", "Error estabilishing database connection: " . $ex->getMessage());
+ }
}
-
+
$storage = new FileStorage($tmpFolder ?? (CHANDLER_ROOT . "/tmp/cache/database"));
$structure = new Database\Structure($connection, $storage);
$conventions = new DiscoveredConventions($structure);
$context = new Database\Context($connection, $structure, $conventions, $storage);
-
+
$this->connection = $connection;
$this->context = $context;
-
- if(CHANDLER_ROOT_CONF["debug"])
+
+ if (CHANDLER_ROOT_CONF["debug"]) {
$this->connection->onQuery = $this->getQueryCallback();
+ }
}
-
+
private function __clone() {}
public function __wakeup() {}
-
+
protected function getQueryCallback(): array
{
- return [(function($connection, $result) {
- if($result instanceof \Nette\Database\DriverException)
+ return [(function ($connection, $result) {
+ if ($result instanceof \Nette\Database\DriverException) {
return;
-
- if(!isset($GLOBALS["dbgSqlQueries"])) {
+ }
+
+ if (!isset($GLOBALS["dbgSqlQueries"])) {
$GLOBALS["dbgSqlQueries"] = [];
$GLOBALS["dbgSqlTime"] = 0;
}
-
+
$params = $result->getParameters();
$GLOBALS["dbgSqlQueries"][] = str_replace(str_split(str_repeat("?", sizeof($params))), $params, $result->getQueryString());
$GLOBALS["dbgSqlTime"] += $result->getTime();
})];
}
-
- function getConnection(): Database\Connection
+
+ public function getConnection(): Database\Connection
{
return $this->connection;
}
-
- function getContext(): Database\Context
+
+ public function getContext(): Database\Context
{
return $this->context;
}
-
- static function i(): DatabaseConnection
+
+ public static function i(): DatabaseConnection
{
return static::$self ?? static::$self = new static(
CHANDLER_ROOT_CONF["database"]["dsn"],
@@ -72,19 +79,19 @@ static function i(): DatabaseConnection
CHANDLER_ROOT_CONF["database"]["password"]
);
}
-
- static function connect(array $options): DatabaseConnection
+
+ public static function connect(array $options): DatabaseConnection
{
$id = sha1(serialize($options)) . "__DATABASECONNECTION\$feafccc";
- if(!isset($GLOBALS[$id])) {
+ if (!isset($GLOBALS[$id])) {
$GLOBALS[$id] = new static(
$options["dsn"],
$options["user"],
$options["password"],
- isset($options["caching"]) ? ($options["caching"]["folder"] ?? NULL) : NULL
+ isset($options["caching"]) ? ($options["caching"]["folder"] ?? null) : null
);
}
-
+
return $GLOBALS[$id];
}
}
diff --git a/chandler/Database/Log.php b/chandler/Database/Log.php
index 27d312e..6854201 100644
--- a/chandler/Database/Log.php
+++ b/chandler/Database/Log.php
@@ -1,5 +1,9 @@
-getRecord()->id;
}
- function getUser(): string
+ public function getUser(): string
{
return $this->getRecord()->user;
}
- function getObjectTable(): string
+ public function getObjectTable(): string
{
return $this->getRecord()->object_table;
}
- function getObjectId(): int
+ public function getObjectId(): int
{
return $this->getRecord()->object_id;
}
- function getObject()
+ public function getObject()
{
$model = $this->getRecord()->object_model;
return new $model(DatabaseConnection::i()->getContext()->table($this->getObjectTable())->get($this->getObjectId()));
}
- function getTypeRaw(): int
+ public function getTypeRaw(): int
{
return $this->getRecord()->type;
}
- function getType(): string
+ public function getType(): string
{
return ["logs_added", "logs_edited", "logs_removed", "logs_restored"][$this->getTypeRaw()];
}
- function getTypeNom(): string
+ public function getTypeNom(): string
{
return ["logs_adding", "logs_editing", "logs_removing", "logs_restoring"][$this->getTypeRaw()];
}
- function getObjectType(): string
+ public function getObjectType(): string
{
$type = tr("log_" . $this->getObjectTable());
if ($type === "@log_" . $this->getObjectTable()) {
@@ -58,54 +62,59 @@ function getObjectType(): string
}
}
- function getObjectName(): string
+ public function getObjectName(): string
{
$object = $this->getObject();
- if (method_exists($object, 'getCanonicalName'))
+ if (method_exists($object, 'getCanonicalName')) {
return $object->getCanonicalName();
- else return "[#" . $this->getObjectId() . "] " . $this->getObjectType();
+ } else {
+ return "[#" . $this->getObjectId() . "] " . $this->getObjectType();
+ }
}
- function getLogsText(): string
+ public function getLogsText(): string
{
return $this->getRecord()->logs_text;
}
- function getObjectURL(): string
+ public function getObjectURL(): string
{
$object = $this->getObject();
- if (method_exists($object, "getURL") && $this->getObjectTable() !== "videos")
+ if (method_exists($object, "getURL") && $this->getObjectTable() !== "videos") {
return $this->getObject()->getURL();
- else
+ } else {
return "#";
+ }
}
- function getObjectAvatar(): ?string
+ public function getObjectAvatar(): ?string
{
$object = $this->getObject();
- if (method_exists($object, 'getAvatarURL'))
+ if (method_exists($object, 'getAvatarURL')) {
return $object->getAvatarURL("normal");
- else return NULL;
+ } else {
+ return null;
+ }
}
- function getOldValue(): ?array
+ public function getOldValue(): ?array
{
return (array) json_decode($this->getRecord()->xdiff_old, true, JSON_UNESCAPED_UNICODE) ?? null;
}
- function getNewValue(): ?array
+ public function getNewValue(): ?array
{
return (array) json_decode($this->getRecord()->xdiff_new, true, JSON_UNESCAPED_UNICODE) ?? null;
}
- function getTime(): int
+ public function getTime(): int
{
return $this->getRecord()->ts;
}
- function diff($old, $new): array
+ public function diff($old, $new): array
{
- $matrix = array();
+ $matrix = [];
$maxlen = 0;
foreach ($old as $oindex => $ovalue) {
$nkeys = array_keys($new, $ovalue);
@@ -119,27 +128,32 @@ function diff($old, $new): array
}
}
}
- if ($maxlen == 0) return array(array('d' => $old, 'i' => $new));
+ if ($maxlen == 0) {
+ return [['d' => $old, 'i' => $new]];
+ }
return array_merge(
$this->diff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)),
array_slice($new, $nmax, $maxlen),
- $this->diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)));
+ $this->diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen))
+ );
}
- function htmlDiff($old, $new): string
+ public function htmlDiff($old, $new): string
{
$ret = '';
$diff = $this->diff(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new));
foreach ($diff as $k) {
- if (is_array($k))
+ if (is_array($k)) {
$ret .= (!empty($k['d']) ? "" . implode(' ', $k['d']) . " " : '') .
(!empty($k['i']) ? "" . implode(' ', $k['i']) . " " : '');
- else $ret .= $k . ' ';
+ } else {
+ $ret .= $k . ' ';
+ }
}
return $ret;
}
- function getChanges(): array
+ public function getChanges(): array
{
$result = $this->getOldValue();
$_changes = [];
@@ -151,31 +165,31 @@ function getChanges(): array
$new_value = xdiff_string_patch((string) $result[$field], (string) $value);
$diff = preg_replace_callback("/<((?!\/?(?:del|ins)\b)[^>]*)>/i", function ($matches) {
return '[' . str_replace(['<', '>'], ['[', ']'], $matches[1]) . ']';
- }, $this->htmlDiff((string)$result[$field], (string)$new_value));
+ }, $this->htmlDiff((string) $result[$field], (string) $new_value));
$_changes[$field] = [
"field" => $field,
"old_value" => $result[$field],
"new_value" => strlen($new_value) > 0 ? $new_value : "(empty)",
"ts" => $this->getTime(),
- "diff" => $diff
+ "diff" => $diff,
];
}
- } else if ($this->getTypeRaw() === 0) { // create
+ } elseif ($this->getTypeRaw() === 0) { // create
foreach ($result as $field => $value) {
$_changes[$field] = [
"field" => $field,
"old_value" => $value,
- "ts" => $this->getTime()
+ "ts" => $this->getTime(),
];
}
- } else if ($this->getTypeRaw() === 2) { // delete
+ } elseif ($this->getTypeRaw() === 2) { // delete
$_changes[] = [
"field" => "deleted",
"old_value" => 0,
"new_value" => 1,
"ts" => $this->getTime(),
- "diff" => $this->htmlDiff("0", "1")
+ "diff" => $this->htmlDiff("0", "1"),
];
}
diff --git a/chandler/Database/Logs.php b/chandler/Database/Logs.php
index 6850daa..512fb3a 100644
--- a/chandler/Database/Logs.php
+++ b/chandler/Database/Logs.php
@@ -1,5 +1,9 @@
-context = DatabaseConnection::i()->getContext();
$this->logs = $this->context->table("ChandlerLogs");
@@ -18,15 +22,15 @@ function __construct()
private function toLog(?ActiveRow $ar): ?Log
{
- return is_null($ar) ? NULL : new Log($ar);
+ return is_null($ar) ? null : new Log($ar);
}
- function get(int $id): ?Log
+ public function get(int $id): ?Log
{
return $this->toLog($this->logs->get($id));
}
- function create(string $user, string $table, string $model, int $type, $object, $changes, ?string $ip = NULL, ?string $useragent = NULL): void
+ public function create(string $user, string $table, string $model, int $type, $object, $changes, ?string $ip = null, ?string $useragent = null): void
{
if ($model !== "Chandler\Database\Log") {
$fobject = (is_array($object) ? $object : $object->unwrap());
@@ -39,22 +43,28 @@ function create(string $user, string $table, string $model, int $type, $object,
}
foreach (array_diff_assoc($nobject, $changes) as $field => $value) {
- if (str_starts_with($field, "rate_limit")) continue;
- if ($field === "online") continue;
- $_changes[$field] = xdiff_string_diff((string)$nobject[$field], (string)$changes[$field]);
+ if (str_starts_with($field, "rate_limit")) {
+ continue;
+ }
+ if ($field === "online") {
+ continue;
+ }
+ $_changes[$field] = xdiff_string_diff((string) $nobject[$field], (string) $changes[$field]);
}
- if (count($_changes) === 0) return;
- } else if ($type === 0) { // if new
+ if (count($_changes) === 0) {
+ return;
+ }
+ } elseif ($type === 0) { // if new
$nobject = $fobject;
foreach ($fobject as $field => $value) {
- $_changes[$field] = xdiff_string_diff("", (string)$value);
+ $_changes[$field] = xdiff_string_diff("", (string) $value);
}
- } else if ($type === 2 || $type === 3) { // if deleting or restoring
- $_changes["deleted"] = (int)($type === 2);
+ } elseif ($type === 2 || $type === 3) { // if deleting or restoring
+ $_changes["deleted"] = (int) ($type === 2);
}
- $log = new Log;
+ $log = new Log();
$log->setUser($user);
$log->setType($type);
$log->setObject_Table($table);
@@ -69,17 +79,19 @@ function create(string $user, string $table, string $model, int $type, $object,
}
}
- function search($filter): \Traversable
+ public function search($filter): \Traversable
{
- foreach ($this->logs->where($filter)->order("id DESC") as $log)
+ foreach ($this->logs->where($filter)->order("id DESC") as $log) {
yield new Log($log);
+ }
}
- function getTypes(): array
+ public function getTypes(): array
{
$types = [];
- foreach ($this->context->query("SELECT DISTINCT(`object_model`) AS `object_model` FROM `ChandlerLogs`")->fetchAll() as $type)
+ foreach ($this->context->query("SELECT DISTINCT(`object_model`) AS `object_model` FROM `ChandlerLogs`")->fetchAll() as $type) {
$types[] = str_replace(CHANDLER_ROOT_CONF["preferences"]["logs"]["entitiesNamespace"], "", $type->object_model);
+ }
return $types;
}
diff --git a/chandler/Debug/DatabasePanel.php b/chandler/Debug/DatabasePanel.php
index 7a900a7..079ce99 100644
--- a/chandler/Debug/DatabasePanel.php
+++ b/chandler/Debug/DatabasePanel.php
@@ -1,49 +1,54 @@
-
- $svg
- $count queries ($time ms)
-
-EOF;
+
+ $svg
+ $count queries ($time ms)
+
+ EOF;
}
-
+
public function getPanel()
{
- if(!isset($GLOBALS["dbgSqlQueries"]))
+ if (!isset($GLOBALS["dbgSqlQueries"])) {
return "No queries were made...";
-
+ }
+
$html = <<Queries:
-
-
-
-HTML;
-
- foreach($GLOBALS["dbgSqlQueries"] as $query) {
+ Queries:
+
+
+
+ HTML;
+
+ foreach ($GLOBALS["dbgSqlQueries"] as $query) {
$query = DbHelpers::dumpSql($query);
$html .= "| $query |
";
}
-
+
$html .= "
";
-
+
return $html;
}
}
diff --git a/chandler/Email/Email.php b/chandler/Email/Email.php
index 8f1cd59..2fb7ce0 100644
--- a/chandler/Email/Email.php
+++ b/chandler/Email/Email.php
@@ -1,5 +1,9 @@
-sendEmail(
CHANDLER_ROOT_CONF["email"]["postmark"]["user"],
$to,
$subject,
$html,
strip_tags($html),
- NULL,
+ null,
true,
- NULL,
- NULL,
- NULL,
+ null,
+ null,
+ null,
["Sensitivity" => "Company-Confidential"],
- NULL,
+ null,
"None",
- NULL,
+ null,
CHANDLER_ROOT_CONF["email"]["postmark"]["stream"]
);
} else {
- $transport = new Swift_SmtpTransport(CHANDLER_ROOT_CONF["email"]["host"], CHANDLER_ROOT_CONF["email"]["port"], CHANDLER_ROOT_CONF["email"]["ssl"] ? "ssl" : NULL);
+ $transport = new Swift_SmtpTransport(CHANDLER_ROOT_CONF["email"]["host"], CHANDLER_ROOT_CONF["email"]["port"], CHANDLER_ROOT_CONF["email"]["ssl"] ? "ssl" : null);
$transport->setUsername(CHANDLER_ROOT_CONF["email"]["user"] ?? CHANDLER_ROOT_CONF["email"]["addr"]);
$transport->setPassword(CHANDLER_ROOT_CONF["email"]["pass"]);
diff --git a/chandler/Eventing/EventDispatcher.php b/chandler/Eventing/EventDispatcher.php
index e176997..4317065 100644
--- a/chandler/Eventing/EventDispatcher.php
+++ b/chandler/Eventing/EventDispatcher.php
@@ -1,33 +1,40 @@
-hooks[] = $hook;
-
+
return true;
}
-
- function pushEvent(Events\Event $event): Events\Event
+
+ public function pushEvent(Events\Event $event): Events\Event
{
- foreach($hooks as $hook) {
- if($event instanceof Events\Cancelable)
- if($event->isCancelled())
+ foreach ($hooks as $hook) {
+ if ($event instanceof Events\Cancelable) {
+ if ($event->isCancelled()) {
break;
-
+ }
+ }
+
$method = "on" . str_replace("Event", "", get_class($event));
- if(!method_exists($hook, $methodName)) continue;
-
+ if (!method_exists($hook, $methodName)) {
+ continue;
+ }
+
$hook->$method($event);
}
-
+
return $event;
}
-
- use TSimpleSingleton;
}
diff --git a/chandler/Eventing/Events/Cancelable.php b/chandler/Eventing/Events/Cancelable.php
index 0cfd8e8..71362b2 100644
--- a/chandler/Eventing/Events/Cancelable.php
+++ b/chandler/Eventing/Events/Cancelable.php
@@ -1,11 +1,14 @@
-data = $data;
$this->code = $code;
$this->time = time();
}
-
- function getData()
+
+ public function getData()
{
return $this->data;
}
-
- function getCode()
+
+ public function getCode()
{
return $this->code;
}
-
- function getTime()
+
+ public function getTime()
{
return $this->time;
}
-
- function isTainted()
+
+ public function isTainted()
{
return !$this->pristine;
}
diff --git a/chandler/Extensions/ExtensionManager.php b/chandler/Extensions/ExtensionManager.php
index 5cfd996..a3ba7d1 100644
--- a/chandler/Extensions/ExtensionManager.php
+++ b/chandler/Extensions/ExtensionManager.php
@@ -1,5 +1,9 @@
-in(CHANDLER_EXTENSIONS_AVAILABLE) as $directory) {
+ foreach (Finder::findDirectories("*")->in(CHANDLER_EXTENSIONS_AVAILABLE) as $directory) {
$extensionName = $directory->getFilename();
$directory = $directory->getRealPath();
$config = "$directory/manifest.yml";
-
- if(!file_exists($config)) {
+
+ if (!file_exists($config)) {
trigger_error("Skipping $extensionName for not having a valid configuration file ($config is not found)", E_USER_WARNING);
continue;
}
-
+
$this->extensions[$extensionName] = (object) chandler_parse_yaml($config);
$this->extensions[$extensionName]->id = $extensionName;
$this->extensions[$extensionName]->rawName = $directory;
$this->extensions[$extensionName]->enabled = CHANDLER_ROOT_CONF["extensions"]["allEnabled"];
}
-
- if(!CHANDLER_ROOT_CONF["extensions"]["allEnabled"]) {
- foreach(Finder::find("*")->in(CHANDLER_EXTENSIONS_ENABLED) as $directory) { #findDirectories doesn't work with symlinks
- if(!is_dir($directory->getRealPath())) continue;
-
+
+ if (!CHANDLER_ROOT_CONF["extensions"]["allEnabled"]) {
+ foreach (Finder::find("*")->in(CHANDLER_EXTENSIONS_ENABLED) as $directory) { #findDirectories doesn't work with symlinks
+ if (!is_dir($directory->getRealPath())) {
+ continue;
+ }
+
$extension = $directory->getFilename();
-
- if(!array_key_exists($extension, $this->extensions)) {
+
+ if (!array_key_exists($extension, $this->extensions)) {
trigger_error("Extension $extension is enabled, but not available, skipping", E_USER_WARNING);
continue;
}
-
+
$this->extensions[$extension]->enabled = true;
}
}
-
- if(!array_key_exists(CHANDLER_ROOT_CONF["rootApp"], $this->extensions) || !$this->extensions[CHANDLER_ROOT_CONF["rootApp"]]->enabled) {
+
+ if (!array_key_exists(CHANDLER_ROOT_CONF["rootApp"], $this->extensions) || !$this->extensions[CHANDLER_ROOT_CONF["rootApp"]]->enabled) {
trigger_error("Selected root app is not available", E_USER_ERROR);
}
-
+
$this->rootApp = CHANDLER_ROOT_CONF["rootApp"];
$this->eventLoop = EventDispatcher::i();
$this->router = Router::i();
-
+
$this->init();
}
-
+
private function init(): void
{
- foreach($this->getExtensions(true) as $name => $configuration) {
- spl_autoload_register(function($class) use ($name) {
- if(substr($class, 0, strlen("$name\\")) !== "$name\\")
+ foreach ($this->getExtensions(true) as $name => $configuration) {
+ spl_autoload_register(function ($class) use ($name) {
+ if (substr($class, 0, strlen("$name\\")) !== "$name\\") {
return false;
-
+ }
+
include_once CHANDLER_EXTENSIONS_ENABLED . "/" . str_replace("\\", "/", $class) . ".php";
});
-
+
define(str_replace("-", "_", mb_strtoupper($name)) . "_ROOT", CHANDLER_EXTENSIONS_ENABLED . "/$name", false);
define(str_replace("-", "_", mb_strtoupper($name)) . "_ROOT_CONF", chandler_parse_yaml(CHANDLER_EXTENSIONS_ENABLED . "/$name/$name.yml"), false);
-
- if(isset($configuration->init)) {
+
+ if (isset($configuration->init)) {
$init = require(CHANDLER_EXTENSIONS_ENABLED . "/$name/" . $configuration->init);
- if(is_callable($init))
+ if (is_callable($init)) {
$init();
+ }
}
-
- if(is_dir($hooks = CHANDLER_EXTENSIONS_ENABLED . "/$name/Hooks")) {
- foreach(Finder::findFiles("*Hook.php")->in($hooks) as $hookFile) {
+
+ if (is_dir($hooks = CHANDLER_EXTENSIONS_ENABLED . "/$name/Hooks")) {
+ foreach (Finder::findFiles("*Hook.php")->in($hooks) as $hookFile) {
$hookClassName = "$name\\Hooks\\" . str_replace(".php", "", end(explode("/", $hookFile)));
- $hook = new $hookClassName;
-
+ $hook = new $hookClassName();
+
$this->eventLoop->addListener($hook);
}
}
-
- if(is_dir($app = CHANDLER_EXTENSIONS_ENABLED . "/$name/Web")) #"app" means "web app", thus variable is called $app
+
+ if (is_dir($app = CHANDLER_EXTENSIONS_ENABLED . "/$name/Web")) { #"app" means "web app", thus variable is called $app
$this->router->readRoutes("$app/routes.yml", $name, $this->rootApp !== $name);
+ }
}
}
-
- function getExtensions(bool $onlyEnabled = false): array
+
+ public function getExtensions(bool $onlyEnabled = false): array
{
return $onlyEnabled
- ? array_filter($this->extensions, function($e) { return $e->enabled; })
+ ? array_filter($this->extensions, function ($e) { return $e->enabled; })
: $this->extensions;
}
-
- function getExtension(string $name): ?object
+
+ public function getExtension(string $name): ?object
{
return @$this->extensions[$name];
}
-
- function disableExtension(string $name): void
+
+ public function disableExtension(string $name): void
{
- if(!array_key_exists($name, $this->getExtensions(true))) return;
-
- if(!unlink(CHANDLER_EXTENSIONS_ENABLED . "/$name")) throw new \Exception("Could not disable extension");
+ if (!array_key_exists($name, $this->getExtensions(true))) {
+ return;
+ }
+
+ if (!unlink(CHANDLER_EXTENSIONS_ENABLED . "/$name")) {
+ throw new \Exception("Could not disable extension");
+ }
}
-
- function enableExtension(string $name): void
+
+ public function enableExtension(string $name): void
{
- if(CHANDLER_ROOT_CONF["extensions"]["allEnabled"]) return;
-
- if(array_key_exists($name, $this->getExtensions(true))) return;
-
+ if (CHANDLER_ROOT_CONF["extensions"]["allEnabled"]) {
+ return;
+ }
+
+ if (array_key_exists($name, $this->getExtensions(true))) {
+ return;
+ }
+
$path = CHANDLER_EXTENSIONS_AVAILABLE . "/$name";
- if(!is_dir($path)) throw new \Exception("Extension doesn't exist");
-
- if(!symlink($path, str_replace("available", "enabled", $path))) throw new \Exception("Could not enable extension");
+ if (!is_dir($path)) {
+ throw new \Exception("Extension doesn't exist");
+ }
+
+ if (!symlink($path, str_replace("available", "enabled", $path))) {
+ throw new \Exception("Could not enable extension");
+ }
}
-
- use TSimpleSingleton;
}
diff --git a/chandler/MVC/Exceptions/InterruptedException.php b/chandler/MVC/Exceptions/InterruptedException.php
index b95c387..6d0735d 100644
--- a/chandler/MVC/Exceptions/InterruptedException.php
+++ b/chandler/MVC/Exceptions/InterruptedException.php
@@ -1,5 +1,7 @@
- CssNode::create(...),
+ 'script' => ScriptNode::create(...),
+ 'presenter' => PresenterNode::create(...),
+ ];
+ }
+
+ public function getProviders(): array
+ {
+ return [
+ 'chandlerPresenter' => $this->presenter,
+ 'chandlerDomain' => explode("\\", $this->presenter)[0],
+ ];
+ }
+}
diff --git a/chandler/MVC/Latte/CssNode.php b/chandler/MVC/Latte/CssNode.php
new file mode 100644
index 0000000..541fac8
--- /dev/null
+++ b/chandler/MVC/Latte/CssNode.php
@@ -0,0 +1,45 @@
+expectArguments();
+ $node = new self();
+ $node->file = $tag->parser->parseUnquotedStringOrExpression();
+ return $node;
+ }
+
+ public function print(\Latte\Compiler\PrintContext $context): string
+ {
+ return $context->format(
+ <<<'XX'
+ %line
+ $__domain = $this->global->chandlerDomain;
+ $__file = %node;
+ $__realpath = CHANDLER_EXTENSIONS_ENABLED . "/$__domain/Web/static/$__file";
+
+ if (file_exists($__realpath)) {
+ $__hash = "sha384-" . base64_encode(hash_file("sha384", $__realpath, true));
+ $__mod = base_convert((string) filemtime($__realpath), 10, 32);
+ echo "";
+ } else {
+ echo "";
+ }
+ XX,
+ $this->position,
+ $this->file
+ );
+ }
+
+ public function &getIterator(): \Generator
+ {
+ yield $this->file;
+ }
+}
diff --git a/chandler/MVC/Latte/PresenterNode.php b/chandler/MVC/Latte/PresenterNode.php
new file mode 100644
index 0000000..e1edaa8
--- /dev/null
+++ b/chandler/MVC/Latte/PresenterNode.php
@@ -0,0 +1,43 @@
+expectArguments();
+ $node = new self();
+ $node->input = $tag->parser->parseArguments();
+ return $node;
+ }
+
+ public function print(\Latte\Compiler\PrintContext $context): string
+ {
+ return $context->format(
+ <<<'XX'
+ %line
+ $__input = %node;
+
+ echo "";
+
+ $__router = \Chandler\MVC\Routing\Router::i();
+ $__out = $__router->execute($__router->reverse(...$__input), $this->global->chandlerPresenter);
+ echo $__out;
+
+ echo "";
+ XX,
+ $this->position,
+ $this->input
+ );
+ }
+
+ public function &getIterator(): \Generator
+ {
+ yield $this->input;
+ }
+}
diff --git a/chandler/MVC/Latte/ScriptNode.php b/chandler/MVC/Latte/ScriptNode.php
new file mode 100644
index 0000000..82881ac
--- /dev/null
+++ b/chandler/MVC/Latte/ScriptNode.php
@@ -0,0 +1,45 @@
+expectArguments();
+ $node = new self();
+ $node->file = $tag->parser->parseUnquotedStringOrExpression();
+ return $node;
+ }
+
+ public function print(\Latte\Compiler\PrintContext $context): string
+ {
+ return $context->format(
+ <<<'XX'
+ %line
+ $__domain = $this->global->chandlerDomain;
+ $__file = %node;
+ $__realpath = CHANDLER_EXTENSIONS_ENABLED . "/$__domain/Web/static/$__file";
+
+ if (file_exists($__realpath)) {
+ $__hash = "sha384-" . base64_encode(hash_file("sha384", $__realpath, true));
+ $__mod = base_convert((string) filemtime($__realpath), 10, 32);
+ echo "";
+ } else {
+ echo "";
+ }
+ XX,
+ $this->position,
+ $this->file
+ );
+ }
+
+ public function &getIterator(): \Generator
+ {
+ yield $this->file;
+ }
+}
diff --git a/chandler/MVC/Routing/Exceptions/UnknownTypeAliasException.php b/chandler/MVC/Routing/Exceptions/UnknownTypeAliasException.php
index ead1b83..c5e1fd5 100644
--- a/chandler/MVC/Routing/Exceptions/UnknownTypeAliasException.php
+++ b/chandler/MVC/Routing/Exceptions/UnknownTypeAliasException.php
@@ -1,5 +1,7 @@
-)%";
- const ALIAS_REGEX = "%{(\??\!?([A-z]++))}%";
-
- private $url = NULL;
+ use TSimpleSingleton;
+ public const HANDLER_DELIMITER = "%([#@❤]|\->)%";
+ public const ALIAS_REGEX = "%{(\??\!?([A-z]++))}%";
+
+ private $url = null;
private $routes = [];
private $statics = [];
private $scope = [];
-
+
private $events;
-
+
protected $types = [
"num" => "(-?\d++)",
"text" => "([A-z0-9]++)",
"slug" => "([A-z0-9А-я\-_ ]++)",
];
-
+
private function __construct()
{
$this->events = EventDispatcher::i();
}
-
- private function computeRegExp(string $route, array $customAliases = [], ?string $prefix = NULL): string
+
+ private function computeRegExp(string $route, array $customAliases = [], ?string $prefix = null): string
{
- $regexp = preg_replace_callback(Router::ALIAS_REGEX, function($matches) use ($customAliases) {
- if($matches[1][0] === "?") {
+ $regexp = preg_replace_callback(Router::ALIAS_REGEX, function ($matches) use ($customAliases) {
+ if ($matches[1][0] === "?") {
$replacement = !isset($customAliases[$matches[2]])
- ? NULL
+ ? null
: ($matches[1][1] !== "!" ? "(" : "(?:") . $customAliases[$matches[2]] . ")";
} else {
$replacement = $this->types[$matches[1]];
}
-
- if(!$replacement) {
+
+ if (!$replacement) {
$exMessage = "Unknown type alias: $matches[1].";
$exMessage .= " (Available options are: " . implode(", ", array_keys($this->types));
- if(sizeof($customAliases) > 0)
+ if (sizeof($customAliases) > 0) {
$exMessage .= " or any of these user-defined aliases: " . implode(", ", array_keys($customAliases)) . ")";
- else
+ } else {
$exMessage .= ")";
-
+ }
+
throw new Exceptions\UnknownTypeAliasException($exMessage);
}
-
+
return $replacement;
}, addslashes($route));
-
- if(!is_null($prefix)) {
+
+ if (!is_null($prefix)) {
$regexp = "\\/$prefix\\" . ($route === "/" ? "/" : "/$regexp");
}
-
+
return "%^$regexp$%";
}
-
- function makeCSRFToken(Route $route, string $nonce): string
+
+ public function makeCSRFToken(Route $route, string $nonce): string
{
$key = hash("snefru", CHANDLER_ROOT_CONF["security"]["secret"] . bin2hex($nonce));
-
+
$data = $route->namespace;
$data .= Session::i()->get("tok", -1);
-
+
return hash_hmac("snefru", $data, $key) . "#" . bin2hex($nonce);
}
-
+
private function setCSRFStatus(Route $route): void
{
- if(CHANDLER_ROOT_CONF["security"]["csrfProtection"] === "disabled") {
+ if (CHANDLER_ROOT_CONF["security"]["csrfProtection"] === "disabled") {
$GLOBALS["csrfCheck"] = true;
} else {
$GLOBALS["csrfCheck"] = false;
-
+
$hash = ($_GET["hash"] ?? ($_POST["hash"] ?? false));
- if($hash !== false) {
+ if ($hash !== false) {
$data = explode("#", $hash);
-
+
try {
- if(!isset($data[0]) || !isset($data[1])) throw new \SodiumException;
+ if (!isset($data[0]) || !isset($data[1])) {
+ throw new \SodiumException();
+ }
[$hash, $nonce] = $data;
-
- if(sodium_memcmp($this->makeCSRFToken($route, hex2bin($nonce)), "$hash#$nonce") === 0) {
- if(CHANDLER_ROOT_CONF["security"]["csrfProtection"] === "permissive")
+
+ if (sodium_memcmp($this->makeCSRFToken($route, hex2bin($nonce)), "$hash#$nonce") === 0) {
+ if (CHANDLER_ROOT_CONF["security"]["csrfProtection"] === "permissive") {
$GLOBALS["csrfCheck"] = true;
- else if(CHANDLER_ROOT_CONF["security"]["csrfProtection"] === "strict")
+ } elseif (CHANDLER_ROOT_CONF["security"]["csrfProtection"] === "strict") {
$GLOBALS["csrfCheck"] = parse_url($_SERVER["HTTP_REFERER"], PHP_URL_HOST) === $_SERVER["HTTP_HOST"];
- else
+ } else {
trigger_error("Bad value for chandler.security.csrfProtection: disabled, permissive or strict expected.", E_USER_ERROR);
+ }
}
- } catch(\SodiumException $ex) {}
+ } catch (\SodiumException $ex) {
+ }
}
}
-
+
$GLOBALS["csrfToken"] = $this->makeCSRFToken($route, openssl_random_pseudo_bytes(4));
}
-
+
private function getDI(string $namespace): DI\Container
{
$loader = new DI\ContainerLoader(CHANDLER_ROOT . "/tmp/cache/di_$namespace", true);
- $class = $loader->load(function($compiler) use ($namespace) {
- $fileLoader = new \Nette\DI\Config\Loader;
+ $class = $loader->load(function ($compiler) use ($namespace) {
+ $fileLoader = new \Nette\DI\Config\Loader();
$fileLoader->addAdapter("yml", \Nette\DI\Config\Adapters\NeonAdapter::class);
-
+
$compiler->loadConfig(CHANDLER_EXTENSIONS_ENABLED . "/$namespace/Web/di.yml", $fileLoader);
});
-
- return new $class;
+
+ return new $class();
}
-
+
private function getPresenter(string $namespace, string $presenterName): ?IPresenter
{
$di = $this->getDI($namespace);
-
- $services = $di->findByType("\\$namespace\\Web\\Presenters\\$presenterName" . "Presenter", false);
- return $di->getService($services[0], false);
+
+ $services = $di->findByType("\\$namespace\\Web\\Presenters\\$presenterName" . "Presenter");
+ return $di->getService($services[0]);
}
-
+
private function delegateView(string $filename, IPresenter $presenter): string
{
return $presenter->getTemplatingEngine()->renderToString($filename, $this->scope);
}
-
+
private function delegateController(string $namespace, string $presenterName, string $action, array $parameters = []): string
{
$presenter = $this->getPresenter($namespace, $presenterName);
$action = ucfirst($action);
-
+
try {
$presenter->onStartup();
$presenter->{"render$action"}(...$parameters);
$presenter->onBeforeRender();
-
+
$this->scope += array_merge_recursive($presenter->getTemplateScope(), []); #TODO: add default parameters
- #TODO: move this to delegateView
-
- $tpl = $this->scope["_template"] ?? "$presenterName/$action.xml";
- if($tpl[0] !== "/") {
+ #TODO: move this to delegateView
+
+ $tpl = $this->scope["_template"] ?? "$presenterName/$action.latte";
+ if ($tpl[0] !== "/") {
$dir = CHANDLER_EXTENSIONS_ENABLED . "/$namespace/Web/Presenters/templates";
$tpl = "$dir/$tpl";
- if(isset($this->scope["_templatePath"]))
+ if (isset($this->scope["_templatePath"])) {
$tpl = str_replace($dir, $this->scope["_templatePath"], $tpl);
+ }
}
-
- if(!file_exists($tpl)) {
+
+ if (!file_exists($tpl)) {
trigger_error("Could not open $tpl as template, falling back.", E_USER_NOTICE);
- $tpl = CHANDLER_EXTENSIONS_ENABLED . "/$namespace/Web/Presenters/templates/$presenterName/$action.xml";
+ $tpl = CHANDLER_EXTENSIONS_ENABLED . "/$namespace/Web/Presenters/templates/$presenterName/$action.latte";
}
//if(str_contains($presenterName, "Poll")) return json_encode($this->scope);
$output = $this->delegateView($tpl, $presenter);
-
+
$presenter->onAfterRender();
- } catch(InterruptedException $ex) {}
-
+ } catch (InterruptedException $ex) {
+ }
+
$presenter->onStop();
$presenter->onDestruction();
- $presenter = NULL;
-
+ $presenter = null;
+
return $output;
}
-
+
private function delegateRoute(Route $route, array $matches): string
{
$parameters = [];
-
- foreach($matches as $param)
+
+ foreach ($matches as $param) {
$parameters[] = is_numeric($param) ? (int) $param : $param;
-
+ }
+
$this->setCSRFStatus($route);
return $this->delegateController($route->namespace, $route->presenter, $route->action, $parameters);
}
-
- function delegateStatic(string $namespace, string $path): string
+
+ public function delegateStatic(string $namespace, string $path): string
{
$static = $static = $this->statics[$namespace];
- if(!isset($static)) return "Fatal error: no route";
-
- if(!file_exists($file = "$static/$path"))
+ if (!isset($static)) {
+ return "Fatal error: no route";
+ }
+
+ if (!file_exists($file = "$static/$path")) {
return "Fatal error: no resource";
-
+ }
+
$hash = "W/\"" . hash_file("snefru", $file) . "\"";
- if(isset($_SERVER["HTTP_IF_NONE_MATCH"]))
- if($_SERVER["HTTP_IF_NONE_MATCH"] === $hash)
+ if (isset($_SERVER["HTTP_IF_NONE_MATCH"])) {
+ if ($_SERVER["HTTP_IF_NONE_MATCH"] === $hash) {
exit(header("HTTP/1.1 304"));
-
+ }
+ }
+
header("Content-Type: " . system_extension_mime_type($file) ?? "text/plain; charset=unknown-8bit");
header("Content-Size: " . filesize($file));
header("Cache-Control: public, must-understand, immutable, max-age=628000000");
header("ETag: $hash");
-
+
readfile($file);
-
+
exit;
}
-
- function reverse(string $hotlink, ...$parameters): ?string
+
+ public function reverse(string $hotlink, ...$parameters): ?string
{
- if(sizeof($j = explode("!", $hotlink)) === 2)
+ if (sizeof($j = explode("!", $hotlink)) === 2) {
[$namespace, $hotlink] = $j;
- else
+ } else {
$namespace = explode("\\", $this->scope["parentModule"])[0];
-
+ }
+
[$presenter, $action] = preg_split(Router::HANDLER_DELIMITER, $hotlink);
-
- foreach($this->routes as $route) {
- if($route->namespace !== $namespace || $route->presenter !== $presenter) continue;
- if(!is_null($action) && $route->action != $action) continue;
-
+
+ foreach ($this->routes as $route) {
+ if ($route->namespace !== $namespace || $route->presenter !== $presenter) {
+ continue;
+ }
+ if (!is_null($action) && $route->action != $action) {
+ continue;
+ }
+
$count = preg_match_all(Router::ALIAS_REGEX, $route->raw);
- if($count != sizeof($parameters)) continue;
-
+ if ($count != sizeof($parameters)) {
+ continue;
+ }
+
$i = 0;
- return preg_replace_callback(Router::ALIAS_REGEX, function() use ($parameters, &$i) {
+ return preg_replace_callback(Router::ALIAS_REGEX, function () use ($parameters, &$i) {
return $parameters[$i++];
}, $route->raw);
}
-
- return NULL;
+
+ return null;
}
-
- function push(?string $prefix, string $url, string $namespace, string $presenter, string $action, array $ph): void
+
+ public function push(?string $prefix, string $url, string $namespace, string $presenter, string $action, array $ph): void
{
- $route = new Route;
+ $route = new Route();
$route->raw = $url;
- if(!is_null($prefix))
+ if (!is_null($prefix)) {
$route->raw = "/$prefix" . $route->raw;
-
+ }
+
$route->regex = $this->computeRegExp($url, $ph, $prefix);
$route->namespace = $namespace;
$route->presenter = $presenter;
$route->action = $action;
-
+
$this->routes[] = $route;
}
-
- function pushStatic(string $namespace, string $path): void
+
+ public function pushStatic(string $namespace, string $path): void
{
$this->statics[$namespace] = $path;
}
-
- function readRoutes(string $filename, string $namespace, bool $autoprefix = true): void
+
+ public function readRoutes(string $filename, string $namespace, bool $autoprefix = true): void
{
$config = chandler_parse_yaml($filename);
-
- if(isset($config["static"]))
+
+ if (isset($config["static"])) {
$this->pushStatic($namespace, CHANDLER_EXTENSIONS_ENABLED . "/$namespace/Web/$config[static]");
-
- if(isset($config["include"]))
- foreach($config["include"] as $include)
+ }
+
+ if (isset($config["include"])) {
+ foreach ($config["include"] as $include) {
$this->readRoutes(dirname($filename) . "/$include", $namespace, $autoprefix);
-
- foreach($config["routes"] as $route) {
+ }
+ }
+
+ foreach ($config["routes"] as $route) {
$route = (object) $route;
$placeholders = $route->placeholders ?? [];
[$presenter, $action] = preg_split(Router::HANDLER_DELIMITER, $route->handler);
-
- $this->push($autoprefix ? $namespace : NULL, $route->url, $namespace, $presenter, $action, $placeholders);
+
+ $this->push($autoprefix ? $namespace : null, $route->url, $namespace, $presenter, $action, $placeholders);
}
}
-
- function getMatchingRoute(string $url): ?array
+
+ public function getMatchingRoute(string $url): ?array
{
- foreach($this->routes as $route)
- if(preg_match($route->regex, $url, $matches))
+ foreach ($this->routes as $route) {
+ if (preg_match($route->regex, $url, $matches)) {
return [$route, array_slice($matches, 1)];
-
- return NULL;
+ }
+ }
+
+ return null;
}
-
- function execute(string $url, ?string $parentModule = null): ?string
+
+ public function execute(string $url, ?string $parentModule = null): ?string
{
$this->scope = [];
$this->url = chandler_escape_url((string) parse_url(preg_replace("%/+%", "/", $url), PHP_URL_PATH));
-
- if(!is_null($parentModule)) {
+
+ if (!is_null($parentModule)) {
$GLOBALS["parentModule"] = $parentModule;
$this->scope["parentModule"] = $GLOBALS["parentModule"];
}
-
- if(preg_match("%^\/assets\/packages\/static\/([A-z_\\-]++)\/(.++)$%", $this->url, $matches)) {
+
+ if (preg_match("%^\/assets\/packages\/static\/([A-z_\\-]++)\/(.++)$%", $this->url, $matches)) {
[$j, $namespace, $file] = $matches;
return $this->delegateStatic($namespace, $file);
}
-
+
$match = $this->getMatchingRoute($this->url);
- if(!$match)
- return NULL;
-
+ if (!$match) {
+ return null;
+ }
+
return $this->delegateRoute(...$match);
}
-
- use TSimpleSingleton;
}
diff --git a/chandler/MVC/SimplePresenter.php b/chandler/MVC/SimplePresenter.php
index 065b9ce..4de60a4 100644
--- a/chandler/MVC/SimplePresenter.php
+++ b/chandler/MVC/SimplePresenter.php
@@ -1,102 +1,75 @@
-template = (object) [];
}
-
- function getTemplatingEngine(): TemplatingEngine
+
+ public function getTemplatingEngine(): TemplatingEngine
{
- $latte = new TemplatingEngine;
- $macros = new \Latte\Macros\MacroSet($latte->getCompiler());
+ $latte = new TemplatingEngine();
+
$latte->setTempDirectory(CHANDLER_ROOT . "/tmp/cache/templates");
-
- $macros->addMacro("css", '
- $domain = "' . explode("\\", static::class)[0] . '";
- $file = (%node.array)[0];
- $realpath = CHANDLER_EXTENSIONS_ENABLED . "/$domain/Web/static/$file";
- if(file_exists($realpath)) {
- $hash = "sha384-" . base64_encode(hash_file("sha384", $realpath, true));
- $mod = base_convert((string) (filemtime($realpath)), 10, 32);
- echo "";
- } else {
- echo "";
- }
- ');
- $macros->addMacro("script", '
- $domain = "' . explode("\\", static::class)[0] . '";
- $file = (%node.array)[0];
- $realpath = CHANDLER_EXTENSIONS_ENABLED . "/$domain/Web/static/$file";
- if(file_exists($realpath)) {
- $hash = "sha384-" . base64_encode(hash_file("sha384", $realpath, true));
- $mod = base_convert((string) (filemtime($realpath)), 10, 32);
- echo "";
- } else {
- echo "";
- }
- ');
- $macros->addMacro("presenter", '
- $input = (%node.array);
-
- echo "";
-
- $router = \Chandler\MVC\Routing\Router::i();
- $__out = $router->execute($router->reverse(...$input), "' . static::class . '");
- echo $__out;
-
- echo "";
- '
- );
-
+ $latte->addExtension(new \Latte\Bridges\Tracy\TracyExtension());
+ $latte->addExtension(new \Latte\Essential\RawPhpExtension());
+
+ $latte->addExtension(new ChandlerExtension(static::class));
+
return $latte;
}
-
+
protected function throwError(int $code = 400, string $desc = "Bad Request", string $message = ""): void
{
- if(!is_null($this->errorTemplate)) {
+ if (!is_null($this->errorTemplate)) {
header("HTTP/1.0 $code $desc");
-
- $ext = explode("\\", get_class($this))[0];
- $path = CHANDLER_EXTENSIONS_ENABLED . "/$ext/Web/Presenters/templates/" . $this->errorTemplate . ".xml";
-
+
+ $ext = explode("\\", get_class($this))[0];
+ $path = CHANDLER_EXTENSIONS_ENABLED . "/$ext/Web/Presenters/templates/" . $this->errorTemplate . ".latte";
+
$latte = $this->getTemplatingEngine();
$latte->render($path, array_merge_recursive([
"code" => $code,
"desc" => $desc,
- "msg" => $message,
+ "msg" => $message,
], $this->getTemplateScope()));
exit;
} else {
chandler_http_panic($code, $desc, $message);
}
}
-
+
protected function assertNoCSRF(): void
{
- if(!$GLOBALS["csrfCheck"])
+ if (!$GLOBALS["csrfCheck"]) {
$this->throwError(400, "Bad Request", "CSRF token is missing or invalid.");
+ }
}
-
+
protected function terminate(): void
{
- throw new Exceptions\InterruptedException;
+ throw new Exceptions\InterruptedException();
}
-
+
protected function notFound(): void
{
$this->throwError(
@@ -105,131 +78,131 @@ protected function notFound(): void
"The resource you are looking for has been deleted, had its name changed or doesn't exist."
);
}
-
+
protected function getCaller(): string
{
return $GLOBALS["parentModule"] ?? "libchandler:absolute.0";
}
-
+
protected function redirect(string $location, int $code = 2): void
{
$code = 300 + $code;
- if(($code <=> 300) !== 0 && $code > 399) return;
-
+ if (($code <=> 300) !== 0 && $code > 399) {
+ return;
+ }
+
header("HTTP/1.1 $code");
header("Location: $location");
exit;
}
-
+
protected function pass(string $to, ...$args): void
{
- $args = array_merge([$to], $args);
+ $args = array_merge([$to], $args);
$router = \Chandler\MVC\Routing\Router::i();
- $__out = $router->execute($router->reverse(...$args), "libchandler:absolute.0");
+ $__out = $router->execute($router->reverse(...$args), "libchandler:absolute.0");
exit($__out);
}
-
+
protected function sendmail(string $to, string $template, array $params): void
{
- $emailDir = pathinfo($template, PATHINFO_DIRNAME);
+ $emailDir = pathinfo($template, PATHINFO_DIRNAME);
$template .= ".eml.latte";
-
- $renderedHTML = (new TemplatingEngine)->renderToString($template, $params);
- $document = new \DOMDocument();
+
+ $renderedHTML = (new TemplatingEngine())->renderToString($template, $params);
+ $document = new \DOMDocument();
$document->loadHTML($renderedHTML, LIBXML_NOEMPTYTAG);
- $querySel = new \DOMXPath($document);
-
+ $querySel = new \DOMXPath($document);
+
$subject = $querySel->query("//title/text()")->item(0)->data;
-
- foreach($querySel->query("//link[@rel='stylesheet']") as $link) {
+
+ foreach ($querySel->query("//link[@rel='stylesheet']") as $link) {
$style = $document->createElement("style");
$style->setAttribute("id", uniqid("mail", true));
$style->appendChild(new \DOMText(file_get_contents("$emailDir/assets/css/" . $link->getAttribute("href"))));
-
+
$link->parentNode->appendChild($style);
$link->parentNode->removeChild($link);
}
-
- foreach($querySel->query("//img") as $image) {
+
+ foreach ($querySel->query("//img") as $image) {
$imagePath = "$emailDir/assets/res/" . $image->getAttribute("src");
- $type = pathinfo($imagePath, PATHINFO_EXTENSION);
- $contents = base64_encode(file_get_contents($imagePath));
+ $type = pathinfo($imagePath, PATHINFO_EXTENSION);
+ $contents = base64_encode(file_get_contents($imagePath));
$image->setAttribute("src", "data:image/$type;base64,$contents");
}
-
+
\Chandler\Email\Email::send($to, $subject, $document->saveHTML());
}
-
+
protected function queryParam(string $index): ?string
{
- return $_GET[$index] ?? NULL;
+ return $_GET[$index] ?? null;
}
-
+
protected function postParam(string $index, bool $csrfCheck = true): ?string
{
- if($csrfCheck)
+ if ($csrfCheck) {
$this->assertNoCSRF();
-
- return $_POST[$index] ?? NULL;
+ }
+
+ return $_POST[$index] ?? null;
}
-
+
protected function requestParam(string $index): ?string
{
- return $_REQUEST[$index] ?? NULL;
+ return $_REQUEST[$index] ?? null;
}
-
+
protected function jsonParam(string $index): ?string
{
- if(!isset($GLOBALS["jsonInputCache"]))
+ if (!isset($GLOBALS["jsonInputCache"])) {
$GLOBALS["jsonInputCache"] = json_decode($this->queryParam("js") ?? file_get_contents("php://input"), true);
-
- return $GLOBALS["jsonInputCache"][$index] ?? NULL;
+ }
+
+ return $GLOBALS["jsonInputCache"][$index] ?? null;
}
-
+
protected function findParam(string $index, array $searchIn = ["json", "post", "query"]): ?string
{
- $res = NULL;
- foreach($searchIn as $search) {
- if($search === "json")
+ $res = null;
+ foreach ($searchIn as $search) {
+ if ($search === "json") {
$res = $this->jsonParam($index) ?? $res;
- else if($search === "post")
+ } elseif ($search === "post") {
$res = $this->postParam($index, false) ?? $res;
- else if($search === "query")
+ } elseif ($search === "query") {
$res = $this->queryParam($index) ?? $res;
+ }
}
-
+
return $res;
}
-
+
protected function checkbox(string $name): bool
{
return ($this->postParam($name) ?? "off") === "on";
}
-
- function getTemplateScope(): array
+
+ public function getTemplateScope(): array
{
return (array) $this->template;
}
-
- function onStartup(): void
+
+ public function onStartup(): void
{
date_default_timezone_set("UTC");
}
-
- function onBeforeRender(): void
+
+ public function onBeforeRender(): void
{
$this->template->csrfToken = $GLOBALS["csrfToken"];
}
-
- function onAfterRender(): void
- {}
-
- function onStop(): void
- {}
-
- function onDestruction(): void
- {}
-
- use SmartObject;
+
+ public function onAfterRender(): void {}
+
+ public function onStop(): void {}
+
+ public function onDestruction(): void {}
}
diff --git a/chandler/Patterns/ActiveRecord.php.old b/chandler/Patterns/ActiveRecord.php.old
deleted file mode 100644
index fae4254..0000000
--- a/chandler/Patterns/ActiveRecord.php.old
+++ /dev/null
@@ -1,34 +0,0 @@
-db = DatabaseConnection::i();
- $this->table = $this->db->table($this->tableName);
- if(!is_null($row)) $this->row = $row;
-
- $this->resetQuery();
- }
-
- private function resetQuery(): void
- {
- $this->query = clone $this->table;
- }
-
- function __call()
-}
diff --git a/chandler/Patterns/TSimpleSingleton.php b/chandler/Patterns/TSimpleSingleton.php
index 53b0b1c..6548046 100644
--- a/chandler/Patterns/TSimpleSingleton.php
+++ b/chandler/Patterns/TSimpleSingleton.php
@@ -1,16 +1,19 @@
-db = DatabaseConnection::i()->getContext();
$this->session = Session::i();
}
-
- private function verifySuRights(string $uId): bool
- {
-
- }
-
+
+ private function verifySuRights(string $uId): bool {}
+
private function makeToken(string $user, string $ip, string $ua): string
{
$data = ["user" => $user, "ip" => $ip, "ua" => $ua];
@@ -27,16 +29,16 @@ private function makeToken(string $user, string $ip, string $ua): string
->table("ChandlerTokens")
->where($data)
->fetch();
-
- if(!$token) {
+
+ if (!$token) {
$this->db->table("ChandlerTokens")->insert($data);
$token = $this->db->table("ChandlerTokens")->where($data)->fetch();
}
-
+
return $token->token;
}
-
- static function verifyHash(string $input, string $hash): bool
+
+ public static function verifyHash(string $input, string $hash): bool
{
try {
[$hash, $salt] = explode("$", $hash);
@@ -50,81 +52,94 @@ static function verifyHash(string $input, string $hash): bool
SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13
)
);
- if(sodium_memcmp($hash, $userHash) !== 0) return false;
- } catch(\SodiumException $ex) {
+ if (sodium_memcmp($hash, $userHash) !== 0) {
+ return false;
+ }
+ } catch (\SodiumException $ex) {
return false;
}
-
+
return true;
}
-
- function getUser(): ?User
+
+ public function getUser(): ?User
{
$token = $this->session->get("tok");
- if(!$token) return null;
-
+ if (!$token) {
+ return null;
+ }
+
$token = $this->db
->table("ChandlerTokens")
->where([
"token" => $token,
])
->fetch();
-
- if(!$token) return null;
-
+
+ if (!$token) {
+ return null;
+ }
+
$checksPassed = false;
- if(CHANDLER_ROOT_CONF["security"]["extendedValidation"])
+ if (CHANDLER_ROOT_CONF["security"]["extendedValidation"]) {
$checksPassed = $token->ip === CONNECTING_IP && $token->ua === $_SERVER["HTTP_USER_AGENT"];
- else
+ } else {
$checksPassed = true;
-
- if($checksPassed) {
+ }
+
+ if ($checksPassed) {
$su = $this->session->get("_su");
$user = $this->db->table("ChandlerUsers")->get($su ?? $token->user);
- if(!$user) return null;
-
+ if (!$user) {
+ return null;
+ }
+
return new User($user, !is_null($su));
}
-
+
return null;
}
-
- function authenticate(string $user): void
+
+ public function authenticate(string $user): void
{
$this->session->set("tok", $this->makeToken($user, CONNECTING_IP, $_SERVER["HTTP_USER_AGENT"]));
}
-
- function verifyCredentials(string $id, string $password): bool
+
+ public function verifyCredentials(string $id, string $password): bool
{
$user = $this->db->table("ChandlerUsers")->get($id);
- if(!$user)
+ if (!$user) {
return false;
- else if(!$this->verifyHash($password, $user->passwordHash))
+ } elseif (!$this->verifyHash($password, $user->passwordHash)) {
return false;
-
+ }
+
return true;
}
-
- function login(string $id, string $password): bool
+
+ public function login(string $id, string $password): bool
{
- if(!$this->verifyCredentials($id, $password))
+ if (!$this->verifyCredentials($id, $password)) {
return false;
-
+ }
+
$this->authenticate($id);
return true;
}
-
- function logout(bool $revoke = false): bool
+
+ public function logout(bool $revoke = false): bool
{
$token = $this->session->get("tok");
- if(!$token) return false;
-
- if($revoke) $this->db->table("ChandlerTokens")->where("id", $token)->delete();
-
- $this->session->set("tok", NULL);
-
+ if (!$token) {
+ return false;
+ }
+
+ if ($revoke) {
+ $this->db->table("ChandlerTokens")->where("id", $token)->delete();
+ }
+
+ $this->session->set("tok", null);
+
return true;
}
-
- use TSimpleSingleton;
}
diff --git a/chandler/Security/Authorization/Permission.php b/chandler/Security/Authorization/Permission.php
index 9dccc5f..e4636ee 100644
--- a/chandler/Security/Authorization/Permission.php
+++ b/chandler/Security/Authorization/Permission.php
@@ -1,15 +1,18 @@
-perm = new Permission;
-
+ $this->perm = new Permission();
+
$this->permissionManager = $permMan;
}
-
- function can(string $action): PermissionBuilder
+
+ public function can(string $action): PermissionBuilder
{
$this->perm->action = $action;
-
+
return $this;
}
-
- function model(string $model): PermissionBuilder
+
+ public function model(string $model): PermissionBuilder
{
$this->perm->model = $model;
-
+
return $this;
}
-
- function whichBelongsTo(?int $to)
+
+ public function whichBelongsTo(?int $to)
{
$this->perm->context = $to;
-
+
return is_null($this->permissionManager)
? $this
: $this->permissionManager->hasPermission($this->build());
}
-
- function build(): Permission
+
+ public function build(): Permission
{
return $this->perm;
}
diff --git a/chandler/Security/Authorization/Permissions.php b/chandler/Security/Authorization/Permissions.php
index 7bd5536..3a3d122 100644
--- a/chandler/Security/Authorization/Permissions.php
+++ b/chandler/Security/Authorization/Permissions.php
@@ -1,61 +1,69 @@
-db = DatabaseConnection::i()->getContext();
$this->user = $user;
-
+
$this->init();
}
-
+
private function init()
{
$uGroups = $this->user->getRaw()->related("ChandlerACLRelations.user")->order("priority ASC")->select("group");
- $groups = array_map(function($j) {
+ $groups = array_map(function ($j) {
return $j->group;
}, iterator_to_array($uGroups));
-
+
$permissionsAllowed = $this->db->table("ChandlerACLGroupsPermissions")->where("group IN (?)", $groups);
$permissionsDenied = iterator_to_array((clone $permissionsAllowed)->where("status", false));
$permissionsDenied = array_merge($permissionsDenied, iterator_to_array($this->db->table("ChandlerACLUsersPermissions")->where("user", $this->user->getId())));
$permissionsAllowed = $permissionsAllowed->where("status", true);
-
- foreach($permissionsAllowed as $perm) {
- foreach($permissionsDenied as $denied)
- if($denied->model === $perm->model && $denied->context === $perm->context && $denied->permission === $perm->permission)
+
+ foreach ($permissionsAllowed as $perm) {
+ foreach ($permissionsDenied as $denied) {
+ if ($denied->model === $perm->model && $denied->context === $perm->context && $denied->permission === $perm->permission) {
continue 2;
-
- $pm = new Permission;
+ }
+ }
+
+ $pm = new Permission();
$pm->action = $perm->permission;
$pm->model = $perm->model;
$pm->context = $perm->context;
$pm->status = true;
-
+
$this->perms[] = $pm;
}
}
-
- function getPermissions(): array
+
+ public function getPermissions(): array
{
return $this->perms;
}
-
- function hasPermission(Permission $pm): bool
+
+ public function hasPermission(Permission $pm): bool
{
- foreach($this->perms as $perm)
- if($perm->model === $pm->model && $perm->context === $pm->context && $perm->action === $pm->action)
+ foreach ($this->perms as $perm) {
+ if ($perm->model === $pm->model && $perm->context === $pm->context && $perm->action === $pm->action) {
return true;
-
+ }
+ }
+
return false;
}
}
diff --git a/chandler/Security/User.php b/chandler/Security/User.php
index f387385..7ef3899 100644
--- a/chandler/Security/User.php
+++ b/chandler/Security/User.php
@@ -1,5 +1,9 @@
-
*/
class User
@@ -17,7 +21,7 @@ class User
* @var \Nette\Database\Context DB Explorer
*/
private $db;
-
+
/**
* @var \Nette\Database\Table\ActiveRow ActiveRow that represents user
*/
@@ -26,21 +30,21 @@ class User
* @var bool Does this user is not the one who is logged in, but substituted?
*/
private $tainted;
-
+
/**
* @param \Nette\Database\Table\ActiveRow $user ActiveRow that represents user
* @param bool $tainted Does this user is not the one who is logged in, but substituted?
*/
- function __construct(ActiveRow $user, bool $tainted = false)
+ public function __construct(ActiveRow $user, bool $tainted = false)
{
$this->db = DatabaseConnection::i()->getContext();
$this->user = $user;
$this->tainted = $tainted;
}
-
+
/**
* Computes hash for a password.
- *
+ *
* @param string $password password
* @return string hash
*/
@@ -55,128 +59,130 @@ private static function makeHash(string $password): string
SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE,
SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13
);
-
+
return bin2hex($hash) . "$" . bin2hex($salt);
}
-
+
/**
* Get user's GUID.
- *
+ *
* @return string GUID
*/
- function getId(): string
+ public function getId(): string
{
return $this->user->id;
}
-
+
/**
* Get user's DB data as an array.
- *
+ *
* @return array DB data in form of associative array
*/
- function getAttributes(): array
+ public function getAttributes(): array
{
return (array) $this->user;
}
-
+
/**
* Get Permission Manager object.
- *
+ *
* @api
* @see \Chandler\Security\User::can
* @return \Chandler\Security\Authorization\Permissions Permission Manager
*/
- function getPermissions(): Permissions
+ public function getPermissions(): Permissions
{
return new Permissions($this);
}
-
+
/**
* Get ActiveRow that represents user
- *
+ *
* @return \Nette\Database\Table\ActiveRow ActiveRow
*/
- function getRaw(): ActiveRow
+ public function getRaw(): ActiveRow
{
return $this->user;
}
-
+
/**
* Checks if this user is not the one who is logged in, but substituted
- *
+ *
* @return bool Does this user is not the one who is logged in, but substituted?
*/
- function isTainted(): bool
+ public function isTainted(): bool
{
return $this->tainted;
}
-
+
/**
* Begins to build permission for checking it's status using Permission Builder.
* To get permission status you should chain methods like this:
* $user->can('do something')->model('\app\Web\Models\MyModel')->whichBelongsTo(10);
* In this case whichBelongsTo will automatically build permission and check if user
* has it. If you need to build permission for something another use {@see \Chandler\Security\User::getPermissions}.
- *
+ *
* @api
* @uses \Chandler\Security\Authorization\PermissionBuilder::can
* @return \Chandler\Security\Authorization\Permissions Permission Manager
*/
- function can(string $action): PermissionBuilder
+ public function can(string $action): PermissionBuilder
{
$pb = new PermissionBuilder($this->getPermissions());
-
+
return $pb->can($action);
}
-
+
/**
* Updates user password.
* If $oldPassword parameter is passed it will update password only if current
* user password (not the new one) matches $oldPassword.
- *
+ *
* @api
* @param string $password New Password
* @param string|null $oldPassword Current Password
* @return bool False if token manipulation error has been thrown
*/
- function updatePassword(string $password, ?string $oldPassword = NULL): bool
+ public function updatePassword(string $password, ?string $oldPassword = null): bool
{
- if(!is_null($oldPassword))
- if(!Authenticator::verifyHash($oldPassword, $this->getRaw()->passwordHash))
+ if (!is_null($oldPassword)) {
+ if (!Authenticator::verifyHash($oldPassword, $this->getRaw()->passwordHash)) {
return false;
-
+ }
+ }
+
$users = DatabaseConnection::i()->getContext()->table("ChandlerUsers");
$users->where("id", $this->getId())->update([
"passwordHash" => $this->makeHash($password),
]);
-
+
return true;
}
-
+
/**
* Creates new user if login has not been taken yet.
- *
+ *
* @api
* @param string $login Login (usually an email)
* @param string $password Password
* @return self|null New user if successful, null otherwise
*/
- static function create(string $login, string $password): ?User
+ public static function create(string $login, string $password): ?User
{
$users = DatabaseConnection::i()->getContext()->table("ChandlerUsers");
$hash = self::makeHash($password);
-
+
try {
$users->insert([
"login" => $login,
"passwordHash" => $hash,
]);
-
+
$user = $users->where("login", $login)->fetch();
- } catch(UniqueConstraintViolationException $ex) {
+ } catch (UniqueConstraintViolationException $ex) {
return null;
}
-
+
return new static($user);
}
}
diff --git a/chandler/Session/Session.php b/chandler/Session/Session.php
index 5f3c092..f0e37e8 100644
--- a/chandler/Session/Session.php
+++ b/chandler/Session/Session.php
@@ -1,15 +1,21 @@
-
*/
class Session
{
+ use TSimpleSingleton;
/**
* @var array Associative array of session variables
*/
@@ -18,23 +24,24 @@ class Session
* @var string Web-portal secret key
*/
private $key;
-
+
/**
* @internal
*/
private function __construct()
{
$this->key = strtr(CHANDLER_ROOT_CONF["security"]["secret"], "-_", "+/");
-
- if(!isset($_COOKIE["CHANDLERSESS"]))
+
+ if (!isset($_COOKIE["CHANDLERSESS"])) {
$this->initSession();
- else
+ } else {
$this->bootstrapData();
+ }
}
-
+
/**
* Sets CHANDLERSESS cookie to specified token.
- *
+ *
* @internal
* @param string $token Token
* @return void
@@ -51,26 +58,26 @@ private function setSessionCookie(string $token): void
true
);
}
-
+
/**
* Calculates session token and sets session cookie value to it.
* This function skips empty keys.
- *
+ *
* @internal
* @return void
*/
private function updateSessionCookie(): void
{
- $this->data = array_filter($this->data, function($data) {
+ $this->data = array_filter($this->data, function ($data) {
return !(is_null($data) && $data !== "");
});
-
+
$this->setSessionCookie(JWT::encode($this->data, ($this->key), "HS512"));
}
-
+
/**
* Initializes session cookie with empty stub and loads no data.
- *
+ *
* @internal
* @return void
*/
@@ -78,14 +85,14 @@ private function initSession(): void
{
$token = JWT::encode([], ($this->key), "HS512");
$this->setSessionCookie($token);
-
+
$this->data = [];
}
-
+
/**
* Reads data from cookie.
* If cookie is corrupted, session terminates and starts again.
- *
+ *
* @internal
* @uses \Chandler\Session\Session::initSession
* @return void
@@ -93,17 +100,17 @@ private function initSession(): void
private function bootstrapData(): void
{
try {
- $this->data = (array) JWT::decode($_COOKIE["CHANDLERSESS"], ($this->key), ["HS512"]);
- } catch(\Exception $ex) {
+ $this->data = (array) JWT::decode($_COOKIE["CHANDLERSESS"], new Key($this->key, "HS512"));
+ } catch (\Exception $ex) {
$this->initSession();
}
}
-
+
/**
* Gets session variable.
* May also set a variable if default value is present and
* setting keys to default is permitted.
- *
+ *
* @api
* @param string $key Session variable name
* @param scalar $default Default value
@@ -111,26 +118,24 @@ private function bootstrapData(): void
* @uses \Chandler\Session\Session::set
* @return scalar
*/
- function get(string $key, $default = null, bool $set = false)
+ public function get(string $key, $default = null, bool $set = false)
{
return $this->data[sha1($key)] ?? ($set ? $this->set($key, $default) : $default);
}
-
+
/**
* Sets session variable.
- *
+ *
* @api
* @param string $key Session variable name
* @param scalar $value Value
* @return scalar Value
*/
- function set(string $key, $value)
+ public function set(string $key, $value)
{
$this->data[sha1($key)] = $value;
$this->updateSessionCookie();
-
+
return $value;
}
-
- use TSimpleSingleton;
}
diff --git a/chandler/Signaling/SignalManager.php b/chandler/Signaling/SignalManager.php
index b38793f..dbb6a54 100644
--- a/chandler/Signaling/SignalManager.php
+++ b/chandler/Signaling/SignalManager.php
@@ -1,15 +1,20 @@
-
*/
class SignalManager
{
+ use TSimpleSingleton;
/**
* @var int Latest event timestamp.
*/
@@ -18,26 +23,26 @@ class SignalManager
* @var \PDO PDO Connection to events SQLite DB.
*/
private $connection;
-
+
/**
* @internal
*/
private function __construct()
{
$this->since = time();
- $this->connection = new \PDO(
- 'sqlite:' . CHANDLER_ROOT . '/tmp/events.bin',
- null,
- null,
+ $this->connection = new \PDO(
+ 'sqlite:' . CHANDLER_ROOT . '/tmp/events.bin',
+ null,
+ null,
[\PDO::ATTR_PERSISTENT => true]
);
$this->connection->query("CREATE TABLE IF NOT EXISTS pool(id INTEGER PRIMARY KEY AUTOINCREMENT, since INTEGER, for INTEGER, event TEXT);");
}
-
+
/**
* Waits for event for user with ID = $for.
* This function is blocking.
- *
+ *
* @internal
* @param int $for User ID
* @return array|null Array of events if there are any, null otherwise
@@ -47,93 +52,98 @@ private function eventFor(int $for): ?array
$since = $this->since - 1;
$statement = $this->connection->query("SELECT * FROM pool WHERE `for` = $for AND `since` > $since ORDER BY since DESC");
$event = $statement->fetch(\PDO::FETCH_LAZY);
- if(!$event) return null;
-
+ if (!$event) {
+ return null;
+ }
+
$this->since = time();
return [$event->id, unserialize(hex2bin($event->event))];
}
-
+
/**
* Set ups listener.
* This function blocks the thread and calls $callback each time
* a signal is recieved for user with ID = $for
- *
+ *
* @api
* @param \Closure $callback Callback
* @param int $for User ID
* @uses \Chandler\Signaling\SignalManager::eventFor
* @return void
*/
- function listen(\Closure $callback, int $for, int $time = 25): void
+ public function listen(\Closure $callback, int $for, int $time = 25): void
{
$this->since = time() - 1;
- for($i = 0; $i < $time; $i++) {
+ for ($i = 0; $i < $time; $i++) {
sleep(1);
-
+
$event = $this->eventFor($for);
- if(!$event) continue;
-
- list($id, $evt) = $event;
- $id = crc32((string)$id);
+ if (!$event) {
+ continue;
+ }
+
+ [$id, $evt] = $event;
+ $id = crc32((string) $id);
$callback($evt, $id);
}
-
+
exit("[]");
}
-
+
/**
* Gets creation time of user's last event.
* If there is no events returns 1.
- *
+ *
* @api
* @param int $for User ID
* @return int
*/
- function tipFor(int $for): int
+ public function tipFor(int $for): int
{
$statement = $this->connection->query("SELECT since FROM pool WHERE `for` = $for ORDER BY since DESC");
$result = $statement->fetch(\PDO::FETCH_LAZY);
- if(!$result) return 1;
-
+ if (!$result) {
+ return 1;
+ }
+
return $result->since;
}
-
+
/**
* Gets history of long pool events.
* If there is no events returns empty array.
- *
+ *
* @api
* @param int $for User ID
* @param int|null $tip last sync time
* @return array
*/
- function getHistoryFor(int $for, ?int $tip = NULL, int $limit = 1000): array
+ public function getHistoryFor(int $for, ?int $tip = null, int $limit = 1000): array
{
$res = [];
- $tip = $tip ?? $this->tipFor($for);
+ $tip ??= $this->tipFor($for);
$query = $this->connection->query("SELECT * FROM pool WHERE `for` = $for AND `since` > $tip ORDER BY since DESC LIMIT $limit");
- foreach($query as $event)
+ foreach ($query as $event) {
$res[] = unserialize(hex2bin($event["event"]));
-
+ }
+
return $res;
}
-
+
/**
* Triggers event for user and sends signal to DB and listeners.
- *
+ *
* @api
* @param object $event Event
* @param int $for User ID
* @return bool Success state
*/
- function triggerEvent(object $event, int $for): bool
+ public function triggerEvent(object $event, int $for): bool
{
$event = bin2hex(serialize($event));
$since = time();
-
+
$this->connection->query("INSERT INTO pool VALUES (NULL, $since, $for, '$event')");
return true;
}
-
- use TSimpleSingleton;
}
diff --git a/chandler/procedural/db_busy.php b/chandler/procedural/db_busy.php
index a5472c7..d8963ca 100644
--- a/chandler/procedural/db_busy.php
+++ b/chandler/procedural/db_busy.php
@@ -1,8 +1,10 @@
-
* @return void
@@ -10,46 +12,46 @@
function chandler_db_busy(): void
{
$errPage = <<<'EOE'
-
-
-
- Resource Busy | Chandler App Server
-
-
-
-

-
Service Unavailable
-
Server can't proccess your request at this moment. Please try again later. Sorry for that.
-
-
-
-EOE;
-
+
+
+
+ Resource Busy | Chandler App Server
+
+
+
+

+
Service Unavailable
+
Server can't proccess your request at this moment. Please try again later. Sorry for that.
+
+
+
+ EOE;
+
header("HTTP/1.1 503 Service Unavailable");
exit($errPage);
}
diff --git a/chandler/procedural/escape_url.php b/chandler/procedural/escape_url.php
index ae3b5f0..b40abc3 100644
--- a/chandler/procedural/escape_url.php
+++ b/chandler/procedural/escape_url.php
@@ -1,4 +1,6 @@
- "png",
];
-
+
static $types;
- if(!isset($types))
+ if (!isset($types)) {
$types = system_extension_mime_types();
+ }
$ext = pathinfo($file, PATHINFO_EXTENSION);
- if(!$ext)
+ if (!$ext) {
$ext = $file;
+ }
$ext = strtolower($ext);
$ext = $aliases[$ext] ?? $ext;
- return isset($types[$ext]) ? $types[$ext] : null;
+ return $types[$ext] ?? null;
}
function system_mime_type_extensions(): array
@@ -46,16 +53,19 @@ function system_mime_type_extensions(): array
# extension listed to be canonical).
$out = [];
$file = fopen('/etc/mime.types', 'r');
- while(($line = fgets($file)) !== false) {
+ while (($line = fgets($file)) !== false) {
$line = trim(preg_replace('/#.*/', '', $line));
- if(!$line)
+ if (!$line) {
continue;
+ }
$parts = preg_split('/\s+/', $line);
- if(count($parts) == 1)
+ if (count($parts) == 1) {
continue;
+ }
$type = array_shift($parts);
- if(!isset($out[$type]))
+ if (!isset($out[$type])) {
$out[$type] = array_shift($parts);
+ }
}
fclose($file);
return $out;
@@ -68,7 +78,8 @@ function system_mime_type_extension(string $type): ?string
#
# $type - the MIME type
static $exts;
- if(!isset($exts))
+ if (!isset($exts)) {
$exts = system_mime_type_extensions();
- return isset($exts[$type]) ? $exts[$type] : null;
+ }
+ return $exts[$type] ?? null;
}
diff --git a/chandler/procedural/panic.php b/chandler/procedural/panic.php
index 39ad7d1..5346255 100644
--- a/chandler/procedural/panic.php
+++ b/chandler/procedural/panic.php
@@ -2,7 +2,7 @@
/**
* Ends application and renders error page.
- *
+ *
* @api
* @author kurotsun
* @param int $code HTTP Error code
@@ -13,45 +13,45 @@
function chandler_http_panic(int $code = 400, string $description = "Bad Request", string $message = ""): void
{
$error = <<
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EOE;
-EOE;
-
header("HTTP/1.0 $code $description");
exit($error);
-}
\ No newline at end of file
+}
diff --git a/chandler/procedural/yaml.php b/chandler/procedural/yaml.php
index 47263e4..b9d368a 100644
--- a/chandler/procedural/yaml.php
+++ b/chandler/procedural/yaml.php
@@ -1,4 +1,5 @@
* @param string $filename Path to file
@@ -20,20 +21,21 @@ function chandler_parse_yaml(string $filename): array
{
$cache = $GLOBALS["ymlCa"];
$id = sha1($filename);
-
+
$result = $cache->load($id);
- if(!$result) {
- if(function_exists("yaml_parse_file"))
+ if (!$result) {
+ if (function_exists("yaml_parse_file")) {
$result = yaml_parse_file($filename);
- else
+ } else {
$result = Yaml::parseFile($filename);
-
+ }
+
$cache->save($id, $result, [
Cache::EXPIRE => "1 day",
- Cache::SLIDING => TRUE,
+ Cache::SLIDING => true,
Cache::FILES => $filename,
]);
}
-
+
return $result;
}
diff --git a/composer.json b/composer.json
index 7ed21c6..f350728 100644
--- a/composer.json
+++ b/composer.json
@@ -1,22 +1,24 @@
{
+ "scripts": {
+ "fix": "php-cs-fixer fix",
+ "lint": "php-cs-fixer fix --dry-run --diff --verbose"
+ },
"require": {
- "php": "~8.1",
-
- "nette/utils": "^3.0",
- "nette/di": "^3.0",
- "nette/database": "^3.0",
+ "php": "~8.2",
+ "nette/utils": "^4.0",
+ "nette/di": "^3.2",
+ "nette/database": "^3.2",
"swiftmailer/swiftmailer": "^6.2",
- "latte/latte": "^2.10",
- "nette/safe-stream": "^2.4",
- "nette/tokenizer": "^3.1",
- "firebase/php-jwt": "^5.0",
- "symfony/translation": "^5.0",
- "symfony/yaml": "^5.3",
- "guzzlehttp/guzzle": "^6.0",
- "wildbit/postmark-php": "^4.0",
- "tracy/tracy": "^2.10"
+ "latte/latte": "^3.1",
+ "firebase/php-jwt": "^6.11",
+ "symfony/yaml": "^7.3",
+ "wildbit/postmark-php": "^7.0",
+ "tracy/tracy": "^2.11"
},
"suggest": {
"ext-yaml": "for faster yaml parsing"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.90"
}
}
diff --git a/composer.lock b/composer.lock
index 1836506..4c29627 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,33 +4,34 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "95611a9a1aee4a0fcabe6cddd0d07593",
+ "content-hash": "5387d7805bbcc789e0484cbc3159d4a4",
"packages": [
{
"name": "doctrine/deprecations",
- "version": "1.1.3",
+ "version": "1.1.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
- "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab"
+ "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
- "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
+ "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
+ "conflict": {
+ "phpunit/phpunit": "<=7.5 || >=13"
+ },
"require-dev": {
- "doctrine/coding-standard": "^9",
- "phpstan/phpstan": "1.4.10 || 1.10.15",
- "phpstan/phpstan-phpunit": "^1.0",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "psalm/plugin-phpunit": "0.18.4",
- "psr/log": "^1 || ^2 || ^3",
- "vimeo/psalm": "4.30.0 || 5.12.0"
+ "doctrine/coding-standard": "^9 || ^12 || ^13",
+ "phpstan/phpstan": "1.4.10 || 2.1.11",
+ "phpstan/phpstan-phpunit": "^1.0 || ^2",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
+ "psr/log": "^1 || ^2 || ^3"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
@@ -38,7 +39,7 @@
"type": "library",
"autoload": {
"psr-4": {
- "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
+ "Doctrine\\Deprecations\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -49,9 +50,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/1.1.3"
+ "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
},
- "time": "2024-01-30T19:34:25+00:00"
+ "time": "2025-04-07T20:06:18+00:00"
},
{
"name": "doctrine/lexer",
@@ -200,25 +201,31 @@
},
{
"name": "firebase/php-jwt",
- "version": "v5.5.1",
+ "version": "v6.11.1",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
- "reference": "83b609028194aa042ea33b5af2d41a7427de80e6"
+ "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6",
- "reference": "83b609028194aa042ea33b5af2d41a7427de80e6",
+ "url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
+ "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": "^8.0"
},
"require-dev": {
- "phpunit/phpunit": ">=4.8 <=9"
+ "guzzlehttp/guzzle": "^7.4",
+ "phpspec/prophecy-phpunit": "^2.0",
+ "phpunit/phpunit": "^9.5",
+ "psr/cache": "^2.0||^3.0",
+ "psr/http-client": "^1.0",
+ "psr/http-factory": "^1.0"
},
"suggest": {
+ "ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"type": "library",
@@ -251,43 +258,53 @@
],
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
- "source": "https://github.com/firebase/php-jwt/tree/v5.5.1"
+ "source": "https://github.com/firebase/php-jwt/tree/v6.11.1"
},
- "time": "2021-11-08T20:18:51+00:00"
+ "time": "2025-04-09T20:32:01+00:00"
},
{
"name": "guzzlehttp/guzzle",
- "version": "6.5.8",
+ "version": "7.10.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981"
+ "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981",
- "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
+ "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": ""
},
"require": {
"ext-json": "*",
- "guzzlehttp/promises": "^1.0",
- "guzzlehttp/psr7": "^1.9",
- "php": ">=5.5",
- "symfony/polyfill-intl-idn": "^1.17"
+ "guzzlehttp/promises": "^2.3",
+ "guzzlehttp/psr7": "^2.8",
+ "php": "^7.2.5 || ^8.0",
+ "psr/http-client": "^1.0",
+ "symfony/deprecation-contracts": "^2.2 || ^3.0"
+ },
+ "provide": {
+ "psr/http-client-implementation": "1.0"
},
"require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
- "psr/log": "^1.1"
+ "guzzle/client-integration-tests": "3.0.2",
+ "php-http/message-factory": "^1.1",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20",
+ "psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
+ "ext-curl": "Required for CURL handler support",
+ "ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "6.5-dev"
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
}
},
"autoload": {
@@ -340,19 +357,20 @@
}
],
"description": "Guzzle is a PHP HTTP client library",
- "homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
+ "psr-18",
+ "psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
- "source": "https://github.com/guzzle/guzzle/tree/6.5.8"
+ "source": "https://github.com/guzzle/guzzle/tree/7.10.0"
},
"funding": [
{
@@ -368,33 +386,37 @@
"type": "tidelift"
}
],
- "time": "2022-06-20T22:16:07+00:00"
+ "time": "2025-08-23T22:36:01+00:00"
},
{
"name": "guzzlehttp/promises",
- "version": "1.5.3",
+ "version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
- "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e"
+ "reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e",
- "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
+ "reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
- "php": ">=5.5"
+ "php": "^7.2.5 || ^8.0"
},
"require-dev": {
- "symfony/phpunit-bridge": "^4.4 || ^5.1"
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
"autoload": {
- "files": [
- "src/functions_include.php"
- ],
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
@@ -431,7 +453,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
- "source": "https://github.com/guzzle/promises/tree/1.5.3"
+ "source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
@@ -447,42 +469,48 @@
"type": "tidelift"
}
],
- "time": "2023-05-21T12:31:43+00:00"
+ "time": "2025-08-22T14:34:08+00:00"
},
{
"name": "guzzlehttp/psr7",
- "version": "1.9.1",
+ "version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b"
+ "reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b",
- "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
+ "reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
- "php": ">=5.4.0",
- "psr/http-message": "~1.0",
- "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ "php": "^7.2.5 || ^8.0",
+ "psr/http-factory": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0",
+ "ralouphie/getallheaders": "^3.0"
},
"provide": {
+ "psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
- "ext-zlib": "*",
- "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "http-interop/http-factory-tests": "0.9.0",
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
"autoload": {
- "files": [
- "src/functions_include.php"
- ],
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
@@ -521,6 +549,11 @@
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://sagikazarmark.hu"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
@@ -536,7 +569,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/1.9.1"
+ "source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
@@ -552,40 +585,42 @@
"type": "tidelift"
}
],
- "time": "2023-04-17T16:00:37+00:00"
+ "time": "2025-08-23T21:21:41+00:00"
},
{
"name": "latte/latte",
- "version": "v2.11.7",
+ "version": "v3.1.0",
"source": {
"type": "git",
"url": "https://github.com/nette/latte.git",
- "reference": "0ac0843a459790d471821f6a82f5d13db831a0d3"
+ "reference": "b6e3ad20c968b0aee9a8b7c8587592cdf1feea73"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/latte/zipball/0ac0843a459790d471821f6a82f5d13db831a0d3",
- "reference": "0ac0843a459790d471821f6a82f5d13db831a0d3",
+ "url": "https://api.github.com/repos/nette/latte/zipball/b6e3ad20c968b0aee9a8b7c8587592cdf1feea73",
+ "reference": "b6e3ad20c968b0aee9a8b7c8587592cdf1feea73",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-tokenizer": "*",
- "php": "7.1 - 8.3"
+ "php": "8.2 - 8.5"
},
"conflict": {
- "nette/application": "<2.4.1"
+ "nette/application": "<3.1.7",
+ "nette/caching": "<3.1.4"
},
"require-dev": {
- "nette/php-generator": "^3.3.4",
- "nette/tester": "^2.0",
- "nette/utils": "^3.0",
- "phpstan/phpstan": "^1",
- "tracy/tracy": "^2.3"
+ "nette/php-generator": "^4.0",
+ "nette/tester": "^2.5",
+ "nette/utils": "^4.0",
+ "phpstan/phpstan-nette": "^2.0@stable",
+ "tracy/tracy": "^2.10"
},
"suggest": {
"ext-fileinfo": "to use filter |datastream",
"ext-iconv": "to use filters |reverse, |substring",
+ "ext-intl": "to use Latte\\Engine::setLocale()",
"ext-mbstring": "to use filters like lower, upper, capitalize, ...",
"nette/php-generator": "to use tag {templatePrint}",
"nette/utils": "to use filter |webalize"
@@ -596,10 +631,13 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.11-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
+ "psr-4": {
+ "Latte\\": "src/Latte"
+ },
"classmap": [
"src/"
]
@@ -634,34 +672,37 @@
],
"support": {
"issues": "https://github.com/nette/latte/issues",
- "source": "https://github.com/nette/latte/tree/v2.11.7"
+ "source": "https://github.com/nette/latte/tree/v3.1.0"
},
- "time": "2023-10-18T17:16:11+00:00"
+ "time": "2025-11-26T04:28:31+00:00"
},
{
"name": "nette/caching",
- "version": "v3.2.3",
+ "version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/nette/caching.git",
- "reference": "6821d74c1db82c493c02c47f6485022d79b63176"
+ "reference": "a1c13221b350d0db0a2bd4a77c1e7b65e0aa065d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/caching/zipball/6821d74c1db82c493c02c47f6485022d79b63176",
- "reference": "6821d74c1db82c493c02c47f6485022d79b63176",
+ "url": "https://api.github.com/repos/nette/caching/zipball/a1c13221b350d0db0a2bd4a77c1e7b65e0aa065d",
+ "reference": "a1c13221b350d0db0a2bd4a77c1e7b65e0aa065d",
"shasum": ""
},
"require": {
- "nette/finder": "^2.4 || ^3.0",
- "nette/utils": "^3.2 || ~4.0.0",
- "php": "8.0 - 8.3"
+ "nette/utils": "^4.0",
+ "php": "8.1 - 8.5"
+ },
+ "conflict": {
+ "latte/latte": "<3.0.12"
},
"require-dev": {
- "latte/latte": "^2.11 || ^3.0",
+ "latte/latte": "^3.0.12",
"nette/di": "^3.1 || ^4.0",
"nette/tester": "^2.4",
- "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-nette": "^2.0@stable",
+ "psr/simple-cache": "^2.0 || ^3.0",
"tracy/tracy": "^2.9"
},
"suggest": {
@@ -670,10 +711,13 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -705,48 +749,48 @@
],
"support": {
"issues": "https://github.com/nette/caching/issues",
- "source": "https://github.com/nette/caching/tree/v3.2.3"
+ "source": "https://github.com/nette/caching/tree/v3.4.0"
},
- "time": "2023-09-26T11:12:20+00:00"
+ "time": "2025-08-06T23:05:08+00:00"
},
{
"name": "nette/database",
- "version": "v3.1.9",
+ "version": "v3.2.8",
"source": {
"type": "git",
"url": "https://github.com/nette/database.git",
- "reference": "4a21417d545e226a8fe189b95111d23a454bd2b3"
+ "reference": "1a84d3e61aa33461a3d6415235b25a7cd8b3f442"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/database/zipball/4a21417d545e226a8fe189b95111d23a454bd2b3",
- "reference": "4a21417d545e226a8fe189b95111d23a454bd2b3",
+ "url": "https://api.github.com/repos/nette/database/zipball/1a84d3e61aa33461a3d6415235b25a7cd8b3f442",
+ "reference": "1a84d3e61aa33461a3d6415235b25a7cd8b3f442",
"shasum": ""
},
"require": {
"ext-pdo": "*",
- "nette/caching": "^3.0",
- "nette/utils": "^3.2.1 || ~4.0.0",
- "php": "7.2 - 8.3"
- },
- "conflict": {
- "nette/di": "<3.0-stable"
+ "nette/caching": "^3.2",
+ "nette/utils": "^4.0",
+ "php": "8.1 - 8.5"
},
"require-dev": {
- "jetbrains/phpstorm-attributes": "^1.0",
- "mockery/mockery": "^1.3.4",
- "nette/di": "^v3.0",
- "nette/tester": "^2.4",
- "phpstan/phpstan-nette": "^0.12",
- "tracy/tracy": "^2.4"
+ "jetbrains/phpstorm-attributes": "^1.2",
+ "mockery/mockery": "^1.6@stable",
+ "nette/di": "^3.1",
+ "nette/tester": "^2.5",
+ "phpstan/phpstan-nette": "^2.0@stable",
+ "tracy/tracy": "^2.9"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.1-dev"
+ "dev-master": "3.2-dev"
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -783,45 +827,49 @@
],
"support": {
"issues": "https://github.com/nette/database/issues",
- "source": "https://github.com/nette/database/tree/v3.1.9"
+ "source": "https://github.com/nette/database/tree/v3.2.8"
},
- "time": "2023-11-05T19:41:36+00:00"
+ "time": "2025-10-30T22:06:23+00:00"
},
{
"name": "nette/di",
- "version": "v3.1.10",
+ "version": "v3.2.5",
"source": {
"type": "git",
"url": "https://github.com/nette/di.git",
- "reference": "2645ec3eaa17fa2ab87c5eb4eaacb1fe6dd28284"
+ "reference": "5708c328ce7658a73c96b14dd6da7b8b27bf220f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/di/zipball/2645ec3eaa17fa2ab87c5eb4eaacb1fe6dd28284",
- "reference": "2645ec3eaa17fa2ab87c5eb4eaacb1fe6dd28284",
+ "url": "https://api.github.com/repos/nette/di/zipball/5708c328ce7658a73c96b14dd6da7b8b27bf220f",
+ "reference": "5708c328ce7658a73c96b14dd6da7b8b27bf220f",
"shasum": ""
},
"require": {
+ "ext-ctype": "*",
"ext-tokenizer": "*",
- "nette/neon": "^3.3 || ^4.0",
- "nette/php-generator": "^3.5.4 || ^4.0",
- "nette/robot-loader": "^3.2 || ~4.0.0",
+ "nette/neon": "^3.3",
+ "nette/php-generator": "^4.1.6",
+ "nette/robot-loader": "^4.0",
"nette/schema": "^1.2.5",
- "nette/utils": "^3.2.5 || ~4.0.0",
- "php": "7.2 - 8.3"
+ "nette/utils": "^4.0",
+ "php": "8.1 - 8.5"
},
"require-dev": {
- "nette/tester": "^2.4",
- "phpstan/phpstan": "^1.0",
+ "nette/tester": "^2.5.2",
+ "phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.9"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.1-dev"
+ "dev-master": "3.2-dev"
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -855,98 +903,31 @@
],
"support": {
"issues": "https://github.com/nette/di/issues",
- "source": "https://github.com/nette/di/tree/v3.1.10"
- },
- "time": "2024-02-06T01:19:44+00:00"
- },
- {
- "name": "nette/finder",
- "version": "v2.6.0",
- "source": {
- "type": "git",
- "url": "https://github.com/nette/finder.git",
- "reference": "991aefb42860abeab8e003970c3809a9d83cb932"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/nette/finder/zipball/991aefb42860abeab8e003970c3809a9d83cb932",
- "reference": "991aefb42860abeab8e003970c3809a9d83cb932",
- "shasum": ""
- },
- "require": {
- "nette/utils": "^2.4 || ^3.0",
- "php": ">=7.1"
- },
- "conflict": {
- "nette/nette": "<2.2"
- },
- "require-dev": {
- "nette/tester": "^2.0",
- "phpstan/phpstan": "^0.12",
- "tracy/tracy": "^2.3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.6-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause",
- "GPL-2.0-only",
- "GPL-3.0-only"
- ],
- "authors": [
- {
- "name": "David Grudl",
- "homepage": "https://davidgrudl.com"
- },
- {
- "name": "Nette Community",
- "homepage": "https://nette.org/contributors"
- }
- ],
- "description": "🔍 Nette Finder: find files and directories with an intuitive API.",
- "homepage": "https://nette.org",
- "keywords": [
- "filesystem",
- "glob",
- "iterator",
- "nette"
- ],
- "support": {
- "issues": "https://github.com/nette/finder/issues",
- "source": "https://github.com/nette/finder/tree/v2.6.0"
+ "source": "https://github.com/nette/di/tree/v3.2.5"
},
- "time": "2022-10-13T01:31:15+00:00"
+ "time": "2025-08-14T22:59:46+00:00"
},
{
"name": "nette/neon",
- "version": "v3.4.4",
+ "version": "v3.4.6",
"source": {
"type": "git",
"url": "https://github.com/nette/neon.git",
- "reference": "3411aa86b104e2d5b7e760da4600865ead963c3c"
+ "reference": "36e3f4f89fd8a7b89ada74c7a678baa9f7cc7719"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/neon/zipball/3411aa86b104e2d5b7e760da4600865ead963c3c",
- "reference": "3411aa86b104e2d5b7e760da4600865ead963c3c",
+ "url": "https://api.github.com/repos/nette/neon/zipball/36e3f4f89fd8a7b89ada74c7a678baa9f7cc7719",
+ "reference": "36e3f4f89fd8a7b89ada74c7a678baa9f7cc7719",
"shasum": ""
},
"require": {
"ext-json": "*",
- "php": "8.0 - 8.4"
+ "php": "8.0 - 8.5"
},
"require-dev": {
"nette/tester": "^2.4",
- "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.7"
},
"bin": [
@@ -959,6 +940,9 @@
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -980,7 +964,7 @@
}
],
"description": "🍸 Nette NEON: encodes and decodes NEON file format.",
- "homepage": "https://ne-on.org",
+ "homepage": "https://neon.nette.org",
"keywords": [
"export",
"import",
@@ -990,33 +974,33 @@
],
"support": {
"issues": "https://github.com/nette/neon/issues",
- "source": "https://github.com/nette/neon/tree/v3.4.4"
+ "source": "https://github.com/nette/neon/tree/v3.4.6"
},
- "time": "2024-10-04T22:00:08+00:00"
+ "time": "2025-11-25T13:12:06+00:00"
},
{
"name": "nette/php-generator",
- "version": "v4.1.6",
+ "version": "v4.2.0",
"source": {
"type": "git",
"url": "https://github.com/nette/php-generator.git",
- "reference": "c90961e782ae86e517fe5ed732eb2b512945565b"
+ "reference": "4707546a1f11badd72f5d82af4f8a6bc64bd56ac"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/php-generator/zipball/c90961e782ae86e517fe5ed732eb2b512945565b",
- "reference": "c90961e782ae86e517fe5ed732eb2b512945565b",
+ "url": "https://api.github.com/repos/nette/php-generator/zipball/4707546a1f11badd72f5d82af4f8a6bc64bd56ac",
+ "reference": "4707546a1f11badd72f5d82af4f8a6bc64bd56ac",
"shasum": ""
},
"require": {
- "nette/utils": "^3.2.9 || ^4.0",
- "php": "8.0 - 8.4"
+ "nette/utils": "^4.0.6",
+ "php": "8.1 - 8.5"
},
"require-dev": {
- "jetbrains/phpstorm-attributes": "dev-master",
+ "jetbrains/phpstorm-attributes": "^1.2",
"nette/tester": "^2.4",
- "nikic/php-parser": "^4.18 || ^5.0",
- "phpstan/phpstan": "^1.0",
+ "nikic/php-parser": "^5.0",
+ "phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.8"
},
"suggest": {
@@ -1025,10 +1009,13 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.1-dev"
+ "dev-master": "4.2-dev"
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -1049,7 +1036,7 @@
"homepage": "https://nette.org/contributors"
}
],
- "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.3 features.",
+ "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.5 features.",
"homepage": "https://nette.org",
"keywords": [
"code",
@@ -1059,42 +1046,44 @@
],
"support": {
"issues": "https://github.com/nette/php-generator/issues",
- "source": "https://github.com/nette/php-generator/tree/v4.1.6"
+ "source": "https://github.com/nette/php-generator/tree/v4.2.0"
},
- "time": "2024-09-10T09:31:55+00:00"
+ "time": "2025-08-06T18:24:31+00:00"
},
{
"name": "nette/robot-loader",
- "version": "v3.4.2",
+ "version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/nette/robot-loader.git",
- "reference": "970c8f82be98ec54180c88a468cd2b057855d993"
+ "reference": "805fb81376c24755d50bdb8bc69ca4db3def71d1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/robot-loader/zipball/970c8f82be98ec54180c88a468cd2b057855d993",
- "reference": "970c8f82be98ec54180c88a468cd2b057855d993",
+ "url": "https://api.github.com/repos/nette/robot-loader/zipball/805fb81376c24755d50bdb8bc69ca4db3def71d1",
+ "reference": "805fb81376c24755d50bdb8bc69ca4db3def71d1",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
- "nette/finder": "^2.5 || ^3.0",
- "nette/utils": "^3.0",
- "php": ">=7.1"
+ "nette/utils": "^4.0",
+ "php": "8.1 - 8.5"
},
"require-dev": {
- "nette/tester": "^2.0",
- "phpstan/phpstan": "^0.12",
- "tracy/tracy": "^2.3"
+ "nette/tester": "^2.4",
+ "phpstan/phpstan-nette": "^2.0@stable",
+ "tracy/tracy": "^2.9"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.4-dev"
+ "dev-master": "4.1-dev"
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -1126,41 +1115,45 @@
],
"support": {
"issues": "https://github.com/nette/robot-loader/issues",
- "source": "https://github.com/nette/robot-loader/tree/v3.4.2"
+ "source": "https://github.com/nette/robot-loader/tree/v4.1.0"
},
- "time": "2022-12-14T15:41:06+00:00"
+ "time": "2025-08-06T18:34:21+00:00"
},
{
- "name": "nette/safe-stream",
- "version": "v2.5.1",
+ "name": "nette/schema",
+ "version": "v1.3.3",
"source": {
"type": "git",
- "url": "https://github.com/nette/safe-stream.git",
- "reference": "96c57055927d0f2b4d0fe545896a7a0335adbeb5"
+ "url": "https://github.com/nette/schema.git",
+ "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/safe-stream/zipball/96c57055927d0f2b4d0fe545896a7a0335adbeb5",
- "reference": "96c57055927d0f2b4d0fe545896a7a0335adbeb5",
+ "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004",
+ "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "nette/utils": "^4.0",
+ "php": "8.1 - 8.5"
},
"require-dev": {
- "nette/tester": "^2.0",
- "phpstan/phpstan": "^0.12",
- "tracy/tracy": "^2.3"
+ "nette/tester": "^2.5.2",
+ "phpstan/phpstan-nette": "^2.0@stable",
+ "tracy/tracy": "^2.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.5-dev"
+ "dev-master": "1.3-dev"
}
},
"autoload": {
- "files": [
- "src/loader.php"
+ "psr-4": {
+ "Nette\\": "src"
+ },
+ "classmap": [
+ "src/"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -1179,52 +1172,63 @@
"homepage": "https://nette.org/contributors"
}
],
- "description": "Nette SafeStream: provides isolation for thread safe manipulation with files via native PHP functions.",
+ "description": "📐 Nette Schema: validating data structures against a given Schema.",
"homepage": "https://nette.org",
"keywords": [
- "atomic",
- "filesystem",
- "isolation",
- "nette",
- "safe",
- "thread safe"
+ "config",
+ "nette"
],
"support": {
- "issues": "https://github.com/nette/safe-stream/issues",
- "source": "https://github.com/nette/safe-stream/tree/v2.5.1"
+ "issues": "https://github.com/nette/schema/issues",
+ "source": "https://github.com/nette/schema/tree/v1.3.3"
},
- "time": "2022-12-12T17:17:33+00:00"
+ "time": "2025-10-30T22:57:59+00:00"
},
{
- "name": "nette/schema",
- "version": "v1.2.5",
+ "name": "nette/utils",
+ "version": "v4.0.9",
"source": {
"type": "git",
- "url": "https://github.com/nette/schema.git",
- "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a"
+ "url": "https://github.com/nette/utils.git",
+ "reference": "505a30ad386daa5211f08a318e47015b501cad30"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a",
- "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a",
+ "url": "https://api.github.com/repos/nette/utils/zipball/505a30ad386daa5211f08a318e47015b501cad30",
+ "reference": "505a30ad386daa5211f08a318e47015b501cad30",
"shasum": ""
},
"require": {
- "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0",
- "php": "7.1 - 8.3"
+ "php": "8.0 - 8.5"
+ },
+ "conflict": {
+ "nette/finder": "<3",
+ "nette/schema": "<1.2.2"
},
"require-dev": {
- "nette/tester": "^2.3 || ^2.4",
- "phpstan/phpstan-nette": "^1.0",
- "tracy/tracy": "^2.7"
+ "jetbrains/phpstorm-attributes": "^1.2",
+ "nette/tester": "^2.5",
+ "phpstan/phpstan-nette": "^2.0@stable",
+ "tracy/tracy": "^2.9"
+ },
+ "suggest": {
+ "ext-gd": "to use Image",
+ "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
+ "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
+ "ext-json": "to use Nette\\Utils\\Json",
+ "ext-mbstring": "to use Strings::lower() etc...",
+ "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -1245,173 +1249,149 @@
"homepage": "https://nette.org/contributors"
}
],
- "description": "📐 Nette Schema: validating data structures against a given Schema.",
+ "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
"homepage": "https://nette.org",
"keywords": [
- "config",
- "nette"
+ "array",
+ "core",
+ "datetime",
+ "images",
+ "json",
+ "nette",
+ "paginator",
+ "password",
+ "slugify",
+ "string",
+ "unicode",
+ "utf-8",
+ "utility",
+ "validation"
],
"support": {
- "issues": "https://github.com/nette/schema/issues",
- "source": "https://github.com/nette/schema/tree/v1.2.5"
+ "issues": "https://github.com/nette/utils/issues",
+ "source": "https://github.com/nette/utils/tree/v4.0.9"
},
- "time": "2023-10-05T20:37:59+00:00"
+ "time": "2025-10-31T00:45:47+00:00"
},
{
- "name": "nette/tokenizer",
- "version": "v3.1.1",
+ "name": "psr/http-client",
+ "version": "1.0.3",
"source": {
"type": "git",
- "url": "https://github.com/nette/tokenizer.git",
- "reference": "370c5e4e2e10eb4d3e406d3a90526f821de98190"
+ "url": "https://github.com/php-fig/http-client.git",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/tokenizer/zipball/370c5e4e2e10eb4d3e406d3a90526f821de98190",
- "reference": "370c5e4e2e10eb4d3e406d3a90526f821de98190",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
"shasum": ""
},
"require": {
- "php": ">=7.1"
- },
- "require-dev": {
- "nette/tester": "~2.0",
- "phpstan/phpstan": "^0.12",
- "tracy/tracy": "^2.3"
+ "php": "^7.0 || ^8.0",
+ "psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "1.0.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Psr\\Http\\Client\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause",
- "GPL-2.0-only",
- "GPL-3.0-only"
+ "MIT"
],
"authors": [
{
- "name": "David Grudl",
- "homepage": "https://davidgrudl.com"
- },
- {
- "name": "Nette Community",
- "homepage": "https://nette.org/contributors"
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
}
],
- "description": "Nette Tokenizer",
- "homepage": "https://nette.org",
+ "description": "Common interface for HTTP clients",
+ "homepage": "https://github.com/php-fig/http-client",
+ "keywords": [
+ "http",
+ "http-client",
+ "psr",
+ "psr-18"
+ ],
"support": {
- "source": "https://github.com/nette/tokenizer/tree/v3.1.1"
+ "source": "https://github.com/php-fig/http-client"
},
- "abandoned": true,
- "time": "2022-02-09T22:28:54+00:00"
+ "time": "2023-09-23T14:17:50+00:00"
},
{
- "name": "nette/utils",
- "version": "v3.2.10",
+ "name": "psr/http-factory",
+ "version": "1.1.0",
"source": {
"type": "git",
- "url": "https://github.com/nette/utils.git",
- "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2"
+ "url": "https://github.com/php-fig/http-factory.git",
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/utils/zipball/a4175c62652f2300c8017fb7e640f9ccb11648d2",
- "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
- "php": ">=7.2 <8.4"
- },
- "conflict": {
- "nette/di": "<3.0.6"
- },
- "require-dev": {
- "jetbrains/phpstorm-attributes": "dev-master",
- "nette/tester": "~2.0",
- "phpstan/phpstan": "^1.0",
- "tracy/tracy": "^2.3"
- },
- "suggest": {
- "ext-gd": "to use Image",
- "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
- "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
- "ext-json": "to use Nette\\Utils\\Json",
- "ext-mbstring": "to use Strings::lower() etc...",
- "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
- "ext-xml": "to use Strings::length() etc. when mbstring is not available"
+ "php": ">=7.1",
+ "psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "1.0.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause",
- "GPL-2.0-only",
- "GPL-3.0-only"
+ "MIT"
],
"authors": [
{
- "name": "David Grudl",
- "homepage": "https://davidgrudl.com"
- },
- {
- "name": "Nette Community",
- "homepage": "https://nette.org/contributors"
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
}
],
- "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
- "homepage": "https://nette.org",
+ "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
- "array",
- "core",
- "datetime",
- "images",
- "json",
- "nette",
- "paginator",
- "password",
- "slugify",
- "string",
- "unicode",
- "utf-8",
- "utility",
- "validation"
+ "factory",
+ "http",
+ "message",
+ "psr",
+ "psr-17",
+ "psr-7",
+ "request",
+ "response"
],
"support": {
- "issues": "https://github.com/nette/utils/issues",
- "source": "https://github.com/nette/utils/tree/v3.2.10"
+ "source": "https://github.com/php-fig/http-factory"
},
- "time": "2023-07-30T15:38:18+00:00"
+ "time": "2024-04-15T12:06:14+00:00"
},
{
"name": "psr/http-message",
- "version": "1.1",
+ "version": "2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
- "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
- "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
@@ -1420,7 +1400,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
@@ -1435,7 +1415,7 @@
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
@@ -1449,9 +1429,9 @@
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-message/tree/1.1"
+ "source": "https://github.com/php-fig/http-message/tree/2.0"
},
- "time": "2023-04-04T09:50:52+00:00"
+ "time": "2023-04-04T09:54:51+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -1575,16 +1555,16 @@
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.5.0",
+ "version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
@@ -1592,12 +1572,12 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "3.5-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
}
},
"autoload": {
@@ -1622,7 +1602,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
@@ -1638,11 +1618,11 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
@@ -1666,8 +1646,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1701,7 +1681,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
@@ -1712,6 +1692,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -1721,16 +1705,16 @@
},
{
"name": "symfony/polyfill-iconv",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
- "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956"
+ "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956",
- "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956",
+ "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa",
+ "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa",
"shasum": ""
},
"require": {
@@ -1745,8 +1729,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1781,7 +1765,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-iconv/tree/v1.33.0"
},
"funding": [
{
@@ -1792,25 +1776,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2024-09-17T14:58:18+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
- "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773"
+ "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773",
- "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3",
+ "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3",
"shasum": ""
},
"require": {
@@ -1823,8 +1811,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1864,7 +1852,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0"
},
"funding": [
{
@@ -1875,16 +1863,20 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2024-09-10T14:38:51+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -1905,8 +1897,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1945,7 +1937,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
},
"funding": [
{
@@ -1956,6 +1948,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -1965,19 +1961,20 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
+ "ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
@@ -1989,8 +1986,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -2025,7 +2022,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
@@ -2036,25 +2033,2017 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-12-23T08:48:59+00:00"
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v7.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/yaml.git",
+ "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc",
+ "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "symfony/console": "<6.4"
+ },
+ "require-dev": {
+ "symfony/console": "^6.4|^7.0"
+ },
+ "bin": [
+ "Resources/bin/yaml-lint"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Yaml\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Loads and dumps YAML files",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/yaml/tree/v7.3.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-27T09:00:46+00:00"
+ },
+ {
+ "name": "tracy/tracy",
+ "version": "v2.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/tracy.git",
+ "reference": "eec57bcf2ff11d79f519a19da9d7ae1e2c63c42e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/tracy/zipball/eec57bcf2ff11d79f519a19da9d7ae1e2c63c42e",
+ "reference": "eec57bcf2ff11d79f519a19da9d7ae1e2c63c42e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-session": "*",
+ "php": "8.2 - 8.5"
+ },
+ "conflict": {
+ "nette/di": "<3.0"
+ },
+ "require-dev": {
+ "latte/latte": "^2.5 || ^3.0",
+ "nette/di": "^3.0",
+ "nette/http": "^3.0",
+ "nette/mail": "^3.0 || ^4.0",
+ "nette/tester": "^2.2",
+ "nette/utils": "^3.0 || ^4.0",
+ "phpstan/phpstan-nette": "^2.0@stable",
+ "psr/log": "^1.0 || ^2.0 || ^3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.11-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Tracy/functions.php"
+ ],
+ "psr-4": {
+ "Tracy\\": "src"
+ },
+ "classmap": [
+ "src"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.",
+ "homepage": "https://tracy.nette.org",
+ "keywords": [
+ "Xdebug",
+ "debug",
+ "debugger",
+ "nette",
+ "profiler"
+ ],
+ "support": {
+ "issues": "https://github.com/nette/tracy/issues",
+ "source": "https://github.com/nette/tracy/tree/v2.11.0"
+ },
+ "time": "2025-10-31T00:12:50+00:00"
+ },
+ {
+ "name": "wildbit/postmark-php",
+ "version": "v7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ActiveCampaign/postmark-php.git",
+ "reference": "f0a53b741833d4b2d1a3827c0bd66e70f4d26d62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ActiveCampaign/postmark-php/zipball/f0a53b741833d4b2d1a3827c0bd66e70f4d26d62",
+ "reference": "f0a53b741833d4b2d1a3827c0bd66e70f4d26d62",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/guzzle": "^7.8",
+ "php": "~8.1 || ~8.2|| ~8.3 || ~8.4"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.40",
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Postmark\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "The officially supported client for Postmark (http://postmarkapp.com)",
+ "support": {
+ "issues": "https://github.com/ActiveCampaign/postmark-php/issues",
+ "source": "https://github.com/ActiveCampaign/postmark-php/tree/v7.0.0"
+ },
+ "time": "2025-07-11T11:40:30+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "clue/ndjson-react",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-ndjson.git",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\NDJson\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-ndjson",
+ "keywords": [
+ "NDJSON",
+ "json",
+ "jsonlines",
+ "newline",
+ "reactphp",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-ndjson/issues",
+ "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-12-23T10:58:28+00:00"
+ },
+ {
+ "name": "composer/pcre",
+ "version": "3.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/pcre.git",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<1.11.10"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.12 || ^2",
+ "phpstan/phpstan-strict-rules": "^1 || ^2",
+ "phpunit/phpunit": "^8 || ^9"
+ },
+ "type": "library",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Pcre\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+ "keywords": [
+ "PCRE",
+ "preg",
+ "regex",
+ "regular expression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/pcre/issues",
+ "source": "https://github.com/composer/pcre/tree/3.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-11-12T16:29:46+00:00"
+ },
+ {
+ "name": "composer/semver",
+ "version": "3.4.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.11",
+ "symfony/phpunit-bridge": "^3 || ^7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/semver/issues",
+ "source": "https://github.com/composer/semver/tree/3.4.4"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ }
+ ],
+ "time": "2025-08-20T19:15:30+00:00"
+ },
+ {
+ "name": "composer/xdebug-handler",
+ "version": "3.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "shasum": ""
+ },
+ "require": {
+ "composer/pcre": "^1 || ^2 || ^3",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Stevenson",
+ "email": "john-stevenson@blueyonder.co.uk"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/xdebug-handler/issues",
+ "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-05-06T16:37:16+00:00"
+ },
+ {
+ "name": "evenement/evenement",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9 || ^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Evenement\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ }
+ ],
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": [
+ "event-dispatcher",
+ "event-emitter"
+ ],
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/v3.0.2"
+ },
+ "time": "2023-08-08T05:53:35+00:00"
+ },
+ {
+ "name": "fidry/cpu-core-counter",
+ "version": "1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theofidry/cpu-core-counter.git",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "fidry/makefile": "^0.2.0",
+ "fidry/php-cs-fixer-config": "^1.1.2",
+ "phpstan/extension-installer": "^1.2.0",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-deprecation-rules": "^2.0.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
+ "phpunit/phpunit": "^8.5.31 || ^9.5.26",
+ "webmozarts/strict-phpunit": "^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Fidry\\CpuCoreCounter\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Théo FIDRY",
+ "email": "theo.fidry@gmail.com"
+ }
+ ],
+ "description": "Tiny utility to get the number of CPU cores.",
+ "keywords": [
+ "CPU",
+ "core"
+ ],
+ "support": {
+ "issues": "https://github.com/theofidry/cpu-core-counter/issues",
+ "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theofidry",
+ "type": "github"
+ }
+ ],
+ "time": "2025-08-14T07:29:31+00:00"
+ },
+ {
+ "name": "friendsofphp/php-cs-fixer",
+ "version": "v3.90.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
+ "reference": "ad732c2e9299c9743f9c55ae53cc0e7642ab1155"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ad732c2e9299c9743f9c55ae53cc0e7642ab1155",
+ "reference": "ad732c2e9299c9743f9c55ae53cc0e7642ab1155",
+ "shasum": ""
+ },
+ "require": {
+ "clue/ndjson-react": "^1.3",
+ "composer/semver": "^3.4",
+ "composer/xdebug-handler": "^3.0.5",
+ "ext-filter": "*",
+ "ext-hash": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "fidry/cpu-core-counter": "^1.3",
+ "php": "^7.4 || ^8.0",
+ "react/child-process": "^0.6.6",
+ "react/event-loop": "^1.5",
+ "react/socket": "^1.16",
+ "react/stream": "^1.4",
+ "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
+ "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/polyfill-mbstring": "^1.33",
+ "symfony/polyfill-php80": "^1.33",
+ "symfony/polyfill-php81": "^1.33",
+ "symfony/polyfill-php84": "^1.33",
+ "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0",
+ "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "facile-it/paraunit": "^1.3.1 || ^2.7",
+ "infection/infection": "^0.31.0",
+ "justinrainbow/json-schema": "^6.5",
+ "keradus/cli-executor": "^2.2",
+ "mikey179/vfsstream": "^1.6.12",
+ "php-coveralls/php-coveralls": "^2.9",
+ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
+ "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
+ "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34",
+ "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2 || ^8.0",
+ "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2 || ^8.0"
+ },
+ "suggest": {
+ "ext-dom": "For handling output formats in XML",
+ "ext-mbstring": "For handling non-UTF8 characters."
+ },
+ "bin": [
+ "php-cs-fixer"
+ ],
+ "type": "application",
+ "autoload": {
+ "psr-4": {
+ "PhpCsFixer\\": "src/"
+ },
+ "exclude-from-classmap": [
+ "src/Fixer/Internal/*"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Dariusz Rumiński",
+ "email": "dariusz.ruminski@gmail.com"
+ }
+ ],
+ "description": "A tool to automatically fix PHP code style",
+ "keywords": [
+ "Static code analysis",
+ "fixer",
+ "standards",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
+ "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.90.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/keradus",
+ "type": "github"
+ }
+ ],
+ "time": "2025-11-20T15:15:16+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "psr/event-dispatcher",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/event-dispatcher.git",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\EventDispatcher\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Standard interfaces for event handling.",
+ "keywords": [
+ "events",
+ "psr",
+ "psr-14"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/event-dispatcher/issues",
+ "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+ },
+ "time": "2019-01-08T18:20:26+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
+ },
+ {
+ "name": "react/cache",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/cache.git",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, Promise-based cache interface for ReactPHP",
+ "keywords": [
+ "cache",
+ "caching",
+ "promise",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/cache/issues",
+ "source": "https://github.com/reactphp/cache/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2022-11-30T15:59:55+00:00"
+ },
+ {
+ "name": "react/child-process",
+ "version": "v0.6.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/child-process.git",
+ "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159",
+ "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/socket": "^1.16",
+ "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\ChildProcess\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven library for executing child processes with ReactPHP.",
+ "keywords": [
+ "event-driven",
+ "process",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/child-process/issues",
+ "source": "https://github.com/reactphp/child-process/tree/v0.6.6"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-01-01T16:37:48+00:00"
+ },
+ {
+ "name": "react/dns",
+ "version": "v1.14.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3",
+ "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.7 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3 || ^2",
+ "react/promise-timer": "^1.11"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Dns\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async DNS resolver for ReactPHP",
+ "keywords": [
+ "async",
+ "dns",
+ "dns-resolver",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/dns/issues",
+ "source": "https://github.com/reactphp/dns/tree/v1.14.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-11-18T19:34:28+00:00"
+ },
+ {
+ "name": "react/event-loop",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
+ "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "suggest": {
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\EventLoop\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": [
+ "asynchronous",
+ "event-loop"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/event-loop/issues",
+ "source": "https://github.com/reactphp/event-loop/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-11-17T20:46:25+00:00"
+ },
+ {
+ "name": "react/promise",
+ "version": "v3.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "1.12.28 || 1.4.10",
+ "phpunit/phpunit": "^9.6 || ^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v3.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-08-19T18:57:03+00:00"
+ },
+ {
+ "name": "react/socket",
+ "version": "v1.17.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08",
+ "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.13",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.6 || ^1.2.1",
+ "react/stream": "^1.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3.3 || ^2",
+ "react/promise-stream": "^1.4",
+ "react/promise-timer": "^1.11"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Socket\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "async",
+ "reactphp",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/socket/issues",
+ "source": "https://github.com/reactphp/socket/tree/v1.17.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-11-19T20:47:34+00:00"
+ },
+ {
+ "name": "react/stream",
+ "version": "v1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2"
+ },
+ "require-dev": {
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": [
+ "event-driven",
+ "io",
+ "non-blocking",
+ "pipe",
+ "reactphp",
+ "readable",
+ "stream",
+ "writable"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/stream/issues",
+ "source": "https://github.com/reactphp/stream/tree/v1.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-06-11T12:45:25+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "6.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544",
+ "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0",
+ "symfony/process": "^4.2 || ^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:53:05+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v7.3.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
+ "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/string": "^7.2"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<6.4",
+ "symfony/dotenv": "<6.4",
+ "symfony/event-dispatcher": "<6.4",
+ "symfony/lock": "<6.4",
+ "symfony/process": "<6.4"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0|2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/event-dispatcher": "^6.4|^7.0",
+ "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/lock": "^6.4|^7.0",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/stopwatch": "^6.4|^7.0",
+ "symfony/var-dumper": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases the creation of beautiful and testable command line interfaces",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cli",
+ "command-line",
+ "console",
+ "terminal"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/console/tree/v7.3.6"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-11-04T01:21:42+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v7.3.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher.git",
+ "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
+ "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/event-dispatcher-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<6.4",
+ "symfony/service-contracts": "<2.5"
+ },
+ "provide": {
+ "psr/event-dispatcher-implementation": "1.0",
+ "symfony/event-dispatcher-implementation": "2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/error-handler": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/stopwatch": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-13T11:49:31+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher-contracts.git",
+ "reference": "59eb412e93815df44f05f342958efa9f46b1e586"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
+ "reference": "59eb412e93815df44f05f342958efa9f46b1e586",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/event-dispatcher": "^1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\EventDispatcher\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to dispatching event",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v7.3.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a",
+ "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "require-dev": {
+ "symfony/process": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v7.3.6"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-11-05T09:52:27+00:00"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v7.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "symfony/filesystem": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Finds files and directories via an intuitive fluent interface",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/finder/tree/v7.3.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-10-15T18:45:57+00:00"
+ },
+ {
+ "name": "symfony/options-resolver",
+ "version": "v7.3.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/options-resolver.git",
+ "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
+ "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\OptionsResolver\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an improved replacement for the array_replace PHP function",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "config",
+ "configuration",
+ "options"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/options-resolver/tree/v7.3.3"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-05T10:16:07+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-grapheme",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's grapheme_* functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "grapheme",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2025-06-27T09:58:17+00:00"
},
{
"name": "symfony/polyfill-php80",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
- "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"shasum": ""
},
"require": {
@@ -2063,8 +4052,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -2105,7 +4094,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
},
"funding": [
{
@@ -2116,73 +4105,50 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2025-01-02T08:10:11+00:00"
},
{
- "name": "symfony/translation",
- "version": "v5.4.44",
+ "name": "symfony/polyfill-php81",
+ "version": "v1.33.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/translation.git",
- "reference": "6fed3a20b5b87ee9cdd9dacf545922b8fd475921"
+ "url": "https://github.com/symfony/polyfill-php81.git",
+ "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/6fed3a20b5b87ee9cdd9dacf545922b8fd475921",
- "reference": "6fed3a20b5b87ee9cdd9dacf545922b8fd475921",
+ "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+ "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php80": "^1.16",
- "symfony/translation-contracts": "^2.3"
- },
- "conflict": {
- "symfony/config": "<4.4",
- "symfony/console": "<5.3",
- "symfony/dependency-injection": "<5.0",
- "symfony/http-kernel": "<5.0",
- "symfony/twig-bundle": "<5.0",
- "symfony/yaml": "<4.4"
- },
- "provide": {
- "symfony/translation-implementation": "2.3"
- },
- "require-dev": {
- "psr/log": "^1|^2|^3",
- "symfony/config": "^4.4|^5.0|^6.0",
- "symfony/console": "^5.4|^6.0",
- "symfony/dependency-injection": "^5.0|^6.0",
- "symfony/finder": "^4.4|^5.0|^6.0",
- "symfony/http-client-contracts": "^1.1|^2.0|^3.0",
- "symfony/http-kernel": "^5.0|^6.0",
- "symfony/intl": "^4.4|^5.0|^6.0",
- "symfony/polyfill-intl-icu": "^1.21",
- "symfony/service-contracts": "^1.1.2|^2|^3",
- "symfony/yaml": "^4.4|^5.0|^6.0"
- },
- "suggest": {
- "psr/log-implementation": "To use logging capability in translator",
- "symfony/config": "",
- "symfony/yaml": ""
+ "php": ">=7.2"
},
"type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
"autoload": {
"files": [
- "Resources/functions.php"
+ "bootstrap.php"
],
"psr-4": {
- "Symfony\\Component\\Translation\\": ""
+ "Symfony\\Polyfill\\Php81\\": ""
},
- "exclude-from-classmap": [
- "/Tests/"
+ "classmap": [
+ "Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -2191,18 +4157,24 @@
],
"authors": [
{
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Provides tools to internationalize your application",
+ "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
"support": {
- "source": "https://github.com/symfony/translation/tree/v5.4.44"
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0"
},
"funding": [
{
@@ -2213,47 +4185,51 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-15T08:12:35+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
- "name": "symfony/translation-contracts",
- "version": "v2.5.3",
+ "name": "symfony/polyfill-php84",
+ "version": "v1.33.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/translation-contracts.git",
- "reference": "b0073a77ac0b7ea55131020e87b1e3af540f4664"
+ "url": "https://github.com/symfony/polyfill-php84.git",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b0073a77ac0b7ea55131020e87b1e3af540f4664",
- "reference": "b0073a77ac0b7ea55131020e87b1e3af540f4664",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
"shasum": ""
},
"require": {
- "php": ">=7.2.5"
- },
- "suggest": {
- "symfony/translation-implementation": ""
+ "php": ">=7.2"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
"psr-4": {
- "Symfony\\Contracts\\Translation\\": ""
- }
+ "Symfony\\Polyfill\\Php84\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -2269,18 +4245,16 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Generic abstractions related to translation",
+ "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
],
"support": {
- "source": "https://github.com/symfony/translation-contracts/tree/v2.5.3"
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0"
},
"funding": [
{
@@ -2291,48 +4265,38 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-01-23T13:51:25+00:00"
+ "time": "2025-06-24T13:30:11+00:00"
},
{
- "name": "symfony/yaml",
- "version": "v5.4.44",
+ "name": "symfony/process",
+ "version": "v7.3.4",
"source": {
"type": "git",
- "url": "https://github.com/symfony/yaml.git",
- "reference": "7025b964f123bbf1896d7563db6ec7f1f63e918a"
+ "url": "https://github.com/symfony/process.git",
+ "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/7025b964f123bbf1896d7563db6ec7f1f63e918a",
- "reference": "7025b964f123bbf1896d7563db6ec7f1f63e918a",
+ "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b",
+ "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-ctype": "^1.8"
- },
- "conflict": {
- "symfony/console": "<5.3"
- },
- "require-dev": {
- "symfony/console": "^5.3|^6.0"
- },
- "suggest": {
- "symfony/console": "For validating YAML files using the lint command"
+ "php": ">=8.2"
},
- "bin": [
- "Resources/bin/yaml-lint"
- ],
"type": "library",
"autoload": {
"psr-4": {
- "Symfony\\Component\\Yaml\\": ""
+ "Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
@@ -2352,10 +4316,10 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Loads and dumps YAML files",
+ "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/yaml/tree/v5.4.44"
+ "source": "https://github.com/symfony/process/tree/v7.3.4"
},
"funding": [
{
@@ -2366,136 +4330,265 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-16T14:36:56+00:00"
+ "time": "2025-09-11T10:12:26+00:00"
},
{
- "name": "tracy/tracy",
- "version": "v2.10.8",
+ "name": "symfony/service-contracts",
+ "version": "v3.6.1",
"source": {
"type": "git",
- "url": "https://github.com/nette/tracy.git",
- "reference": "0e0f3312708fb9c179a92072ebacc24aeee7e2e8"
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/tracy/zipball/0e0f3312708fb9c179a92072ebacc24aeee7e2e8",
- "reference": "0e0f3312708fb9c179a92072ebacc24aeee7e2e8",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
- "ext-json": "*",
- "ext-session": "*",
- "php": "8.0 - 8.4"
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
- "nette/di": "<3.0"
- },
- "require-dev": {
- "latte/latte": "^2.5 || ^3.0",
- "nette/di": "^3.0",
- "nette/http": "^3.0",
- "nette/mail": "^3.0 || ^4.0",
- "nette/tester": "^2.2",
- "nette/utils": "^3.0 || ^4.0",
- "phpstan/phpstan": "^1.0",
- "psr/log": "^1.0 || ^2.0 || ^3.0"
+ "ext-psr": "<1.1|>=2"
},
"type": "library",
"extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
"branch-alias": {
- "dev-master": "2.10-dev"
+ "dev-main": "3.6-dev"
}
},
"autoload": {
- "files": [
- "src/Tracy/functions.php"
- ],
- "classmap": [
- "src"
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "David Grudl",
- "homepage": "https://davidgrudl.com"
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
},
{
- "name": "Nette Community",
- "homepage": "https://nette.org/contributors"
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
}
],
- "description": "😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.",
- "homepage": "https://tracy.nette.org",
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
"keywords": [
- "Xdebug",
- "debug",
- "debugger",
- "nette",
- "profiler"
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
],
"support": {
- "issues": "https://github.com/nette/tracy/issues",
- "source": "https://github.com/nette/tracy/tree/v2.10.8"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
- "time": "2024-08-07T02:04:53+00:00"
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-15T11:30:57+00:00"
},
{
- "name": "wildbit/postmark-php",
- "version": "v4.0.5",
+ "name": "symfony/stopwatch",
+ "version": "v7.3.0",
"source": {
"type": "git",
- "url": "https://github.com/ActiveCampaign/postmark-php.git",
- "reference": "b71efba061de7cf7e1f853d211b1c5edce4e3c5b"
+ "url": "https://github.com/symfony/stopwatch.git",
+ "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd",
+ "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/service-contracts": "^2.5|^3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Stopwatch\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a way to profile code",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/stopwatch/tree/v7.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-02-24T10:49:57+00:00"
+ },
+ {
+ "name": "symfony/string",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/string.git",
+ "reference": "f96476035142921000338bad71e5247fbc138872"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ActiveCampaign/postmark-php/zipball/b71efba061de7cf7e1f853d211b1c5edce4e3c5b",
- "reference": "b71efba061de7cf7e1f853d211b1c5edce4e3c5b",
+ "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872",
+ "reference": "f96476035142921000338bad71e5247fbc138872",
"shasum": ""
},
"require": {
- "guzzlehttp/guzzle": "^6.0|^7.0",
- "php": ">=7.0.0"
+ "php": ">=8.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-normalizer": "~1.0",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "phpunit/phpunit": "^6.0.0"
+ "symfony/emoji": "^7.1",
+ "symfony/http-client": "^6.4|^7.0",
+ "symfony/intl": "^6.4|^7.0",
+ "symfony/translation-contracts": "^2.5|^3.0",
+ "symfony/var-exporter": "^6.4|^7.0"
},
"type": "library",
"autoload": {
- "psr-0": {
- "Postmark\\": "src/"
- }
+ "files": [
+ "Resources/functions.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\String\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "description": "The officially supported client for Postmark (http://postmarkapp.com)",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "grapheme",
+ "i18n",
+ "string",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
"support": {
- "issues": "https://github.com/ActiveCampaign/postmark-php/issues",
- "source": "https://github.com/ActiveCampaign/postmark-php/tree/v4.0.5"
+ "source": "https://github.com/symfony/string/tree/v7.3.4"
},
- "time": "2023-02-03T15:00:17+00:00"
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T14:36:48+00:00"
}
],
- "packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": "~7.3||~8.1"
+ "php": "~8.2"
},
"platform-dev": {},
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.9.0"
}
diff --git a/htdocs/index.php b/htdocs/index.php
index a6b22cc..c6d65ee 100644
--- a/htdocs/index.php
+++ b/htdocs/index.php
@@ -1,4 +1,6 @@
-