diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100644 index 000000000..6631f0702 --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,10 @@ +FROM php:8.4-cli + +COPY --from=ghcr.io/php/pie:bin /pie /usr/bin/pie + +RUN apt update && apt install -y git + +RUN docker-php-ext-configure pcntl --enable-pcntl \ + && docker-php-ext-install pcntl \ + && pie install arnaud-lb/inotify + diff --git a/composer.lock b/composer.lock index c61e357a5..9ac3b6072 100644 --- a/composer.lock +++ b/composer.lock @@ -6,6 +6,69 @@ ], "content-hash": "36cc19c043cd4e53ba6d7cff20e23b9d", "packages": [ + { + "name": "cboden/ratchet", + "version": "v0.4.4", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/Ratchet.git", + "reference": "5012dc954541b40c5599d286fd40653f5716a38f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/Ratchet/zipball/5012dc954541b40c5599d286fd40653f5716a38f", + "reference": "5012dc954541b40c5599d286fd40653f5716a38f", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^1.7|^2.0", + "php": ">=5.4.2", + "ratchet/rfc6455": "^0.3.1", + "react/event-loop": ">=0.4", + "react/socket": "^1.0 || ^0.8 || ^0.7 || ^0.6 || ^0.5", + "symfony/http-foundation": "^2.6|^3.0|^4.0|^5.0|^6.0", + "symfony/routing": "^2.6|^3.0|^4.0|^5.0|^6.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ratchet\\": "src/Ratchet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "role": "Developer" + }, + { + "name": "Matt Bonneau", + "role": "Developer" + } + ], + "description": "PHP WebSocket library", + "homepage": "http://socketo.me", + "keywords": [ + "Ratchet", + "WebSockets", + "server", + "sockets", + "websocket" + ], + "support": { + "chat": "https://gitter.im/reactphp/reactphp", + "issues": "https://github.com/ratchetphp/Ratchet/issues", + "source": "https://github.com/ratchetphp/Ratchet/tree/v0.4.4" + }, + "time": "2021-12-14T00:20:41+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.2", @@ -206,6 +269,225 @@ ], "time": "2024-02-05T11:56:58+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": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "21dc724a0583619cd1652f673303492272778051" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", + "shasum": "" + }, + "require": { + "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": { + "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": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "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", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.8.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-08-23T21:21:41+00:00" + }, { "name": "jawira/plantuml-encoding", "version": "v1.1.0", @@ -449,40 +731,42 @@ }, { "name": "league/csv", - "version": "9.15.0", + "version": "9.24.1", "source": { "type": "git", "url": "https://github.com/thephpleague/csv.git", - "reference": "fa7e2441c0bc9b2360f4314fd6c954f7ff40d435" + "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/fa7e2441c0bc9b2360f4314fd6c954f7ff40d435", - "reference": "fa7e2441c0bc9b2360f4314fd6c954f7ff40d435", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/e0221a3f16aa2a823047d59fab5809d552e29bc8", + "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8", "shasum": "" }, "require": { "ext-filter": "*", - "ext-json": "*", - "ext-mbstring": "*", "php": "^8.1.2" }, "require-dev": { - "doctrine/collections": "^2.1.4", "ext-dom": "*", "ext-xdebug": "*", - "friendsofphp/php-cs-fixer": "^v3.22.0", - "phpbench/phpbench": "^1.2.15", - "phpstan/phpstan": "^1.10.57", - "phpstan/phpstan-deprecation-rules": "^1.1.4", - "phpstan/phpstan-phpunit": "^1.3.15", - "phpstan/phpstan-strict-rules": "^1.5.2", - "phpunit/phpunit": "^10.5.9", - "symfony/var-dumper": "^6.4.2" + "friendsofphp/php-cs-fixer": "^3.75.0", + "phpbench/phpbench": "^1.4.1", + "phpstan/phpstan": "^1.12.27", + "phpstan/phpstan-deprecation-rules": "^1.2.1", + "phpstan/phpstan-phpunit": "^1.4.2", + "phpstan/phpstan-strict-rules": "^1.6.2", + "phpunit/phpunit": "^10.5.16 || ^11.5.22", + "symfony/var-dumper": "^6.4.8 || ^7.3.0" }, "suggest": { "ext-dom": "Required to use the XMLConverter and the HTMLConverter classes", - "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters", + "ext-mbstring": "Needed to ease transcoding CSV using mb stream filters", + "ext-mysqli": "Requiered to use the package with the MySQLi extension", + "ext-pdo": "Required to use the package with the PDO extension", + "ext-pgsql": "Requiered to use the package with the PgSQL extension", + "ext-sqlite3": "Required to use the package with the SQLite3 extension" }, "type": "library", "extra": { @@ -534,20 +818,20 @@ "type": "github" } ], - "time": "2024-02-20T20:00:00+00:00" + "time": "2025-06-25T14:53:51+00:00" }, { "name": "league/flysystem", - "version": "3.29.1", + "version": "3.30.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319" + "reference": "2203e3151755d874bb2943649dae1eb8533ac93e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319", - "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e", + "reference": "2203e3151755d874bb2943649dae1eb8533ac93e", "shasum": "" }, "require": { @@ -571,13 +855,13 @@ "composer/semver": "^3.0", "ext-fileinfo": "*", "ext-ftp": "*", - "ext-mongodb": "^1.3", + "ext-mongodb": "^1.3|^2", "ext-zip": "*", "friendsofphp/php-cs-fixer": "^3.5", "google/cloud-storage": "^1.23", "guzzlehttp/psr7": "^2.6", "microsoft/azure-storage-blob": "^1.1", - "mongodb/mongodb": "^1.2", + "mongodb/mongodb": "^1.2|^2", "phpseclib/phpseclib": "^3.0.36", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.5.11|^10.0", @@ -615,22 +899,22 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.29.1" + "source": "https://github.com/thephpleague/flysystem/tree/3.30.0" }, - "time": "2024-10-08T08:58:34+00:00" + "time": "2025-06-25T13:29:59+00:00" }, { "name": "league/flysystem-local", - "version": "3.29.0", + "version": "3.30.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27" + "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27", - "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/6691915f77c7fb69adfb87dcd550052dc184ee10", + "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10", "shasum": "" }, "require": { @@ -664,9 +948,9 @@ "local" ], "support": { - "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.0" }, - "time": "2024-08-09T21:24:39+00:00" + "time": "2025-05-21T10:34:19+00:00" }, { "name": "league/mime-type-detection", @@ -955,16 +1239,16 @@ }, { "name": "masterminds/html5", - "version": "2.9.0", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + "reference": "fcf91eb64359852f00d921887b219479b4f21251" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", "shasum": "" }, "require": { @@ -1016,22 +1300,22 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" }, - "time": "2024-03-31T07:05:07+00:00" + "time": "2025-07-25T09:04:22+00:00" }, { "name": "monolog/monolog", - "version": "3.6.0", + "version": "3.9.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654" + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", - "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", "shasum": "" }, "require": { @@ -1051,12 +1335,14 @@ "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpstan/phpstan": "^1.9", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.5.17", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", "predis/predis": "^1.1 || ^2", - "ruflin/elastica": "^7", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" }, @@ -1107,7 +1393,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.6.0" + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" }, "funding": [ { @@ -1119,7 +1405,7 @@ "type": "tidelift" } ], - "time": "2024-04-12T21:02:21+00:00" + "time": "2025-03-24T10:02:05+00:00" }, { "name": "nette/schema", @@ -1430,13 +1716,17 @@ "dist": { "type": "path", "url": "./packages/guides-cli", - "reference": "01b63176c171294709d3f7b71eb35d3a02d40d21" + "reference": "783ce201a182ac9b920edc873389d9027a56f050" }, "require": { + "cboden/ratchet": "0.4.x@dev", + "league/mime-type-detection": "^1.16", "monolog/monolog": "^3.0", "php": "^8.1", "phpdocumentor/guides": "^1.0 || ^2.0", "phpdocumentor/guides-restructured-text": "^1.0 || ^2.0", + "react/http": "^v1.11", + "react/socket": "^v1.16", "symfony/config": "^5.4 || ^6.3 || ^7.0", "symfony/console": "^5.4 || ^6.3 || ^7.0", "symfony/dependency-injection": "^5.4 || ^6.3 || ^7.0", @@ -1926,16 +2216,16 @@ }, { "name": "psr/http-message", - "version": "2.0", + "version": "1.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "shasum": "" }, "require": { @@ -1944,7 +2234,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -1959,7 +2249,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "homepage": "http://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -1973,9 +2263,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" + "source": "https://github.com/php-fig/http-message/tree/1.1" }, - "time": "2023-04-04T09:54:51+00:00" + "time": "2023-04-04T09:50:52+00:00" }, { "name": "psr/log", @@ -2028,116 +2318,76 @@ "time": "2024-09-11T13:17:53+00:00" }, { - "name": "scrivo/highlight.php", - "version": "v9.18.1.10", + "name": "ralouphie/getallheaders", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/scrivo/highlight.php.git", - "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e" + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/850f4b44697a2552e892ffe71490ba2733c2fc6e", - "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "ext-json": "*", - "php": ">=5.4" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.7", - "sabberworm/php-css-parser": "^8.3", - "symfony/finder": "^2.8|^3.4|^5.4", - "symfony/var-dumper": "^2.8|^3.4|^5.4" - }, - "suggest": { - "ext-mbstring": "Allows highlighting code with unicode characters and supports language with unicode keywords" + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" }, "type": "library", "autoload": { "files": [ - "HighlightUtilities/functions.php" - ], - "psr-0": { - "Highlight\\": "", - "HighlightUtilities\\": "" - } + "src/getallheaders.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Geert Bergman", - "homepage": "http://www.scrivo.org/", - "role": "Project Author" - }, - { - "name": "Vladimir Jimenez", - "homepage": "https://allejo.io", - "role": "Maintainer" - }, - { - "name": "Martin Folkers", - "homepage": "https://twobrain.io", - "role": "Contributor" + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" } ], - "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", - "keywords": [ - "code", - "highlight", - "highlight.js", - "highlight.php", - "syntax" - ], + "description": "A polyfill for getallheaders.", "support": { - "issues": "https://github.com/scrivo/highlight.php/issues", - "source": "https://github.com/scrivo/highlight.php" + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" }, - "funding": [ - { - "url": "https://github.com/allejo", - "type": "github" - } - ], - "time": "2022-12-17T21:53:22+00:00" + "time": "2019-03-08T08:55:37+00:00" }, { - "name": "symfony/clock", - "version": "v6.4.8", + "name": "ratchet/rfc6455", + "version": "v0.3.1", "source": { "type": "git", - "url": "https://github.com/symfony/clock.git", - "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98" + "url": "https://github.com/ratchetphp/RFC6455.git", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/7a4840efd17135cbd547e41ec49fb910ed4f8b98", - "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98", + "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/7c964514e93456a52a99a20fcfa0de242a43ccdb", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/clock": "^1.0", - "symfony/polyfill-php83": "^1.28" + "guzzlehttp/psr7": "^2 || ^1.7", + "php": ">=5.4.2" }, - "provide": { - "psr/clock-implementation": "1.0" + "require-dev": { + "phpunit/phpunit": "^5.7", + "react/socket": "^1.3" }, "type": "library", "autoload": { - "files": [ - "Resources/now.php" - ], "psr-4": { - "Symfony\\Component\\Clock\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Ratchet\\RFC6455\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2145,8 +2395,691 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Chris Boden", + "email": "cboden@gmail.com", + "role": "Developer" + }, + { + "name": "Matt Bonneau", + "role": "Developer" + } + ], + "description": "RFC6455 WebSocket protocol handler", + "homepage": "http://socketo.me", + "keywords": [ + "WebSockets", + "rfc6455", + "websocket" + ], + "support": { + "chat": "https://gitter.im/reactphp/reactphp", + "issues": "https://github.com/ratchetphp/RFC6455/issues", + "source": "https://github.com/ratchetphp/RFC6455/tree/v0.3.1" + }, + "time": "2021-12-09T23:20:49+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/dns", + "version": "v1.13.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "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.13.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-13T14:18:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "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.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/http", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/http.git", + "reference": "8db02de41dcca82037367f67a2d4be365b1c4db9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/http/zipball/8db02de41dcca82037367f67a2d4be365b1c4db9", + "reference": "8db02de41dcca82037367f67a2d4be365b1c4db9", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "fig/http-message-util": "^1.1", + "php": ">=5.3.0", + "psr/http-message": "^1.0", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.3 || ^1.2.1", + "react/socket": "^1.16", + "react/stream": "^1.4" + }, + "require-dev": { + "clue/http-proxy-react": "^1.8", + "clue/reactphp-ssh-proxy": "^1.4", + "clue/socks-react": "^1.4", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.2 || ^3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Http\\": "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, streaming HTTP client and server implementation for ReactPHP", + "keywords": [ + "async", + "client", + "event-driven", + "http", + "http client", + "http server", + "https", + "psr-7", + "reactphp", + "server", + "streaming" + ], + "support": { + "issues": "https://github.com/reactphp/http/issues", + "source": "https://github.com/reactphp/http/tree/v1.11.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-11-20T15:24:08+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.16.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "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.16.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-07-26T10:38:09+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": "scrivo/highlight.php", + "version": "v9.18.1.10", + "source": { + "type": "git", + "url": "https://github.com/scrivo/highlight.php.git", + "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/850f4b44697a2552e892ffe71490ba2733c2fc6e", + "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7", + "sabberworm/php-css-parser": "^8.3", + "symfony/finder": "^2.8|^3.4|^5.4", + "symfony/var-dumper": "^2.8|^3.4|^5.4" + }, + "suggest": { + "ext-mbstring": "Allows highlighting code with unicode characters and supports language with unicode keywords" + }, + "type": "library", + "autoload": { + "files": [ + "HighlightUtilities/functions.php" + ], + "psr-0": { + "Highlight\\": "", + "HighlightUtilities\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Geert Bergman", + "homepage": "http://www.scrivo.org/", + "role": "Project Author" + }, + { + "name": "Vladimir Jimenez", + "homepage": "https://allejo.io", + "role": "Maintainer" + }, + { + "name": "Martin Folkers", + "homepage": "https://twobrain.io", + "role": "Contributor" + } + ], + "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", + "keywords": [ + "code", + "highlight", + "highlight.js", + "highlight.php", + "syntax" + ], + "support": { + "issues": "https://github.com/scrivo/highlight.php/issues", + "source": "https://github.com/scrivo/highlight.php" + }, + "funding": [ + { + "url": "https://github.com/allejo", + "type": "github" + } + ], + "time": "2022-12-17T21:53:22+00:00" + }, + { + "name": "symfony/clock", + "version": "v6.4.24", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", + "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", @@ -2161,7 +3094,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v6.4.8" + "source": "https://github.com/symfony/clock/tree/v6.4.24" }, "funding": [ { @@ -2172,25 +3105,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-05-31T14:51:39+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/config", - "version": "v6.4.7", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "51da0e4494d81bd7b5b5bd80319c55d8e0d7f4ff" + "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/51da0e4494d81bd7b5b5bd80319c55d8e0d7f4ff", - "reference": "51da0e4494d81bd7b5b5bd80319c55d8e0d7f4ff", + "url": "https://api.github.com/repos/symfony/config/zipball/80e2cf005cf17138c97193be0434cdcfd1b2212e", + "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e", "shasum": "" }, "require": { @@ -2236,7 +3173,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.7" + "source": "https://github.com/symfony/config/tree/v6.4.24" }, "funding": [ { @@ -2247,25 +3184,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-04-18T09:22:46+00:00" + "time": "2025-07-26T13:50:30+00:00" }, { "name": "symfony/console", - "version": "v6.4.17", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", + "url": "https://api.github.com/repos/symfony/console/zipball/59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", "shasum": "" }, "require": { @@ -2330,7 +3271,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.17" + "source": "https://github.com/symfony/console/tree/v6.4.24" }, "funding": [ { @@ -2341,25 +3282,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-12-07T12:07:30+00:00" + "time": "2025-07-30T10:38:54+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.7", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "d8c5f9781b71c2a868ae9d0e5c9b283684740b6d" + "reference": "929ab73b93247a15166ee79e807ccee4f930322d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d8c5f9781b71c2a868ae9d0e5c9b283684740b6d", - "reference": "d8c5f9781b71c2a868ae9d0e5c9b283684740b6d", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/929ab73b93247a15166ee79e807ccee4f930322d", + "reference": "929ab73b93247a15166ee79e807ccee4f930322d", "shasum": "" }, "require": { @@ -2367,7 +3312,7 @@ "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.2.10|^7.0" + "symfony/var-exporter": "^6.4.20|^7.2.5" }, "conflict": { "ext-psr": "<1.1|>=2", @@ -2411,7 +3356,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.7" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.24" }, "funding": [ { @@ -2422,25 +3367,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-04-18T09:22:46+00:00" + "time": "2025-07-30T17:30:48+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -2453,7 +3402,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2478,7 +3427,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.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -2494,20 +3443,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.7", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "d84384f3f67de3cb650db64d685d70395dacfc3f" + "reference": "307a09d8d7228d14a05e5e05b95fffdacab032b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d84384f3f67de3cb650db64d685d70395dacfc3f", - "reference": "d84384f3f67de3cb650db64d685d70395dacfc3f", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/307a09d8d7228d14a05e5e05b95fffdacab032b2", + "reference": "307a09d8d7228d14a05e5e05b95fffdacab032b2", "shasum": "" }, "require": { @@ -2558,7 +3507,7 @@ "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/v6.4.7" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.24" }, "funding": [ { @@ -2569,25 +3518,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-04-18T09:22:46+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { @@ -2596,12 +3549,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": { @@ -2634,7 +3587,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -2650,20 +3603,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.13", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" + "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", - "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", "shasum": "" }, "require": { @@ -2700,7 +3653,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.13" + "source": "https://github.com/symfony/filesystem/tree/v6.4.24" }, "funding": [ { @@ -2711,25 +3664,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-10-25T15:07:50+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/html-sanitizer", - "version": "v6.4.12", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/html-sanitizer.git", - "reference": "b58efe8ed0d8f5bf84913380a2f9da0c242f4200" + "reference": "8e9bb309986809af4cd9e049f9362d736387f083" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/b58efe8ed0d8f5bf84913380a2f9da0c242f4200", - "reference": "b58efe8ed0d8f5bf84913380a2f9da0c242f4200", + "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/8e9bb309986809af4cd9e049f9362d736387f083", + "reference": "8e9bb309986809af4cd9e049f9362d736387f083", "shasum": "" }, "require": { @@ -2769,7 +3726,7 @@ "sanitizer" ], "support": { - "source": "https://github.com/symfony/html-sanitizer/tree/v6.4.12" + "source": "https://github.com/symfony/html-sanitizer/tree/v6.4.24" }, "funding": [ { @@ -2780,32 +3737,36 @@ "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-20T08:21:33+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.12", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "fbebfcce21084d3e91ea987ae5bdd8c71ff0fd56" + "reference": "6d78fe8abecd547c159b8a49f7c88610630b7da2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/fbebfcce21084d3e91ea987ae5bdd8c71ff0fd56", - "reference": "fbebfcce21084d3e91ea987ae5bdd8c71ff0fd56", + "url": "https://api.github.com/repos/symfony/http-client/zipball/6d78fe8abecd547c159b8a49f7c88610630b7da2", + "reference": "6d78fe8abecd547c159b8a49f7c88610630b7da2", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "^3.4.1", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -2862,7 +3823,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.12" + "source": "https://github.com/symfony/http-client/tree/v6.4.24" }, "funding": [ { @@ -2873,25 +3834,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-20T08:21:33+00:00" + "time": "2025-07-14T16:38:25+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "20414d96f391677bf80078aa55baece78b82647d" + "reference": "75d7043853a42837e68111812f4d964b01e5101c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", - "reference": "20414d96f391677bf80078aa55baece78b82647d", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", "shasum": "" }, "require": { @@ -2899,12 +3864,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": { @@ -2940,7 +3905,84 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/http-client-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": "2025-04-29T11:18:49+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v6.4.24", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "0341e41d8d8830c31a1dff5cbc5bdb3ec872a073" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0341e41d8d8830c31a1dff5cbc5bdb3ec872a073", + "reference": "0341e41d8d8830c31a1dff5cbc5bdb3ec872a073", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "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": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v6.4.24" }, "funding": [ { @@ -2951,16 +3993,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-04-18T09:32:20+00:00" + "time": "2025-07-10T08:14:14+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", @@ -3019,7 +4065,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": [ { @@ -3030,6 +4076,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" @@ -3039,16 +4089,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -3097,7 +4147,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -3108,16 +4158,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": "2025-06-27T09:58:17+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", @@ -3178,7 +4232,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": [ { @@ -3189,6 +4243,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" @@ -3198,19 +4256,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": { @@ -3258,7 +4317,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": [ { @@ -3269,25 +4328,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-12-23T08:48:59+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": { @@ -3338,7 +4401,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": [ { @@ -3349,25 +4412,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": "2025-01-02T08:10:11+00:00" }, { - "name": "symfony/polyfill-php81", - "version": "v1.31.0", + "name": "symfony/polyfill-php83", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -3376,8 +4443,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -3385,7 +4452,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" + "Symfony\\Polyfill\\Php83\\": "" }, "classmap": [ "Resources/stubs" @@ -3405,7 +4472,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -3414,7 +4481,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -3425,46 +4492,41 @@ "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-07-08T02:45:35+00:00" }, { - "name": "symfony/polyfill-php83", - "version": "v1.31.0", + "name": "symfony/process", + "version": "v6.4.24", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "url": "https://github.com/symfony/process.git", + "reference": "8eb6dc555bfb49b2703438d5de65cc9f138ff50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/process/zipball/8eb6dc555bfb49b2703438d5de65cc9f138ff50b", + "reference": "8eb6dc555bfb49b2703438d5de65cc9f138ff50b", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.1" }, "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" + "Symfony\\Component\\Process\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3473,24 +4535,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/process/tree/v6.4.24" }, "funding": [ { @@ -3501,34 +4557,54 @@ "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-07-10T08:14:14+00:00" }, { - "name": "symfony/process", - "version": "v6.4.19", + "name": "symfony/routing", + "version": "v6.4.24", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3" + "url": "https://github.com/symfony/routing.git", + "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3", - "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3", + "url": "https://api.github.com/repos/symfony/routing/zipball/e4f94e625c8e6f910aa004a0042f7b2d398278f5", + "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/annotations": "<1.12", + "symfony/config": "<6.2", + "symfony/dependency-injection": "<5.4", + "symfony/yaml": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12|^2", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.2|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Process\\": "" + "Symfony\\Component\\Routing\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3548,10 +4624,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Executes commands in sub-processes", + "description": "Maps an HTTP request to a set of configuration variables", "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], "support": { - "source": "https://github.com/symfony/process/tree/v6.4.19" + "source": "https://github.com/symfony/routing/tree/v6.4.24" }, "funding": [ { @@ -3562,25 +4644,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": "2025-02-04T13:35:48+00:00" + "time": "2025-07-15T08:46:37+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -3598,7 +4684,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -3634,7 +4720,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -3650,20 +4736,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/string", - "version": "v6.4.15", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" + "reference": "f0ce0bd36a3accb4a225435be077b4b4875587f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "url": "https://api.github.com/repos/symfony/string/zipball/f0ce0bd36a3accb4a225435be077b4b4875587f4", + "reference": "f0ce0bd36a3accb4a225435be077b4b4875587f4", "shasum": "" }, "require": { @@ -3720,7 +4806,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.15" + "source": "https://github.com/symfony/string/tree/v6.4.24" }, "funding": [ { @@ -3731,25 +4817,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-11-13T13:31:12+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", "shasum": "" }, "require": { @@ -3762,7 +4852,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -3798,7 +4888,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" }, "funding": [ { @@ -3814,20 +4904,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-27T08:32:26+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.7", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "825f9b00c37bbe1c1691cc1aff9b5451fc9b4405" + "reference": "1e742d559fe5b19d0cdc281b1bf0b1fcc243bd35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/825f9b00c37bbe1c1691cc1aff9b5451fc9b4405", - "reference": "825f9b00c37bbe1c1691cc1aff9b5451fc9b4405", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1e742d559fe5b19d0cdc281b1bf0b1fcc243bd35", + "reference": "1e742d559fe5b19d0cdc281b1bf0b1fcc243bd35", "shasum": "" }, "require": { @@ -3875,7 +4965,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.7" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.24" }, "funding": [ { @@ -3886,12 +4976,16 @@ "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-04-18T09:22:46+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/yaml", @@ -3967,26 +5061,26 @@ }, { "name": "twig/twig", - "version": "v3.14.0", + "version": "v3.21.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72" + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72", - "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php81": "^1.29" + "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { + "phpstan/phpstan": "^2.0", "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, @@ -4030,7 +5124,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.14.0" + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" }, "funding": [ { @@ -4042,7 +5136,7 @@ "type": "tidelift" } ], - "time": "2024-09-09T17:55:12+00:00" + "time": "2025-05-03T07:21:55+00:00" }, { "name": "webmozart/assert", diff --git a/packages/filesystem/src/FileSystem.php b/packages/filesystem/src/FileSystem.php index ceb322027..140f7b870 100644 --- a/packages/filesystem/src/FileSystem.php +++ b/packages/filesystem/src/FileSystem.php @@ -54,4 +54,6 @@ public function listContents(string $directory = '', bool $recursive = false): a /** @return StorageAttributes[] */ public function find(SpecificationInterface $specification): iterable; + + public function isDirectory(string $path): bool; } diff --git a/packages/filesystem/src/FlySystemAdapter.php b/packages/filesystem/src/FlySystemAdapter.php index 329187561..b01cecbe5 100644 --- a/packages/filesystem/src/FlySystemAdapter.php +++ b/packages/filesystem/src/FlySystemAdapter.php @@ -92,4 +92,9 @@ public function find(SpecificationInterface $specification): iterable { return $this->filesystem->find($specification); } + + public function isDirectory(string $path): bool + { + return $this->filesystem->isDirectory($path); + } } diff --git a/packages/filesystem/src/FlysystemV1/FlysystemV1.php b/packages/filesystem/src/FlysystemV1/FlysystemV1.php index 1a4698e6d..fae31ba85 100644 --- a/packages/filesystem/src/FlysystemV1/FlysystemV1.php +++ b/packages/filesystem/src/FlysystemV1/FlysystemV1.php @@ -75,4 +75,9 @@ public function find(SpecificationInterface $specification): iterable yield new \phpDocumentor\FileSystem\FlysystemV1\StorageAttributes($file); } } + + public function isDirectory(string $path): bool + { + return $this->filesystem->directoryExists($path); + } } diff --git a/packages/filesystem/src/FlysystemV3/FlysystemV3.php b/packages/filesystem/src/FlysystemV3/FlysystemV3.php index c5e9ce84a..be648914d 100644 --- a/packages/filesystem/src/FlysystemV3/FlysystemV3.php +++ b/packages/filesystem/src/FlysystemV3/FlysystemV3.php @@ -35,6 +35,11 @@ public function has(string $path): bool return $this->filesystem->has($path); } + public function isDirectory(string $path): bool + { + return $this->filesystem->directoryExists($path); + } + public function readStream(string $path): mixed { return $this->filesystem->readStream($path); diff --git a/packages/guides-cli/composer.json b/packages/guides-cli/composer.json index 09df05b5f..c313f3122 100644 --- a/packages/guides-cli/composer.json +++ b/packages/guides-cli/composer.json @@ -32,7 +32,11 @@ "symfony/config": "^5.4 || ^6.3 || ^7.0", "symfony/console": "^5.4 || ^6.3 || ^7.0", "symfony/dependency-injection": "^5.4 || ^6.3 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.3 || ^7.0" + "symfony/event-dispatcher": "^5.4 || ^6.3 || ^7.0", + "cboden/ratchet": "0.4.x@dev", + "react/http": "^v1.11", + "react/socket": "^v1.16", + "league/mime-type-detection": "^1.16" }, "bin": [ "bin/guides" diff --git a/packages/guides-cli/resources/config/services.php b/packages/guides-cli/resources/config/services.php index e069a707c..d4a7ba16a 100644 --- a/packages/guides-cli/resources/config/services.php +++ b/packages/guides-cli/resources/config/services.php @@ -6,7 +6,12 @@ use phpDocumentor\Guides\Cli\Application; use phpDocumentor\Guides\Cli\Command\ProgressBarSubscriber; use phpDocumentor\Guides\Cli\Command\Run; +use phpDocumentor\Guides\Cli\Command\Serve; +use phpDocumentor\Guides\Cli\Command\SettingsBuilder; use phpDocumentor\Guides\Cli\Command\WorkingDirectorySwitcher; +use phpDocumentor\Guides\Cli\Internal\RunCommand; +use phpDocumentor\Guides\Cli\Internal\RunCommandHandler; +use phpDocumentor\Guides\Cli\Internal\ServerFactory; use Psr\Clock\ClockInterface; use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerInterface; @@ -26,6 +31,10 @@ ->public() ->tag('phpdoc.guides.cli.command') + ->set(Serve::class) + ->public() + ->tag('phpdoc.guides.cli.command') + ->set(NativeClock::class) ->alias(ClockInterface::class, NativeClock::class) @@ -44,5 +53,9 @@ ->set(WorkingDirectorySwitcher::class) ->tag('event_listener', ['event' => ConsoleEvents::COMMAND, 'method' => '__invoke']) - ->set(ProgressBarSubscriber::class); + ->set(ProgressBarSubscriber::class) + ->set(SettingsBuilder::class) + ->set(RunCommandHandler::class) + ->tag('phpdoc.guides.command', ['command' => RunCommand::class]) + ->set(ServerFactory::class); }; diff --git a/packages/guides-cli/src/Command/Run.php b/packages/guides-cli/src/Command/Run.php index da7cff393..f5c7d1968 100644 --- a/packages/guides-cli/src/Command/Run.php +++ b/packages/guides-cli/src/Command/Run.php @@ -14,51 +14,27 @@ namespace phpDocumentor\Guides\Cli\Command; use Doctrine\Deprecations\Deprecation; -use Flyfinder\Path; -use Flyfinder\Specification\InPath; -use Flyfinder\Specification\NotSpecification; -use Flyfinder\Specification\OrSpecification; -use Flyfinder\Specification\SpecificationInterface; use League\Tactician\CommandBus; use Monolog\Handler\ErrorLogHandler; use Monolog\Handler\StreamHandler; use Monolog\Logger; -use phpDocumentor\FileSystem\Finder\Exclude; -use phpDocumentor\FileSystem\FlySystemAdapter; +use phpDocumentor\Guides\Cli\Internal\RunCommand; use phpDocumentor\Guides\Cli\Logger\SpyProcessor; -use phpDocumentor\Guides\Compiler\CompilerContext; -use phpDocumentor\Guides\Event\PostProjectNodeCreated; -use phpDocumentor\Guides\Handlers\CompileDocumentsCommand; -use phpDocumentor\Guides\Handlers\ParseDirectoryCommand; -use phpDocumentor\Guides\Handlers\ParseFileCommand; -use phpDocumentor\Guides\Handlers\RenderCommand; -use phpDocumentor\Guides\Nodes\ProjectNode; -use phpDocumentor\Guides\Settings\ProjectSettings; use phpDocumentor\Guides\Settings\SettingsManager; use phpDocumentor\Guides\Twig\Theme\ThemeManager; use Psr\Clock\ClockInterface; use Psr\Log\LogLevel; -use RuntimeException; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\EventDispatcher\EventDispatcher; -use function array_map; use function array_pop; -use function array_reduce; -use function array_shift; -use function assert; use function count; use function implode; use function is_countable; -use function is_dir; -use function method_exists; -use function pathinfo; -use function sprintf; use function strtoupper; final class Run extends Command @@ -71,47 +47,13 @@ public function __construct( private readonly ClockInterface $clock, private readonly EventDispatcher $eventDispatcher, private readonly ProgressBarSubscriber $progressBarSubscriber, + private SettingsBuilder $settingsBuilder, ) { parent::__construct('run'); - $this->addArgument( - 'input', - InputArgument::OPTIONAL, - 'Directory which holds the files to render', - ); - $this->addOption( - 'output', - null, - InputOption::VALUE_REQUIRED, - 'Directory to write rendered files to', - ); - - $this->addOption( - 'input-file', - null, - InputOption::VALUE_REQUIRED, - 'If set, only the specified file is parsed, relative to the directory specified in "input"', - ); - - $this->addOption( - 'exclude-path', - null, - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Paths to exclude, doc files in these directories will not be parsed', - ); + $this->settingsBuilder ??= new SettingsBuilder($this->eventDispatcher, $this->settingsManager, $this->clock); + $this->settingsBuilder->configureCommand($this); - $this->addOption( - 'input-format', - null, - InputOption::VALUE_REQUIRED, - 'Format of the input can be "RST", or "Markdown"', - ); - $this->addOption( - 'output-format', - null, - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Format of the input can be "html" and/or "interlink"', - ); $this->addOption( 'log-path', null, @@ -132,13 +74,6 @@ public function __construct( 'If set, returns a non-zero exit code as soon as any errors occur', ); - $this->addOption( - 'theme', - null, - InputOption::VALUE_REQUIRED, - 'The theme used for rendering', - ); - $this->addOption( 'progress', null, @@ -159,93 +94,11 @@ public function registerProgressBar(ConsoleOutputInterface $output): void $this->progressBarSubscriber->subscribe($output, $this->eventDispatcher); } - private function getSettingsOverriddenWithInput(InputInterface $input): ProjectSettings - { - $settings = $this->settingsManager->getProjectSettings(); - - if ($settings->isShowProgressBar()) { - $settings->setShowProgressBar($input->getOption('progress')); - } - - if ($input->getArgument('input')) { - $settings->setInput((string) $input->getArgument('input')); - } - - if ($input->getOption('output')) { - $settings->setOutput((string) $input->getOption('output')); - } - - if ($input->getOption('input-file')) { - $inputFile = (string) $input->getOption('input-file'); - $pathInfo = pathinfo($inputFile); - $settings->setInputFile($pathInfo['filename']); - if (!empty($pathInfo['extension'])) { - $settings->setInputFormat($pathInfo['extension']); - } - } - - if ($input->getOption('input-format')) { - $settings->setInputFormat((string) $input->getOption('input-format')); - } - - if ($input->getOption('log-path')) { - $settings->setLogPath((string) $input->getOption('log-path')); - } - - if ($input->getOption('fail-on-error')) { - $settings->setFailOnError(LogLevel::ERROR); - } - - if ($input->getOption('fail-on-log')) { - $settings->setFailOnError(LogLevel::WARNING); - } - - if (count($input->getOption('output-format')) > 0) { - $settings->setOutputFormats($input->getOption('output-format')); - } - - if ($input->getOption('theme')) { - $settings->setTheme((string) $input->getOption('theme')); - } - - if (method_exists($settings, 'setExcludes')) { - /** @var list $excludePaths */ - $excludePaths = (array) $input->getOption('exclude-path'); - if ($excludePaths !== []) { - $settings->setExcludes( - $settings->getExcludes()->withPaths($excludePaths), - ); - } - } - - return $settings; - } - protected function execute(InputInterface $input, OutputInterface $output): int { - $settings = $this->getSettingsOverriddenWithInput($input); - $inputDir = $settings->getInput(); - if (!is_dir($inputDir)) { - throw new RuntimeException(sprintf('Input directory "%s" was not found! ' . "\n" . - 'Run "vendor/bin/guides -h" for information on how to configure this command.', $inputDir)); - } - - $projectNode = new ProjectNode( - $settings->getTitle() === '' ? null : $settings->getTitle(), - $settings->getVersion() === '' ? null : $settings->getVersion(), - $settings->getRelease() === '' ? null : $settings->getRelease(), - $settings->getCopyright() === '' ? null : $settings->getCopyright(), - $this->clock->now(), - ); - - $event = new PostProjectNodeCreated($projectNode, $settings); - $event = $this->eventDispatcher->dispatch($event); - assert($event instanceof PostProjectNodeCreated); - $projectNode = $event->getProjectNode(); - $settings = $event->getSettings(); - - $outputDir = $settings->getOutput(); - $sourceFileSystem = FlySystemAdapter::createForPath($settings->getInput()); + $this->settingsBuilder->overrideWithInput($input); + $projectNode = $this->settingsBuilder->createProjectNode(); + $settings = $this->settingsBuilder->getSettings(); $logPath = $settings->getLogPath(); if ($logPath === 'php://stder') { @@ -260,57 +113,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->logger->pushProcessor($spyProcessor); } - $documents = []; - - if ($output instanceof ConsoleOutputInterface && $settings->isShowProgressBar()) { $this->progressBarSubscriber->subscribe($output, $this->eventDispatcher); } - if ($settings->getInputFile() === '') { - $documents = $this->commandBus->handle( - new ParseDirectoryCommand( - $sourceFileSystem, - '', - $settings->getInputFormat(), - $projectNode, - $this->getExclude($settings, $input), - ), - ); - } else { - $documents[] = $this->commandBus->handle( - new ParseFileCommand( - $sourceFileSystem, - '', - $settings->getInputFile(), - $settings->getInputFormat(), - 1, - $projectNode, - true, - ), - ); - } - - $this->themeManager->useTheme($settings->getTheme()); - - $documents = $this->commandBus->handle(new CompileDocumentsCommand($documents, new CompilerContext($projectNode))); - - $destinationFileSystem = FlySystemAdapter::createForPath($outputDir); + $documents = $this->commandBus->handle( + new RunCommand($settings, $projectNode, $input), + ); $outputFormats = $settings->getOutputFormats(); - - foreach ($outputFormats as $format) { - $this->commandBus->handle( - new RenderCommand( - $format, - $documents, - $sourceFileSystem, - $destinationFileSystem, - $projectNode, - ), - ); - } - + $outputDir = $settings->getOutput(); if ($output->isQuiet() === false) { $lastFormat = ''; @@ -331,31 +143,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Command::SUCCESS; } - - private function getExclude(ProjectSettings $settings, InputInterface|null $input = null): Exclude|SpecificationInterface|null - { - if (method_exists($settings, 'getExcludes')) { - return $settings->getExcludes(); - } - - if ($input === null) { - return null; - } - - if ($input->getOption('exclude-path')) { - /** @var string[] $excludedPaths */ - $excludedPaths = (array) $input->getOption('exclude-path'); - $excludedSpecifications = array_map(static fn (string $path) => new NotSpecification(new InPath(new Path($path))), $excludedPaths); - $excludedSpecification = array_shift($excludedSpecifications); - assert($excludedSpecification !== null); - - return array_reduce( - $excludedSpecifications, - static fn (SpecificationInterface $carry, SpecificationInterface $spec) => new OrSpecification($carry, $spec), - $excludedSpecification, - ); - } - - return null; - } } diff --git a/packages/guides-cli/src/Command/Serve.php b/packages/guides-cli/src/Command/Serve.php new file mode 100644 index 000000000..239bfe141 --- /dev/null +++ b/packages/guides-cli/src/Command/Serve.php @@ -0,0 +1,133 @@ +settingsBuilder->configureCommand($this); + $this->addOption('host', null, InputOption::VALUE_REQUIRED, 'Hostname to serve on', 'localhost'); + $this->addOption('port', 'p', InputOption::VALUE_REQUIRED, 'Port to run the server on', 1337); + $this->addOption('listen', 'l', InputOption::VALUE_REQUIRED, 'Address to listen on', '0.0.0.0'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->pushHandler(new ErrorLogHandler(ErrorLogHandler::OPERATING_SYSTEM)); + // Enable tick processing for signal handling + declare(ticks=1); + + $loop = Loop::get(); + $loop->addSignal(SIGINT, static function () use ($loop, $output): void { + $output->writeln('Shutting down server...'); + $loop->stop(); + $output->writeln('Server stopped'); + exit(0); + }); + + + $dir = $input->getOption('output'); + if ($dir === null) { + $output->writeln('Please specify an output directory using --output option'); + + return Command::FAILURE; + } + + $files = FlySystemAdapter::createForPath($dir); + $app = $this->serverFactory->createWebserver( + $files, + $loop, + $input->getOption('host'), + $input->getOption('listen'), + (int) $input->getOption('port'), + ); + + $watcher = new InotifyWatcher($loop, $this->dispatcher, $input->getArgument('input')); + + $this->dispatcher->addListener( + PostParseDocument::class, + static function (PostParseDocument $event) use ($watcher): void { + $watcher->addPath($event->getOriginalFileName()); + }, + ); + + $this->dispatcher->addListener( + FileModifiedEvent::class, + function (FileModifiedEvent $event) use ($app, $input, $output): void { + $output->writeln( + sprintf( + 'File modified: %s, rerendering...', + $event->path, + ), + ); + $this->commandBus->handle( + new RunCommand( + $this->settingsBuilder->getSettings(), + $this->settingsBuilder->createProjectNode(), + $input, + ), + ); + $output->writeln('Rerendering completed.'); + $app->notifyClients(); + }, + ); + + $this->settingsBuilder->overrideWithInput($input); + + $this->commandBus->handle( + new RunCommand( + $this->settingsBuilder->getSettings(), + $this->settingsBuilder->createProjectNode(), + $input, + ), + ); + + $output->writeln(sprintf('Server running at http://localhost:1337')); + $output->writeln('WebSocket server running at ws://localhost:1337/ws'); + $output->writeln('Press Ctrl+C to stop the server'); + + $app->run(); + + return Command::SUCCESS; + } +} diff --git a/packages/guides-cli/src/Command/SettingsBuilder.php b/packages/guides-cli/src/Command/SettingsBuilder.php new file mode 100644 index 000000000..448105d36 --- /dev/null +++ b/packages/guides-cli/src/Command/SettingsBuilder.php @@ -0,0 +1,188 @@ +settingsManager->getProjectSettings(); + + if ($settings->isShowProgressBar() && $input->hasOption('progress')) { + $settings->setShowProgressBar($input->getOption('progress')); + } + + if ($input->getArgument('input')) { + $settings->setInput((string) $input->getArgument('input')); + } + + if ($input->getOption('output')) { + $settings->setOutput((string) $input->getOption('output')); + } + + if ($input->getOption('input-file')) { + $inputFile = (string) $input->getOption('input-file'); + $pathInfo = pathinfo($inputFile); + $settings->setInputFile($pathInfo['filename']); + if (!empty($pathInfo['extension'])) { + $settings->setInputFormat($pathInfo['extension']); + } + } + + if ($input->getOption('input-format')) { + $settings->setInputFormat((string) $input->getOption('input-format')); + } + + if ($input->hasOption('log-path')) { + $settings->setLogPath((string) $input->getOption('log-path')); + } + + if ($input->hasOption('fail-on-error')) { + $settings->setFailOnError(LogLevel::ERROR); + } + + if ($input->hasOption('fail-on-log')) { + $settings->setFailOnError(LogLevel::WARNING); + } + + if (count($input->getOption('output-format')) > 0) { + $settings->setOutputFormats($input->getOption('output-format')); + } + + if ($input->getOption('theme')) { + $settings->setTheme((string) $input->getOption('theme')); + } + + if (method_exists($settings, 'setExcludes')) { + /** @var list $excludePaths */ + $excludePaths = (array) $input->getOption('exclude-path'); + if ($excludePaths !== []) { + $settings->setExcludes( + $settings->getExcludes()->withPaths($excludePaths), + ); + } + } + + $this->settings = $settings; + } + + public function createProjectNode(): ProjectNode + { + $projectNode = new ProjectNode( + $this->settings->getTitle() === '' ? null : $this->settings->getTitle(), + $this->settings->getVersion() === '' ? null : $this->settings->getVersion(), + $this->settings->getRelease() === '' ? null : $this->settings->getRelease(), + $this->settings->getCopyright() === '' ? null : $this->settings->getCopyright(), + $this->clock->now(), + ); + + $event = new PostProjectNodeCreated($projectNode, $this->settings); + $event = $this->eventDispatcher->dispatch($event); + assert($event instanceof PostProjectNodeCreated); + $projectNode = $event->getProjectNode(); + $this->settings = $event->getSettings(); + + return $projectNode; + } + + public function getSettings(): ProjectSettings + { + $inputDir = $this->settings->getInput(); + if (!is_dir($inputDir)) { + throw new RuntimeException(sprintf('Input directory "%s" was not found! ' . "\n" . + 'Run "vendor/bin/guides -h" for information on how to configure this command.', $inputDir)); + } + + return $this->settings; + } + + public function configureCommand(Command $command): void + { + $command->addArgument( + 'input', + InputArgument::OPTIONAL, + 'Directory which holds the files to render', + ); + $command->addOption( + 'output', + null, + InputOption::VALUE_REQUIRED, + 'Directory to write rendered files to', + ); + + $command->addOption( + 'input-file', + null, + InputOption::VALUE_REQUIRED, + 'If set, only the specified file is parsed, relative to the directory specified in "input"', + ); + + $command->addOption( + 'exclude-path', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Paths to exclude, doc files in these directories will not be parsed', + ); + + $command->addOption( + 'input-format', + null, + InputOption::VALUE_REQUIRED, + 'Format of the input can be "RST", or "Markdown"', + ); + $command->addOption( + 'output-format', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Format of the input can be "html" and/or "interlink"', + ); + + $command->addOption( + 'theme', + null, + InputOption::VALUE_REQUIRED, + 'The theme used for rendering', + ); + } +} diff --git a/packages/guides-cli/src/Internal/HttpHandler.php b/packages/guides-cli/src/Internal/HttpHandler.php new file mode 100644 index 000000000..090247f59 --- /dev/null +++ b/packages/guides-cli/src/Internal/HttpHandler.php @@ -0,0 +1,135 @@ +detector = new ExtensionMimeTypeDetector(); + } + + public function onOpen(ConnectionInterface $conn, RequestInterface|null $request = null): void + { + if ($request === null) { + $conn->close(); + + return; + } + + $path = $request->getUri()->getPath(); + $this->logger->info( + sprintf( + 'Received request for %s from %s', + $path, + $conn->remoteAddress, + ), + ); + + // Remove leading slash and any route parameters + $requestPath = trim($path, '/'); + + // For empty path (root) serve index.html + if ($requestPath === '') { + $requestPath = 'index.html'; + } + + if ($this->files->isDirectory($requestPath)) { + $requestPath .= '/index.html'; + } + + if ($this->files->has($requestPath)) { + $content = $this->files->read($requestPath) ?: ''; + + // Inject WebSocket client code for HTML files + if ($this->detector->detectMimeTypeFromPath($requestPath) === 'text/html') { + $content = $this->injectWebSocketClient($content); + } + + $headers = [ + 'Content-Type' => $this->detector->detectMimeTypeFromPath($requestPath) ?? 'text/plain', + 'Content-Length' => strlen($content), + ]; + + $conn->send(Message::toString(new Response(200, $headers, $content))); + $conn->close(); + + return; + } + + $content = '

404 - Page Not Found

'; + $headers = [ + 'Content-Type' => 'text/html', + 'Content-Length' => strlen($content), + ]; + + $conn->send(Message::toString(new Response(404, $headers, $content))); + $conn->close(); + } + + private function injectWebSocketClient(string $html): string + { + //Read html and inject script before closing body tag + $injection = <<<'EOT' + +EOT; + + return str_replace('', $injection . '', $html); + } + + public function onClose(ConnectionInterface $conn): void + { + $this->close($conn); + } + + public function onError(ConnectionInterface $conn, Throwable $e): void + { + $this->close($conn, 500); + } + + public function onMessage(ConnectionInterface $from, string $msg): void + { + // TODO: Implement onMessage() method. + } +} diff --git a/packages/guides-cli/src/Internal/RunCommand.php b/packages/guides-cli/src/Internal/RunCommand.php new file mode 100644 index 000000000..21ae6e6bb --- /dev/null +++ b/packages/guides-cli/src/Internal/RunCommand.php @@ -0,0 +1,28 @@ +settings; + $projectNode = $command->projectNode; + $outputDir = $settings->getOutput(); + $sourceFileSystem = FlySystemAdapter::createForPath($settings->getInput()); + $documents = []; + if ($settings->getInputFile() === '') { + $documents = $this->commandBus->handle( + new ParseDirectoryCommand( + $sourceFileSystem, + '', + $settings->getInputFormat(), + $projectNode, + $this->getExclude($settings, $command->input), + ), + ); + } else { + $documents[] = $this->commandBus->handle( + new ParseFileCommand( + $sourceFileSystem, + '', + $settings->getInputFile(), + $settings->getInputFormat(), + 1, + $projectNode, + true, + ), + ); + } + + $this->themeManager->useTheme($settings->getTheme()); + + $documents = $this->commandBus->handle(new CompileDocumentsCommand($documents, new CompilerContext($projectNode))); + + $destinationFileSystem = FlySystemAdapter::createForPath($outputDir); + + $outputFormats = $settings->getOutputFormats(); + + foreach ($outputFormats as $format) { + $this->commandBus->handle( + new RenderCommand( + $format, + $documents, + $sourceFileSystem, + $destinationFileSystem, + $projectNode, + ), + ); + } + + return $documents; + } + + private function getExclude(ProjectSettings $settings, InputInterface|null $input = null): Exclude|SpecificationInterface|null + { + if (method_exists($settings, 'getExcludes')) { + return $settings->getExcludes(); + } + + if ($input === null) { + return null; + } + + if ($input->getOption('exclude-path')) { + /** @var string[] $excludedPaths */ + $excludedPaths = (array) $input->getOption('exclude-path'); + $excludedSpecifications = array_map(static fn (string $path) => new NotSpecification(new InPath(new Path($path))), $excludedPaths); + $excludedSpecification = array_shift($excludedSpecifications); + assert($excludedSpecification !== null); + + return array_reduce( + $excludedSpecifications, + static fn (SpecificationInterface $carry, SpecificationInterface $spec) => new OrSpecification($carry, $spec), + $excludedSpecification, + ); + } + + return null; + } +} diff --git a/packages/guides-cli/src/Internal/Server.php b/packages/guides-cli/src/Internal/Server.php new file mode 100644 index 000000000..001a1f9a9 --- /dev/null +++ b/packages/guides-cli/src/Internal/Server.php @@ -0,0 +1,35 @@ +app->run(); + } + + public function notifyClients(): void + { + $this->webSocketHandler->sendUpdate(); + } +} diff --git a/packages/guides-cli/src/Internal/ServerFactory.php b/packages/guides-cli/src/Internal/ServerFactory.php new file mode 100644 index 000000000..9fc81f2f1 --- /dev/null +++ b/packages/guides-cli/src/Internal/ServerFactory.php @@ -0,0 +1,51 @@ +logger, $files); + $wsServer = new WebSocketHandler($this->logger); + $host = 'localhost'; + + + // Setup the Ratchet App with routes + $app = new App($host, $port, $listen, $loop); + + // Add WebSocket route at /ws + $app->route('/ws', $wsServer, ['*']); + + // Add HTTP server for all other routes - use a different pattern syntax + $app->routes->add('catch-all', new Route( + '/{url}', + ['_controller' => $httpHandler], + ['url' => '.*'], + methods: ['GET'], + )); + + return new Server($app, $wsServer); + } +} diff --git a/packages/guides-cli/src/Internal/Watcher/FileModifiedEvent.php b/packages/guides-cli/src/Internal/Watcher/FileModifiedEvent.php new file mode 100644 index 000000000..17861b768 --- /dev/null +++ b/packages/guides-cli/src/Internal/Watcher/FileModifiedEvent.php @@ -0,0 +1,21 @@ + */ + private array $watchDescriptors; + + public function __construct( + private LoopInterface $loop, + private EventDispatcherInterface $dispatcher, + private string $inputPath, + ) { + } + + public function __invoke(): void + { + $events = inotify_read($this->inotify); + if ($events === false) { + return; + } + + foreach ($events as $event) { + if (!isset($this->watchDescriptors[$event['wd']])) { + continue; + } + + $path = $this->watchDescriptors[$event['wd']]['path']; + + // File modified event - triggered by direct modification + if ($event['mask'] & IN_MODIFY) { + $this->dispatcher->dispatch(new FileModifiedEvent($path)); + + return; + } + + // File closed after writing - common on macOS/Orbstack + if ($event['mask'] & IN_CLOSE_WRITE) { + $this->dispatcher->dispatch(new FileModifiedEvent($path)); + + return; + } + + if ($event['mask'] & IN_CREATE) { + //$this->dispatcher->dispatch(new FileCreatedEvent($path, $event['name'])); + return; + } + + if ($event['mask'] & IN_DELETE) { + //$this->dispatcher->dispatch(new FileDeletedEvent($path, $event['name'])); + return; + } + + // Log unhandled event types for debugging + var_dump('Unhandled event mask: ' . $event['mask']); + } + } + + public function addPath(string $path): void + { + if ($this->inotify === false) { + $this->inotify = inotify_init(); + stream_set_blocking($this->inotify, false); + + // wait for any file events by reading from inotify handler asynchronously + $this->loop->addReadStream($this->inotify, $this); + } + + // Add IN_CLOSE_WRITE to the watch mask to support macOS/Orbstack + $descriptor = inotify_add_watch( + $this->inotify, + $this->inputPath . DIRECTORY_SEPARATOR . $path, + IN_MODIFY | IN_CLOSE_WRITE | IN_CREATE | IN_DELETE, + ); + $this->watchDescriptors[$descriptor] = ['path' => $path]; + } +} diff --git a/packages/guides-cli/src/Internal/WebSocketHandler.php b/packages/guides-cli/src/Internal/WebSocketHandler.php new file mode 100644 index 000000000..3b3c6fa8e --- /dev/null +++ b/packages/guides-cli/src/Internal/WebSocketHandler.php @@ -0,0 +1,61 @@ + */ + private SplObjectStorage $clients; + + public function __construct(private LoggerInterface $logger) + { + $this->clients = new SplObjectStorage(); + } + + public function onOpen(ConnectionInterface $conn): void + { + $this->clients->attach($conn); + $this->logger->info('New WebSocket connection {resourceId}', ['resourceId' => $conn->resourceId]); + } + + public function onClose(ConnectionInterface $conn): void + { + $this->clients->detach($conn); + $this->logger->info('WebSocket connection {resourceId} has disconnected', ['resourceId' => $conn->resourceId]); + } + + public function onError(ConnectionInterface $conn, Throwable $e): void + { + $conn->close(); + } + + public function onMessage(ConnectionInterface $conn, MessageInterface $msg): void + { + //We do nothing with the message, just a ping to keep the connection alive + } + + public function sendUpdate(): void + { + foreach ($this->clients as $client) { + $client->send('update'); + } + } +}