diff --git a/.gitignore b/.gitignore index a67d42b..aa5a2af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ composer.phar /vendor/ +/.phpunit.cache # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file diff --git a/README.md b/README.md index a10cfa1..cfa699f 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Extension for PHPStan for better support for Craft CMS. The following features a - Dependency injection container support for `Craft::$container->get()` - Recognises custom field handles as properties on `Element` and `ElementQuery`, including handle overrides from entry-type field layouts (read from your project config) - Validates the `action` value of Twig `actionInput()` calls against discovered controller routes (including shorthand routes for controller default actions) +- Detects Twig N+1 query patterns and related performance smells (relational access in loops, queries built in loops, `|length` on queries, unbounded `.all()`), with eager-load (`.with([...])`) and Craft 5 `.eagerly()` suppression ## Install @@ -18,6 +19,10 @@ Via Composer $ composer require --dev jensderond/phpstan-craftcms ``` +The Twig checks require `twig/twig` ^3.27. Craft pins Twig to a specific minor +(e.g. Craft 5.10 uses `~3.27.0`), so projects on an older Craft 5.x release that +locks Twig below 3.27 need to update Craft before installing this version. + ## Usage Add `phpstan-craftcms` to the project `phpstan.neon` / `phpstan.neon.dist`: @@ -42,12 +47,61 @@ parameters: - %currentWorkingDirectory%/modules - %currentWorkingDirectory%/plugins handleMap: [] + craftTemplateScan: + excludeDirectories: + - vendor + - node_modules + craftTwigPerformance: + enabled: true + templatePaths: %craftActionInput.templatePaths% + checks: + nPlusOne: true + nestedRelationAll: true + queryInLoop: true + lengthOnQuery: true + unboundedAll: false ``` - `yii2.config_path` — path to your Yii/Craft application config used to build the service and route maps. - `craftcms.projectConfigPath` — path to the Craft project config directory; used to collect custom field handles and entry-type handle overrides. - `craftActionInput.templatePaths` — directories scanned for Twig `actionInput()` calls. - `craftActionInput.handleMap` — optional map of additional handle aliases used when resolving `actionInput()` values to controllers. +- `craftTemplateScan.excludeDirectories` — directory **names** pruned from the template walk (shared by the action-input and performance scans). Defaults to `vendor` and `node_modules`, so third-party templates a package bundles (Craft's own control-panel templates, other plugins' example/asset templates) are not analysed when a scanned path contains them. Add more names (e.g. `tests`) to skip further trees. + +### Twig performance checks + +`craftTwigPerformance.checks` toggles each check; `unboundedAll` is off by default +(it is often intentional). Suppress a check project-wide via `ignoreErrors` using +its identifier: + +- `craftcms.twigNPlusOne` +- `craftcms.twigNestedRelationAll` +- `craftcms.twigQueryInLoop` +- `craftcms.twigLengthOnQuery` +- `craftcms.twigUnboundedAll` + +Limitations: analysis is per-template — it does not follow loop variables across +`{% include %}`, macros, or block boundaries. Loop-source eager-loading is detected +inline or one `{% set %}` back. `.with(...)` is honored only for literal string +arrays; dynamic arguments suppress the finding. `|length`-on-query detection is a +best-effort static heuristic. Eager-load suppression recognizes both +`.with([...])` and Craft 5's `.eagerly()`. Relation checks +(`twigNPlusOne`/`twigNestedRelationAll`) fire only for loops that iterate element +query results: a loop over a static array/hash literal — directly, via `{% set %}`, +or through nested loops — yields plain values, so an attribute that happens to +share a relation field's handle (e.g. `font.file` over a hash literal) is not +flagged. + +#### Result cache and template changes + +The Twig checks scan the template tree directly, outside PHPStan's per-file +analysis. PHPStan's result cache is normally keyed on the analysed **PHP** +files (and the config) only, so this extension registers a result-cache meta +extension that folds a hash of every discovered template's path and contents +into the cache metadata. Editing, adding, or removing a `.twig` file changes +that hash, which invalidates the result cache and triggers a full re-analysis — +no manual `clear-result-cache` needed. Template changes are picked up by a +plain `phpstan analyse`, locally and in CI, just like PHP changes. ## Credits diff --git a/composer.json b/composer.json index 9b5b414..9870e60 100644 --- a/composer.json +++ b/composer.json @@ -1,13 +1,15 @@ { "name": "jensderond/phpstan-craftcms", "description": "CraftCMS extension for PHPStan", - "version": "1.3.0", + "version": "1.4.0", "require": { - "phpstan/phpstan": "^2.1" + "phpstan/phpstan": "^2.1", + "twig/twig": "^3.27" }, "require-dev": { - "craftcms/cms": "~5", - "laravel/pint": "^1.25" + "craftcms/cms": "^5.10.8", + "laravel/pint": "^1.25", + "phpunit/phpunit": "^11.5" }, "license": "MIT", "autoload": { @@ -15,6 +17,11 @@ "Jensderond\\PhpstanCraftcms\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "Jensderond\\PhpstanCraftcms\\Tests\\": "tests/" + } + }, "authors": [ { "name": "Jens de Rond", @@ -22,7 +29,8 @@ } ], "scripts": { - "lint": "pint" + "lint": "pint", + "test": "phpunit" }, "config": { "allow-plugins": { diff --git a/composer.lock b/composer.lock index bbbb088..3e0d9e4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "22782ed2364ff517cf8d976c4ecdc263", + "content-hash": "6793668d829c89ff56a79e634dc62851", "packages": [ { "name": "phpstan/phpstan", @@ -58,158 +58,198 @@ } ], "time": "2025-10-10T14:14:11+00:00" - } - ], - "packages-dev": [ + }, { - "name": "bacon/bacon-qr-code", - "version": "2.0.8", + "name": "symfony/deprecation-contracts", + "version": "v3.7.1", "source": { "type": "git", - "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { - "dasprid/enum": "^1.0.3", - "ext-iconv": "*", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "phly/keep-a-changelog": "^2.1", - "phpunit/phpunit": "^7 | ^8 | ^9", - "spatie/phpunit-snapshot-assertions": "^4.2.9", - "squizlabs/php_codesniffer": "^3.4" - }, - "suggest": { - "ext-imagick": "to generate QR code images" + "php": ">=8.1" }, "type": "library", - "autoload": { - "psr-4": { - "BaconQrCode\\": "src/" + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" } }, + "autoload": { + "files": [ + "function.php" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "MIT" ], "authors": [ { - "name": "Ben Scholzen 'DASPRiD'", - "email": "mail@dasprids.de", - "homepage": "https://dasprids.de/", - "role": "Developer" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "BaconQrCode is a QR code generator for PHP.", - "homepage": "https://github.com/Bacon/BaconQrCode", + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/Bacon/BaconQrCode/issues", - "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, - "time": "2022-12-07T17:46:57+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-05T06:23:12+00:00" }, { - "name": "brick/math", - "version": "0.13.1", + "name": "symfony/polyfill-ctype", + "version": "v1.37.0", "source": { "type": "git", - "url": "https://github.com/brick/math.git", - "reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04", - "reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { - "php": "^8.1" + "php": ">=7.2" }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^10.1", - "vimeo/psalm": "6.8.8" + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Brick\\Math\\": "src/" + "Symfony\\Polyfill\\Ctype\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Arbitrary-precision arithmetic library", + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", "keywords": [ - "Arbitrary-precision", - "BigInteger", - "BigRational", - "arithmetic", - "bigdecimal", - "bignum", - "bignumber", - "brick", - "decimal", - "integer", - "math", - "mathematics", - "rational" + "compatibility", + "ctype", + "polyfill", + "portable" ], "support": { - "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.13.1" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { - "url": "https://github.com/BenMorel", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-03-29T13:50:30+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { - "name": "cebe/markdown", - "version": "1.2.1", + "name": "symfony/polyfill-mbstring", + "version": "v1.38.2", "source": { "type": "git", - "url": "https://github.com/cebe/markdown.git", - "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", - "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { - "lib-pcre": "*", - "php": ">=5.4.0" + "ext-iconv": "*", + "php": ">=7.2" }, - "require-dev": { - "cebe/indent": "*", - "facebook/xhprof": "*@dev", - "phpunit/phpunit": "4.1.*" + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" }, - "bin": [ - "bin/markdown" - ], "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "cebe\\markdown\\": "" + "Symfony\\Polyfill\\Mbstring\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -218,121 +258,1993 @@ ], "authors": [ { - "name": "Carsten Brandt", - "email": "mail@cebe.cc", - "homepage": "http://cebe.cc/", - "role": "Creator" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A super fast, highly extensible markdown parser for PHP", - "homepage": "https://github.com/cebe/markdown#readme", + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", "keywords": [ - "extensible", - "fast", - "gfm", - "markdown", - "markdown-extra" + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" ], "support": { - "issues": "https://github.com/cebe/markdown/issues", - "source": "https://github.com/cebe/markdown" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, - "time": "2018-03-26T11:24:36+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-27T06:59:30+00:00" }, { - "name": "commerceguys/addressing", - "version": "v2.2.4", + "name": "twig/twig", + "version": "v3.27.1", "source": { "type": "git", - "url": "https://github.com/commerceguys/addressing.git", - "reference": "ea826dbe5b3fe76960073a2167d5cf996c811cda" + "url": "https://github.com/twigphp/Twig.git", + "reference": "ae2071bffb38f04847fc0864d730c94b9cb8ab74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/commerceguys/addressing/zipball/ea826dbe5b3fe76960073a2167d5cf996c811cda", - "reference": "ea826dbe5b3fe76960073a2167d5cf996c811cda", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/ae2071bffb38f04847fc0864d730c94b9cb8ab74", + "reference": "ae2071bffb38f04847fc0864d730c94b9cb8ab74", "shasum": "" }, "require": { - "doctrine/collections": "^1.6 || ^2.0", - "php": ">=8.0" + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { - "ext-json": "*", - "mikey179/vfsstream": "^1.6.11", - "phpunit/phpunit": "^9.6", - "squizlabs/php_codesniffer": "^3.7", - "symfony/validator": "^5.4 || ^6.3 || ^7.0" - }, - "suggest": { - "symfony/validator": "to validate addresses" + "php-cs-fixer/shim": "^3.0@stable", + "phpstan/phpstan": "^2.0@stable", + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { - "CommerceGuys\\Addressing\\": "src" + "Twig\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Bojan Zivanovic" + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { - "name": "Damien Tournoud" - } - ], - "description": "Addressing library powered by CLDR and Google's address data.", - "keywords": [ + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.27.1" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2026-05-30T17:09:26+00:00" + } + ], + "packages-dev": [ + { + "name": "bacon/bacon-qr-code", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "4da2233e72eeecd9be3b62e0dc2cc9ed8e2e31c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/4da2233e72eeecd9be3b62e0dc2cc9ed8e2e31c2", + "reference": "4da2233e72eeecd9be3b62e0dc2cc9ed8e2e31c2", + "shasum": "" + }, + "require": { + "dasprid/enum": "^1.0.3", + "ext-iconv": "*", + "php": "^8.1" + }, + "require-dev": { + "phly/keep-a-changelog": "^2.12", + "phpunit/phpunit": "^10.5.11 || ^11.0.4", + "spatie/phpunit-snapshot-assertions": "^5.1.5", + "spatie/pixelmatch-php": "^1.2.0", + "squizlabs/php_codesniffer": "^3.9" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "support": { + "issues": "https://github.com/Bacon/BaconQrCode/issues", + "source": "https://github.com/Bacon/BaconQrCode/tree/v3.1.1" + }, + "time": "2026-04-05T21:06:35+00:00" + }, + { + "name": "brick/math", + "version": "0.17.2", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "8189e751995f9e15729c1aa2f89fa8f166ffe818" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/8189e751995f9e15729c1aa2f89fa8f166ffe818", + "reference": "8189e751995f9e15729c1aa2f89fa8f166ffe818", + "shasum": "" + }, + "require": { + "php": "^8.2" + }, + "require-dev": { + "phpstan/phpstan": "2.1.22", + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "bignumber", + "brick", + "decimal", + "integer", + "math", + "mathematics", + "rational" + ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.17.2" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2026-05-25T20:34:43+00:00" + }, + { + "name": "carbonphp/carbon-doctrine-types", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d", + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "conflict": { + "doctrine/dbal": "<4.0.0 || >=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, + { + "name": "cebe/markdown", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/cebe/markdown.git", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "shasum": "" + }, + "require": { + "lib-pcre": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "cebe/indent": "*", + "facebook/xhprof": "*@dev", + "phpunit/phpunit": "4.1.*" + }, + "bin": [ + "bin/markdown" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "cebe\\markdown\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Creator" + } + ], + "description": "A super fast, highly extensible markdown parser for PHP", + "homepage": "https://github.com/cebe/markdown#readme", + "keywords": [ + "extensible", + "fast", + "gfm", + "markdown", + "markdown-extra" + ], + "support": { + "issues": "https://github.com/cebe/markdown/issues", + "source": "https://github.com/cebe/markdown" + }, + "time": "2018-03-26T11:24:36+00:00" + }, + { + "name": "commerceguys/addressing", + "version": "v2.2.5", + "source": { + "type": "git", + "url": "https://github.com/commerceguys/addressing.git", + "reference": "15b789e5e6ededaf803d23c56cdc300a94522a7c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/commerceguys/addressing/zipball/15b789e5e6ededaf803d23c56cdc300a94522a7c", + "reference": "15b789e5e6ededaf803d23c56cdc300a94522a7c", + "shasum": "" + }, + "require": { + "doctrine/collections": "^1.6 || ^2.0", + "php": ">=8.0" + }, + "require-dev": { + "ext-json": "*", + "mikey179/vfsstream": "^1.6.11", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.7", + "symfony/validator": "^5.4 || ^6.3 || ^7.0 || ^8.0" + }, + "suggest": { + "symfony/validator": "to validate addresses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "CommerceGuys\\Addressing\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bojan Zivanovic" + }, + { + "name": "Damien Tournoud" + } + ], + "description": "Addressing library powered by CLDR and Google's address data.", + "keywords": [ "address", "internationalization", "localization", "postal" ], "support": { - "issues": "https://github.com/commerceguys/addressing/issues", - "source": "https://github.com/commerceguys/addressing/tree/v2.2.4" + "issues": "https://github.com/commerceguys/addressing/issues", + "source": "https://github.com/commerceguys/addressing/tree/v2.2.5" + }, + "time": "2026-01-05T13:00:32+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2025-08-20T19:15:30+00:00" + }, + { + "name": "craftcms/cms", + "version": "5.10.8.1", + "source": { + "type": "git", + "url": "https://github.com/craftcms/cms.git", + "reference": "dc39613556a054f7674a3bdccdb813b8b7e28b34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/craftcms/cms/zipball/dc39613556a054f7674a3bdccdb813b8b7e28b34", + "reference": "dc39613556a054f7674a3bdccdb813b8b7e28b34", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "^3.0", + "commerceguys/addressing": "^2.1.1", + "composer/semver": "^3.3.2", + "craftcms/plugin-installer": "~1.6.0", + "craftcms/server-check": "~5.1.0", + "craftcms/url-validator": "^1.0", + "creocoder/yii2-nested-sets": "~0.9.0", + "elvanto/litemoji": "~4.3.0", + "enshrined/svg-sanitize": "~0.22.0", + "ext-bcmath": "*", + "ext-curl": "*", + "ext-dom": "*", + "ext-intl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-pcre": "*", + "ext-pdo": "*", + "ext-zip": "*", + "guzzlehttp/guzzle": "^7.2.0", + "illuminate/collections": "^v10.42.0", + "illuminate/support": "^10.49", + "league/uri": "^7.0", + "mikehaertl/php-shellcommand": "^1.6.3", + "moneyphp/money": "^4.0", + "monolog/monolog": "^3.0", + "php": "^8.2", + "phpdocumentor/reflection-docblock": "^5.3", + "phpoffice/phpspreadsheet": "^5.3", + "pixelandtonic/graphql-php": "~14.11.10.1", + "pixelandtonic/imagine": "~1.5.2.1", + "pragmarx/google2fa": "^8.0", + "pragmarx/recovery": "^0.2.1", + "samdark/yii2-psr-log-target": "^1.1.3", + "seld/cli-prompt": "^1.0.4", + "symfony/css-selector": "^6.0|^7.0", + "symfony/dom-crawler": "^6.0|^7.0", + "symfony/filesystem": "^6.3", + "symfony/http-client": "^6.0.3|^7.0", + "symfony/property-access": "^7.0", + "symfony/property-info": "^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^5.0|^6.0|^7.0", + "symfony/yaml": "^5.2.3|^6.0|^7.0", + "theiconic/name-parser": "^1.2", + "twig/twig": "~3.27.0", + "voku/portable-ascii": "^2.0", + "web-auth/webauthn-lib": "~5.2.4", + "yiisoft/yii2": "~2.0.55.0", + "yiisoft/yii2-debug": "~2.1.27.0", + "yiisoft/yii2-queue": "~2.3.2", + "yiisoft/yii2-symfonymailer": "^4.0.0" + }, + "provide": { + "bower-asset/inputmask": "5.0.9", + "bower-asset/jquery": "3.6.1", + "bower-asset/punycode": "^2.2", + "bower-asset/yii2-pjax": "~2.0.1", + "yii2tech/ar-softdelete": "1.0.4" + }, + "require-dev": { + "codeception/codeception": "^5.2.0", + "codeception/lib-innerbrowser": "4.0.1", + "codeception/module-asserts": "^3.0.0", + "codeception/module-datafactory": "^3.0.0", + "codeception/module-phpbrowser": "^3.0.0", + "codeception/module-rest": "^3.3.2", + "codeception/module-yii2": "^1.1.9", + "craftcms/ecs": "dev-main", + "fakerphp/faker": "^1.19.0", + "league/factory-muffin": "^3.3.0", + "phpstan/phpstan": "^2.1", + "rector/rector": "^2.0", + "vlucas/phpdotenv": "^5.4.1", + "yiisoft/yii2-redis": "^2.0" + }, + "suggest": { + "ext-exif": "Adds support for parsing image EXIF data.", + "ext-iconv": "Adds support for more character encodings than PHP’s built-in mb_convert_encoding() function, which Craft will take advantage of when converting strings to UTF-8.", + "ext-imagick": "Adds support for more image processing formats and options." + }, + "type": "library", + "autoload": { + "psr-4": { + "craft\\": "src/", + "yii2tech\\ar\\softdelete\\": "lib/ar-softdelete/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "proprietary" + ], + "authors": [ + { + "name": "Pixel & Tonic", + "homepage": "https://pixelandtonic.com/" + } + ], + "description": "Craft CMS", + "homepage": "https://craftcms.com", + "keywords": [ + "cms", + "craftcms", + "yii2" + ], + "support": { + "docs": "https://craftcms.com/docs/5.x/", + "email": "support@craftcms.com", + "forum": "https://craftcms.stackexchange.com/", + "issues": "https://github.com/craftcms/cms/issues?state=open", + "rss": "https://github.com/craftcms/cms/releases.atom", + "source": "https://github.com/craftcms/cms" + }, + "time": "2026-06-23T15:45:02+00:00" + }, + { + "name": "craftcms/plugin-installer", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/craftcms/plugin-installer.git", + "reference": "bd1650e8da6d5ca7a8527068d3e51c34bc7b6b4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/craftcms/plugin-installer/zipball/bd1650e8da6d5ca7a8527068d3e51c34bc7b6b4f", + "reference": "bd1650e8da6d5ca7a8527068d3e51c34bc7b6b4f", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4" + }, + "require-dev": { + "composer/composer": "^1.0 || ^2.0" + }, + "type": "composer-plugin", + "extra": { + "class": "craft\\composer\\Plugin" + }, + "autoload": { + "psr-4": { + "craft\\composer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Craft CMS Plugin Installer", + "homepage": "https://craftcms.com/", + "keywords": [ + "cms", + "composer", + "craftcms", + "installer", + "plugin" + ], + "support": { + "docs": "https://craftcms.com/docs", + "email": "support@craftcms.com", + "forum": "https://craftcms.stackexchange.com/", + "issues": "https://github.com/craftcms/cms/issues?state=open", + "rss": "https://craftcms.com/changelog.rss", + "source": "https://github.com/craftcms/cms" + }, + "time": "2023-02-22T13:17:00+00:00" + }, + { + "name": "craftcms/server-check", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/craftcms/server-check.git", + "reference": "7a4f1720c4fe1f0731254a82e63060a217f51cdc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/craftcms/server-check/zipball/7a4f1720c4fe1f0731254a82e63060a217f51cdc", + "reference": "7a4f1720c4fe1f0731254a82e63060a217f51cdc", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "server/requirements" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Craft CMS Server Check", + "homepage": "https://craftcms.com/", + "keywords": [ + "cms", + "craftcms", + "requirements", + "yii2" + ], + "support": { + "docs": "https://github.com/craftcms/docs", + "email": "support@craftcms.com", + "forum": "https://craftcms.stackexchange.com/", + "issues": "https://github.com/craftcms/server-check/issues?state=open", + "rss": "https://github.com/craftcms/server-check/releases.atom", + "source": "https://github.com/craftcms/server-check" + }, + "time": "2026-04-07T16:48:35+00:00" + }, + { + "name": "craftcms/url-validator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/craftcms/url-validator.git", + "reference": "75b44bc4d3f89feb9410b85d385f01210edd5eb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/craftcms/url-validator/zipball/75b44bc4d3f89feb9410b85d385f01210edd5eb1", + "reference": "75b44bc4d3f89feb9410b85d385f01210edd5eb1", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.0.2" + }, + "require-dev": { + "laravel/pint": "^1.29", + "nunomaduro/collision": "^8.1", + "pestphp/pest": "^3.0", + "phpstan/phpstan": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "CraftCms\\UrlValidator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pixel & Tonic", + "homepage": "https://pixelandtonic.com/" + } + ], + "description": "Validate URLs and IP addresses against SSRF, DNS rebinding, and cloud-metadata attacks.", + "homepage": "https://github.com/craftcms/url-validator", + "keywords": [ + "IP", + "craftcms", + "security", + "ssrf", + "url", + "validation" + ], + "support": { + "issues": "https://github.com/craftcms/url-validator/issues", + "source": "https://github.com/craftcms/url-validator/tree/1.0.0" + }, + "time": "2026-06-15T17:29:09+00:00" + }, + { + "name": "creocoder/yii2-nested-sets", + "version": "0.9.0", + "source": { + "type": "git", + "url": "https://github.com/creocoder/yii2-nested-sets.git", + "reference": "cb8635a459b6246e5a144f096b992dcc30cf9954" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/creocoder/yii2-nested-sets/zipball/cb8635a459b6246e5a144f096b992dcc30cf9954", + "reference": "cb8635a459b6246e5a144f096b992dcc30cf9954", + "shasum": "" + }, + "require": { + "yiisoft/yii2": "*" + }, + "type": "yii2-extension", + "autoload": { + "psr-4": { + "creocoder\\nestedsets\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Alexander Kochetov", + "email": "creocoder@gmail.com" + } + ], + "description": "The nested sets behavior for the Yii framework", + "keywords": [ + "nested sets", + "yii2" + ], + "support": { + "issues": "https://github.com/creocoder/yii2-nested-sets/issues", + "source": "https://github.com/creocoder/yii2-nested-sets/tree/master" + }, + "time": "2015-01-27T10:53:51+00:00" + }, + { + "name": "dasprid/enum", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "shasum": "" + }, + "require": { + "php": ">=7.1 <9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "support": { + "issues": "https://github.com/DASPRiD/Enum/issues", + "source": "https://github.com/DASPRiD/Enum/tree/1.0.7" + }, + "time": "2025-09-16T12:23:56+00:00" + }, + { + "name": "doctrine/collections", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/7713da39d8e237f28411d6a616a3dce5e20d5de2", + "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1", + "php": "^8.1", + "symfony/polyfill-php84": "^1.30" + }, + "require-dev": { + "doctrine/coding-standard": "^14", + "ext-json": "*", + "phpstan/phpstan": "^2.1.30", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpunit/phpunit": "^10.5.58 || ^11.5.42 || ^12.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/2.6.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcollections", + "type": "tidelift" + } + ], + "time": "2026-01-15T10:01:58+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.6", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=14" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", + "psr/log": "^1 || ^2 || ^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" + }, + "time": "2026-02-07T07:09:04+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2025-08-10T19:31:58+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2025-03-06T22:45:56+00:00" + }, + { + "name": "elvanto/litemoji", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/elvanto/litemoji.git", + "reference": "f13cf10686f7110a3b17d09de03050d0708840b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/elvanto/litemoji/zipball/f13cf10686f7110a3b17d09de03050d0708840b8", + "reference": "f13cf10686f7110a3b17d09de03050d0708840b8", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=7.3" + }, + "require-dev": { + "milesj/emojibase": "7.0.*", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "LitEmoji\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library simplifying the conversion of unicode, HTML and shortcode emoji.", + "keywords": [ + "emoji", + "php-emoji" + ], + "support": { + "issues": "https://github.com/elvanto/litemoji/issues", + "source": "https://github.com/elvanto/litemoji/tree/4.3.0" + }, + "time": "2022-10-28T02:32:19+00:00" + }, + { + "name": "enshrined/svg-sanitize", + "version": "0.22.0", + "source": { + "type": "git", + "url": "https://github.com/darylldoyle/svg-sanitizer.git", + "reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0afa95ea74be155a7bcd6c6fb60c276c39984500", + "reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5 || ^8.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "enshrined\\svgSanitize\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Daryll Doyle", + "email": "daryll@enshrined.co.uk" + } + ], + "description": "An SVG sanitizer for PHP", + "support": { + "issues": "https://github.com/darylldoyle/svg-sanitizer/issues", + "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.22.0" + }, + "time": "2025-08-12T10:13:48+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.19.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0" + }, + "time": "2025-10-17T16:34:55+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.13.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "55901a76dfd2006a0cc012b9e3c5b487f796478d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/55901a76dfd2006a0cc012b9e3c5b487f796478d", + "reference": "55901a76dfd2006a0cc012b9e3c5b487f796478d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.5", + "guzzlehttp/psr7": "^2.12.3", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0", + "symfony/polyfill-php80": "^1.25" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "guzzlehttp/test-server": "^0.6", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.52 || ^9.6.34", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "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": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "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" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.13.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2026-06-29T20:14:18+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "4360e982f87f5f258bf872d094647791db2f4c8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/4360e982f87f5f258bf872d094647791db2f4c8e", + "reference": "4360e982f87f5f258bf872d094647791db2f4c8e", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.52 || ^9.6.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "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": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.5.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2026-06-02T12:23:43+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.12.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7ec62dc3f44aa218487dbed81a9bf9bc647be55d", + "reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0", + "symfony/polyfill-php80": "^1.25" + }, + "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": "1.1.0", + "jshttp/mime-db": "1.54.0.1", + "phpunit/phpunit": "^8.5.52 || ^9.6.34" + }, + "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.12.3" + }, + "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": "2026-06-23T15:21:08+00:00" + }, + { + "name": "illuminate/collections", + "version": "v10.49.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/collections.git", + "reference": "6ae9c74fa92d4e1824d1b346cd435e8eacdc3232" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/collections/zipball/6ae9c74fa92d4e1824d1b346cd435e8eacdc3232", + "reference": "6ae9c74fa92d4e1824d1b346cd435e8eacdc3232", + "shasum": "" + }, + "require": { + "illuminate/conditionable": "^10.0", + "illuminate/contracts": "^10.0", + "illuminate/macroable": "^10.0", + "php": "^8.1" + }, + "suggest": { + "symfony/var-dumper": "Required to use the dump method (^6.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "files": [ + "helpers.php" + ], + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Collections package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-09-08T19:05:53+00:00" + }, + { + "name": "illuminate/conditionable", + "version": "v10.49.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/conditionable.git", + "reference": "47c700320b7a419f0d188d111f3bbed978fcbd3f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/conditionable/zipball/47c700320b7a419f0d188d111f3bbed978fcbd3f", + "reference": "47c700320b7a419f0d188d111f3bbed978fcbd3f", + "shasum": "" + }, + "require": { + "php": "^8.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Conditionable package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-03-24T11:47:24+00:00" + }, + { + "name": "illuminate/contracts", + "version": "v10.49.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/contracts.git", + "reference": "2393ef579e020d88e24283913c815c3e2c143323" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/2393ef579e020d88e24283913c815c3e2c143323", + "reference": "2393ef579e020d88e24283913c815c3e2c143323", + "shasum": "" + }, + "require": { + "php": "^8.1", + "psr/container": "^1.1.1|^2.0.1", + "psr/simple-cache": "^1.0|^2.0|^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Contracts\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Contracts package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "time": "2025-01-13T16:03:24+00:00" + "time": "2025-03-24T11:47:24+00:00" }, { - "name": "composer/semver", - "version": "3.4.4", + "name": "illuminate/macroable", + "version": "v10.49.0", "source": { "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" + "url": "https://github.com/illuminate/macroable.git", + "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "url": "https://api.github.com/repos/illuminate/macroable/zipball/dff667a46ac37b634dcf68909d9d41e94dc97c27", + "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" + "php": "^8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.x-dev" + "dev-master": "10.x-dev" } }, "autoload": { "psr-4": { - "Composer\\Semver\\": "src" + "Illuminate\\Support\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -341,391 +2253,497 @@ ], "authors": [ { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], + "description": "The Illuminate Macroable package.", + "homepage": "https://laravel.com", "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.4" + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, + "time": "2023-06-05T12:46:42+00:00" + }, + { + "name": "illuminate/support", + "version": "v10.49.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/support.git", + "reference": "28b505e671dbe119e4e32a75c78f87189d046e39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/support/zipball/28b505e671dbe119e4e32a75c78f87189d046e39", + "reference": "28b505e671dbe119e4e32a75c78f87189d046e39", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^2.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-mbstring": "*", + "illuminate/collections": "^10.0", + "illuminate/conditionable": "^10.0", + "illuminate/contracts": "^10.0", + "illuminate/macroable": "^10.0", + "nesbot/carbon": "^2.67", + "php": "^8.1", + "voku/portable-ascii": "^2.0" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "suggest": { + "illuminate/filesystem": "Required to use the composer class (^10.0).", + "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.6).", + "ramsey/uuid": "Required to use Str::uuid() (^4.7).", + "symfony/process": "Required to use the composer class (^6.2).", + "symfony/uid": "Required to use Str::ulid() (^6.2).", + "symfony/var-dumper": "Required to use the dd function (^6.2).", + "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.4.1)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "files": [ + "helpers.php" + ], + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "url": "https://github.com/composer", - "type": "github" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "time": "2025-08-20T19:15:30+00:00" + "description": "The Illuminate Support package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-09-08T19:05:53+00:00" }, { - "name": "craftcms/cms", - "version": "5.8.19", + "name": "laravel/pint", + "version": "v1.25.1", "source": { "type": "git", - "url": "https://github.com/craftcms/cms.git", - "reference": "2fdb2031cdf41875121c3f4b0094551ae95a2c38" + "url": "https://github.com/laravel/pint.git", + "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/craftcms/cms/zipball/2fdb2031cdf41875121c3f4b0094551ae95a2c38", - "reference": "2fdb2031cdf41875121c3f4b0094551ae95a2c38", + "url": "https://api.github.com/repos/laravel/pint/zipball/5016e263f95d97670d71b9a987bd8996ade6d8d9", + "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9", "shasum": "" }, "require": { - "bacon/bacon-qr-code": "^2.0", - "commerceguys/addressing": "^2.1.1", - "composer/semver": "^3.3.2", - "craftcms/plugin-installer": "~1.6.0", - "craftcms/server-check": "~5.0.1", - "creocoder/yii2-nested-sets": "~0.9.0", - "elvanto/litemoji": "~4.3.0", - "enshrined/svg-sanitize": "~0.22.0", - "ext-bcmath": "*", - "ext-curl": "*", - "ext-dom": "*", - "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", - "ext-openssl": "*", - "ext-pcre": "*", - "ext-pdo": "*", - "ext-zip": "*", - "guzzlehttp/guzzle": "^7.2.0", - "illuminate/collections": "^v10.42.0", - "league/uri": "^7.0", - "mikehaertl/php-shellcommand": "^1.6.3", - "moneyphp/money": "^4.0", - "monolog/monolog": "^3.0", - "php": "^8.2", - "phpdocumentor/reflection-docblock": "^5.3", - "pixelandtonic/imagine": "~1.3.3.1", - "pragmarx/google2fa": "^8.0", - "pragmarx/recovery": "^0.2.1", - "samdark/yii2-psr-log-target": "^1.1.3", - "seld/cli-prompt": "^1.0.4", - "symfony/css-selector": "^6.0|^7.0", - "symfony/dom-crawler": "^6.0|^7.0", - "symfony/filesystem": "^6.3", - "symfony/http-client": "^6.0.3|^7.0", - "symfony/property-access": "^7.0", - "symfony/property-info": "^7.0", - "symfony/serializer": "^6.4", - "symfony/var-dumper": "^5.0|^6.0|^7.0", - "symfony/yaml": "^5.2.3|^6.0|^7.0", - "theiconic/name-parser": "^1.2", - "twig/twig": "~3.15.0", - "voku/stringy": "^6.4.0", - "web-auth/webauthn-lib": "~4.9.0", - "webonyx/graphql-php": "~14.11.10", - "yiisoft/yii2": "~2.0.52.0", - "yiisoft/yii2-debug": "~2.1.27.0", - "yiisoft/yii2-queue": "~2.3.2", - "yiisoft/yii2-symfonymailer": "^4.0.0" - }, - "provide": { - "bower-asset/inputmask": "5.0.9", - "bower-asset/jquery": "3.6.1", - "bower-asset/punycode": "^1.4", - "bower-asset/yii2-pjax": "~2.0.1", - "yii2tech/ar-softdelete": "1.0.4" + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" }, "require-dev": { - "codeception/codeception": "^5.2.0", - "codeception/lib-innerbrowser": "4.0.1", - "codeception/module-asserts": "^3.0.0", - "codeception/module-datafactory": "^3.0.0", - "codeception/module-phpbrowser": "^3.0.0", - "codeception/module-rest": "^3.3.2", - "codeception/module-yii2": "^1.1.9", - "craftcms/ecs": "dev-main", - "fakerphp/faker": "^1.19.0", - "league/factory-muffin": "^3.3.0", - "phpstan/phpstan": "^2.1", - "rector/rector": "^2.0", - "vlucas/phpdotenv": "^5.4.1", - "yiisoft/yii2-redis": "^2.0" - }, - "suggest": { - "ext-exif": "Adds support for parsing image EXIF data.", - "ext-iconv": "Adds support for more character encodings than PHP’s built-in mb_convert_encoding() function, which Craft will take advantage of when converting strings to UTF-8.", - "ext-imagick": "Adds support for more image processing formats and options." + "friendsofphp/php-cs-fixer": "^3.87.2", + "illuminate/view": "^11.46.0", + "larastan/larastan": "^3.7.1", + "laravel-zero/framework": "^11.45.0", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3.1", + "pestphp/pest": "^2.36.0" }, - "type": "library", + "bin": [ + "builds/pint" + ], + "type": "project", "autoload": { "psr-4": { - "craft\\": "src/", - "yii2tech\\ar\\softdelete\\": "lib/ar-softdelete/src/" + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "proprietary" + "MIT" ], "authors": [ { - "name": "Pixel & Tonic", - "homepage": "https://pixelandtonic.com/" + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" } ], - "description": "Craft CMS", - "homepage": "https://craftcms.com", + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", "keywords": [ - "cms", - "craftcms", - "yii2" + "format", + "formatter", + "lint", + "linter", + "php" ], "support": { - "docs": "https://craftcms.com/docs/5.x/", - "email": "support@craftcms.com", - "forum": "https://craftcms.stackexchange.com/", - "issues": "https://github.com/craftcms/cms/issues?state=open", - "rss": "https://github.com/craftcms/cms/releases.atom", - "source": "https://github.com/craftcms/cms" + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" }, - "time": "2025-10-28T19:21:54+00:00" + "time": "2025-09-19T02:57:12+00:00" }, { - "name": "craftcms/plugin-installer", - "version": "1.6.0", + "name": "league/uri", + "version": "7.8.1", "source": { "type": "git", - "url": "https://github.com/craftcms/plugin-installer.git", - "reference": "bd1650e8da6d5ca7a8527068d3e51c34bc7b6b4f" + "url": "https://github.com/thephpleague/uri.git", + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/craftcms/plugin-installer/zipball/bd1650e8da6d5ca7a8527068d3e51c34bc7b6b4f", - "reference": "bd1650e8da6d5ca7a8527068d3e51c34bc7b6b4f", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/08cf38e3924d4f56238125547b5720496fac8fd4", + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.4" + "league/uri-interfaces": "^7.8.1", + "php": "^8.1", + "psr/http-factory": "^1" }, - "require-dev": { - "composer/composer": "^1.0 || ^2.0" + "conflict": { + "league/uri-schemes": "^1.0" }, - "type": "composer-plugin", + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", + "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", "extra": { - "class": "craft\\composer\\Plugin" + "branch-alias": { + "dev-master": "7.x-dev" + } }, "autoload": { "psr-4": { - "craft\\composer\\": "src/" + "League\\Uri\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Craft CMS Plugin Installer", - "homepage": "https://craftcms.com/", + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", "keywords": [ - "cms", - "composer", - "craftcms", - "installer", - "plugin" + "URN", + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc2141", + "rfc3986", + "rfc3987", + "rfc6570", + "rfc8141", + "uri", + "uri-template", + "url", + "ws" ], "support": { - "docs": "https://craftcms.com/docs", - "email": "support@craftcms.com", - "forum": "https://craftcms.stackexchange.com/", - "issues": "https://github.com/craftcms/cms/issues?state=open", - "rss": "https://craftcms.com/changelog.rss", - "source": "https://github.com/craftcms/cms" + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.8.1" }, - "time": "2023-02-22T13:17:00+00:00" + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-03-15T20:22:25+00:00" }, { - "name": "craftcms/server-check", - "version": "5.0.4", + "name": "league/uri-interfaces", + "version": "7.8.1", "source": { "type": "git", - "url": "https://github.com/craftcms/server-check.git", - "reference": "3b1f239c1cc781710978b0baa3e3bc99410d1973" + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/craftcms/server-check/zipball/3b1f239c1cc781710978b0baa3e3bc99410d1973", - "reference": "3b1f239c1cc781710978b0baa3e3bc99410d1973", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/85d5c77c5d6d3af6c54db4a78246364908f3c928", + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928", "shasum": "" }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, "autoload": { - "classmap": [ - "server/requirements" - ] + "psr-4": { + "League\\Uri\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Craft CMS Server Check", - "homepage": "https://craftcms.com/", + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", + "homepage": "https://uri.thephpleague.com", "keywords": [ - "cms", - "craftcms", - "requirements", - "yii2" + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" ], "support": { - "docs": "https://github.com/craftcms/docs", - "email": "support@craftcms.com", - "forum": "https://craftcms.stackexchange.com/", - "issues": "https://github.com/craftcms/server-check/issues?state=open", - "rss": "https://github.com/craftcms/server-check/releases.atom", - "source": "https://github.com/craftcms/server-check" + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.1" }, - "time": "2025-07-23T14:22:43+00:00" + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-03-08T20:05:35+00:00" }, { - "name": "creocoder/yii2-nested-sets", - "version": "0.9.0", + "name": "maennchen/zipstream-php", + "version": "3.2.2", "source": { "type": "git", - "url": "https://github.com/creocoder/yii2-nested-sets.git", - "reference": "cb8635a459b6246e5a144f096b992dcc30cf9954" + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/creocoder/yii2-nested-sets/zipball/cb8635a459b6246e5a144f096b992dcc30cf9954", - "reference": "cb8635a459b6246e5a144f096b992dcc30cf9954", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e", + "reference": "77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e", "shasum": "" }, "require": { - "yiisoft/yii2": "*" + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.3" }, - "type": "yii2-extension", + "require-dev": { + "brianium/paratest": "^7.7", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.86", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^12.0", + "vimeo/psalm": "^6.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", "autoload": { "psr-4": { - "creocoder\\nestedsets\\": "src" + "ZipStream\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Alexander Kochetov", - "email": "creocoder@gmail.com" + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" } ], - "description": "The nested sets behavior for the Yii framework", + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", "keywords": [ - "nested sets", - "yii2" + "stream", + "zip" ], "support": { - "issues": "https://github.com/creocoder/yii2-nested-sets/issues", - "source": "https://github.com/creocoder/yii2-nested-sets/tree/master" + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.2" }, - "time": "2015-01-27T10:53:51+00:00" + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + } + ], + "time": "2026-04-11T18:38:28+00:00" }, { - "name": "dasprid/enum", - "version": "1.0.7", + "name": "markbaker/complex", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/DASPRiD/Enum.git", - "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce" + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce", - "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", "shasum": "" }, "require": { - "php": ">=7.1 <9.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", - "squizlabs/php_codesniffer": "*" + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" }, "type": "library", "autoload": { "psr-4": { - "DASPRiD\\Enum\\": "src/" + "Complex\\": "classes/src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "MIT" ], "authors": [ { - "name": "Ben Scholzen 'DASPRiD'", - "email": "mail@dasprids.de", - "homepage": "https://dasprids.de/", - "role": "Developer" + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" } ], - "description": "PHP 7.1 enum implementation", + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", "keywords": [ - "enum", - "map" + "complex", + "mathematics" ], "support": { - "issues": "https://github.com/DASPRiD/Enum/issues", - "source": "https://github.com/DASPRiD/Enum/tree/1.0.7" + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" }, - "time": "2025-09-16T12:23:56+00:00" + "time": "2022-12-06T16:21:08+00:00" }, { - "name": "defuse/php-encryption", - "version": "v2.4.0", + "name": "markbaker/matrix", + "version": "3.0.1", "source": { "type": "git", - "url": "https://github.com/defuse/php-encryption.git", - "reference": "f53396c2d34225064647a05ca76c1da9d99e5828" + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/defuse/php-encryption/zipball/f53396c2d34225064647a05ca76c1da9d99e5828", - "reference": "f53396c2d34225064647a05ca76c1da9d99e5828", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", "shasum": "" }, "require": { - "ext-openssl": "*", - "paragonie/random_compat": ">= 2", - "php": ">=5.6.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^5|^6|^7|^8|^9|^10", - "yoast/phpunit-polyfills": "^2.0.0" + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" }, - "bin": [ - "bin/generate-defuse-key" - ], "type": "library", "autoload": { "psr-4": { - "Defuse\\Crypto\\": "src" + "Matrix\\": "classes/src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -734,65 +2752,53 @@ ], "authors": [ { - "name": "Taylor Hornby", - "email": "taylor@defuse.ca", - "homepage": "https://defuse.ca/" - }, - { - "name": "Scott Arciszewski", - "email": "info@paragonie.com", - "homepage": "https://paragonie.com" + "name": "Mark Baker", + "email": "mark@demon-angel.eu" } ], - "description": "Secure PHP Encryption Library", + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", "keywords": [ - "aes", - "authenticated encryption", - "cipher", - "crypto", - "cryptography", - "encrypt", - "encryption", - "openssl", - "security", - "symmetric key cryptography" + "mathematics", + "matrix", + "vector" ], "support": { - "issues": "https://github.com/defuse/php-encryption/issues", - "source": "https://github.com/defuse/php-encryption/tree/v2.4.0" + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" }, - "time": "2023-06-19T06:10:36+00:00" + "time": "2022-12-02T22:17:43+00:00" }, { - "name": "doctrine/collections", - "version": "2.4.0", + "name": "masterminds/html5", + "version": "2.10.1", "source": { "type": "git", - "url": "https://github.com/doctrine/collections.git", - "reference": "9acfeea2e8666536edff3d77c531261c63680160" + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "fd5018f6815fff903946d0564977b44ce8010e29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/9acfeea2e8666536edff3d77c531261c63680160", - "reference": "9acfeea2e8666536edff3d77c531261c63680160", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fd5018f6815fff903946d0564977b44ce8010e29", + "reference": "fd5018f6815fff903946d0564977b44ce8010e29", "shasum": "" }, "require": { - "doctrine/deprecations": "^1", - "php": "^8.1", - "symfony/polyfill-php84": "^1.30" + "ext-dom": "*", + "php": ">=5.3.0" }, "require-dev": { - "doctrine/coding-standard": "^14", - "ext-json": "*", - "phpstan/phpstan": "^2.1.30", - "phpstan/phpstan-phpunit": "^2.0.7", - "phpunit/phpunit": "^10.5.58 || ^11.5.42 || ^12.4" + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9 || ^10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } }, - "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\Collections\\": "src" + "Masterminds\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -801,130 +2807,137 @@ ], "authors": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" + "name": "Matt Butcher", + "email": "technosophos@gmail.com" }, { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" + "name": "Matt Farina", + "email": "matt@mattfarina.com" }, { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" } ], - "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", - "homepage": "https://www.doctrine-project.org/projects/collections.html", + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", "keywords": [ - "array", - "collections", - "iterators", - "php" + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" ], "support": { - "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/2.4.0" + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.1" }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcollections", - "type": "tidelift" - } - ], - "time": "2025-10-25T09:18:13+00:00" + "time": "2026-06-23T18:43:15+00:00" }, { - "name": "doctrine/deprecations", - "version": "1.1.5", + "name": "mikehaertl/php-shellcommand", + "version": "1.7.0", "source": { "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "url": "https://github.com/mikehaertl/php-shellcommand.git", + "reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/mikehaertl/php-shellcommand/zipball/e79ea528be155ffdec6f3bf1a4a46307bb49e545", + "reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" + "php": ">= 5.3.0" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", - "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", - "psr/log": "^1 || ^2 || ^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + "phpunit/phpunit": ">4.0 <=9.4" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "src" + "mikehaertl\\shellcommand\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", + "authors": [ + { + "name": "Michael Härtl", + "email": "haertl.mike@gmail.com" + } + ], + "description": "An object oriented interface to shell commands", + "keywords": [ + "shell" + ], "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "issues": "https://github.com/mikehaertl/php-shellcommand/issues", + "source": "https://github.com/mikehaertl/php-shellcommand/tree/1.7.0" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2023-04-19T08:25:22+00:00" }, { - "name": "doctrine/lexer", - "version": "3.0.1", + "name": "moneyphp/money", + "version": "v4.9.0", "source": { "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + "url": "https://github.com/moneyphp/money.git", + "reference": "d49ee625c6ba79b9d7a228ce153b02fc1032152b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "url": "https://api.github.com/repos/moneyphp/money/zipball/d49ee625c6ba79b9d7a228ce153b02fc1032152b", + "reference": "d49ee625c6ba79b9d7a228ce153b02fc1032152b", "shasum": "" }, "require": { - "php": "^8.1" + "ext-bcmath": "*", + "ext-filter": "*", + "ext-json": "*", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" }, "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10.5", - "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^5.21" + "cache/taggable-cache": "^1.1.0", + "doctrine/coding-standard": "^12.0", + "doctrine/instantiator": "^1.5.0 || ^2.0", + "ext-gmp": "*", + "ext-intl": "*", + "florianv/exchanger": "^2.8.1", + "florianv/swap": "^4.3.0", + "moneyphp/crypto-currencies": "^1.1.0", + "moneyphp/iso-currencies": "^3.4", + "php-http/message": "^1.16.0", + "php-http/mock-client": "^1.6.0", + "phpbench/phpbench": "^1.2.5", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1.9", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5.9", + "psr/cache": "^1.0.1 || ^2.0 || ^3.0", + "ticketswap/phpstan-error-formatter": "^1.1" + }, + "suggest": { + "ext-gmp": "Calculate without integer limits", + "ext-intl": "Format Money objects with intl", + "florianv/exchanger": "Exchange rates library for PHP", + "florianv/swap": "Exchange rates library for PHP", + "psr/cache-implementation": "Used for Currency caching" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, "autoload": { "psr-4": { - "Doctrine\\Common\\Lexer\\": "src" + "Money\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -933,82 +2946,99 @@ ], "authors": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" + "name": "Mathias Verraes", + "email": "mathias@verraes.net", + "homepage": "http://verraes.net" }, { - "name": "Roman Borschel", - "email": "roman@code-factory.org" + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" }, { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Frederik Bosch", + "email": "f.bosch@genkgo.nl" } ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "description": "PHP implementation of Fowler's Money pattern", + "homepage": "http://moneyphp.org", "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" + "Value Object", + "money", + "vo" ], "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/3.0.1" + "issues": "https://github.com/moneyphp/money/issues", + "source": "https://github.com/moneyphp/money/tree/v4.9.0" }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], - "time": "2024-02-05T11:56:58+00:00" + "time": "2026-05-04T20:23:15+00:00" }, { - "name": "egulias/email-validator", - "version": "4.0.4", + "name": "monolog/monolog", + "version": "3.10.0", "source": { "type": "git", - "url": "https://github.com/egulias/EmailValidator.git", - "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + "url": "https://github.com/Seldaek/monolog.git", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", - "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", "shasum": "" }, "require": { - "doctrine/lexer": "^2.0 || ^3.0", "php": ">=8.1", - "symfony/polyfill-intl-idn": "^1.26" + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" }, "require-dev": { - "phpunit/phpunit": "^10.2", - "vimeo/psalm": "^5.12" + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8 || ^2.0", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "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", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" }, "suggest": { - "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-main": "3.x-dev" } }, "autoload": { "psr-4": { - "Egulias\\EmailValidator\\": "src" + "Monolog\\": "src/Monolog" } }, "notification-url": "https://packagist.org/downloads/", @@ -1017,230 +3047,286 @@ ], "authors": [ { - "name": "Eduardo Gulias Davis" + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" } ], - "description": "A library for validating emails against several RFCs", - "homepage": "https://github.com/egulias/EmailValidator", + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ - "email", - "emailvalidation", - "emailvalidator", - "validation", - "validator" + "log", + "logging", + "psr-3" ], "support": { - "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" }, "funding": [ { - "url": "https://github.com/egulias", + "url": "https://github.com/Seldaek", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" } ], - "time": "2025-03-06T22:45:56+00:00" + "time": "2026-01-02T08:56:05+00:00" }, { - "name": "elvanto/litemoji", - "version": "4.3.0", + "name": "myclabs/deep-copy", + "version": "1.13.4", "source": { "type": "git", - "url": "https://github.com/elvanto/litemoji.git", - "reference": "f13cf10686f7110a3b17d09de03050d0708840b8" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/elvanto/litemoji/zipball/f13cf10686f7110a3b17d09de03050d0708840b8", - "reference": "f13cf10686f7110a3b17d09de03050d0708840b8", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": ">=7.3" + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { - "milesj/emojibase": "7.0.*", - "phpunit/phpunit": "^9.0" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], "psr-4": { - "LitEmoji\\": "src/" + "DeepCopy\\": "src/DeepCopy/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "A PHP library simplifying the conversion of unicode, HTML and shortcode emoji.", + "description": "Create deep copies (clones) of your objects", "keywords": [ - "emoji", - "php-emoji" + "clone", + "copy", + "duplicate", + "object", + "object graph" ], "support": { - "issues": "https://github.com/elvanto/litemoji/issues", - "source": "https://github.com/elvanto/litemoji/tree/4.3.0" + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, - "time": "2022-10-28T02:32:19+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" }, { - "name": "enshrined/svg-sanitize", - "version": "0.22.0", + "name": "nesbot/carbon", + "version": "2.73.0", "source": { "type": "git", - "url": "https://github.com/darylldoyle/svg-sanitizer.git", - "reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500" + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "9228ce90e1035ff2f0db84b40ec2e023ed802075" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0afa95ea74be155a7bcd6c6fb60c276c39984500", - "reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/9228ce90e1035ff2f0db84b40ec2e023ed802075", + "reference": "9228ce90e1035ff2f0db84b40ec2e023ed802075", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-libxml": "*", - "php": "^7.1 || ^8.0" + "carbonphp/carbon-doctrine-types": "*", + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "psr/clock": "^1.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + }, + "provide": { + "psr/clock-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "^6.5 || ^8.5" + "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", + "doctrine/orm": "^2.7 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.0", + "kylekatarnls/multi-tester": "^2.0", + "ondrejmirtes/better-reflection": "<6", + "phpmd/phpmd": "^2.9", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.99 || ^1.7.14", + "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", + "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", + "squizlabs/php_codesniffer": "^3.4" }, + "bin": [ + "bin/carbon" + ], "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" + } + }, "autoload": { "psr-4": { - "enshrined\\svgSanitize\\": "src" + "Carbon\\": "src/Carbon/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "GPL-2.0-or-later" + "MIT" ], "authors": [ { - "name": "Daryll Doyle", - "email": "daryll@enshrined.co.uk" + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" } ], - "description": "An SVG sanitizer for PHP", + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], "support": { - "issues": "https://github.com/darylldoyle/svg-sanitizer/issues", - "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.22.0" + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" }, - "time": "2025-08-12T10:13:48+00:00" + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2025-01-08T20:10:23+00:00" }, { - "name": "ezyang/htmlpurifier", - "version": "v4.19.0", + "name": "nikic/php-parser", + "version": "v5.7.0", "source": { "type": "git", - "url": "https://github.com/ezyang/htmlpurifier.git", - "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf", - "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { - "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" }, "require-dev": { - "cerdic/css-tidy": "^1.7 || ^2.0", - "simpletest/simpletest": "dev-master" - }, - "suggest": { - "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", - "ext-bcmath": "Used for unit conversion and imagecrash protection", - "ext-iconv": "Converts text to and from non-UTF-8 encodings", - "ext-tidy": "Used for pretty-printing HTML" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" }, + "bin": [ + "bin/php-parse" + ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, "autoload": { - "files": [ - "library/HTMLPurifier.composer.php" - ], - "psr-0": { - "HTMLPurifier": "library/" - }, - "exclude-from-classmap": [ - "/library/HTMLPurifier/Language/" - ] + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-2.1-or-later" + "BSD-3-Clause" ], "authors": [ { - "name": "Edward Z. Yang", - "email": "admin@htmlpurifier.org", - "homepage": "http://ezyang.com" + "name": "Nikita Popov" } ], - "description": "Standards compliant HTML filter written in PHP", - "homepage": "http://htmlpurifier.org/", + "description": "A PHP parser written in PHP", "keywords": [ - "html" + "parser", + "php" ], "support": { - "issues": "https://github.com/ezyang/htmlpurifier/issues", - "source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0" + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-17T16:34:55+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "7.10.0", + "name": "paragonie/constant_time_encoding", + "version": "v3.1.3", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", - "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", "shasum": "" }, "require": { - "ext-json": "*", - "guzzlehttp/promises": "^2.3", - "guzzlehttp/psr7": "^2.8", - "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0" - }, - "provide": { - "psr/http-client-implementation": "1.0" + "php": "^8" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-curl": "*", - "guzzle/client-integration-tests": "3.0.2", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.39 || ^9.6.20", - "psr/log": "^1.1 || ^2.0 || ^3.0" - }, - "suggest": { - "ext-curl": "Required for CURL handler support", - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { - "GuzzleHttp\\": "src/" + "ParagonIE\\ConstantTime\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1249,198 +3335,184 @@ ], "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": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia" - }, - { - "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": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" }, { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" } ], - "description": "Guzzle is a PHP HTTP client library", + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "psr-18", - "psr-7", - "rest", - "web service" + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" ], "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.10.0" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", - "type": "tidelift" - } - ], - "time": "2025-08-23T22:36:01+00:00" + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2025-09-24T15:06:41+00:00" }, { - "name": "guzzlehttp/promises", - "version": "2.3.0", + "name": "phar-io/manifest", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "481557b130ef3790cf82b713667b43030dc9c957" + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", - "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.44 || ^9.6.25" + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false + "branch-alias": { + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "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": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" }, { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" }, { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.3.0" + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, "funding": [ { - "url": "https://github.com/GrahamCampbell", + "url": "https://github.com/theseer", "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" }, { - "url": "https://github.com/Nyholm", - "type": "github" + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" }, { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", - "type": "tidelift" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "time": "2025-08-22T14:34:08+00:00" + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" }, { - "name": "guzzlehttp/psr7", - "version": "2.8.0", + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", "source": { "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "21dc724a0583619cd1652f673303492272778051" + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", - "reference": "21dc724a0583619cd1652f673303492272778051", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", "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" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false + "branch-alias": { + "dev-2.x": "2.x-dev" } }, "autoload": { "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1449,107 +3521,66 @@ ], "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" + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" } ], - "description": "PSR-7 message implementation that also provides common utility methods", + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" ], "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.8.0" + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" }, - "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" + "time": "2020-06-27T09:03:43+00:00" }, { - "name": "illuminate/collections", - "version": "v10.49.0", + "name": "phpdocumentor/reflection-docblock", + "version": "5.6.7", "source": { "type": "git", - "url": "https://github.com/illuminate/collections.git", - "reference": "6ae9c74fa92d4e1824d1b346cd435e8eacdc3232" + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "31a105931bc8ffa3a123383829772e832fd8d903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/6ae9c74fa92d4e1824d1b346cd435e8eacdc3232", - "reference": "6ae9c74fa92d4e1824d1b346cd435e8eacdc3232", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/31a105931bc8ffa3a123383829772e832fd8d903", + "reference": "31a105931bc8ffa3a123383829772e832fd8d903", "shasum": "" }, "require": { - "illuminate/conditionable": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/macroable": "^10.0", - "php": "^8.1" + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", + "webmozart/assert": "^1.9.1 || ^2" }, - "suggest": { - "symfony/var-dumper": "Required to use the dump method (^6.2)." + "require-dev": { + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { - "files": [ - "helpers.php" - ], "psr-4": { - "Illuminate\\Support\\": "" + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1558,44 +3589,60 @@ ], "authors": [ { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" } ], - "description": "The Illuminate Collections package.", - "homepage": "https://laravel.com", + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.7" }, - "time": "2025-09-08T19:05:53+00:00" + "time": "2026-03-18T20:47:46+00:00" }, { - "name": "illuminate/conditionable", - "version": "v10.49.0", + "name": "phpdocumentor/type-resolver", + "version": "1.12.0", "source": { "type": "git", - "url": "https://github.com/illuminate/conditionable.git", - "reference": "47c700320b7a419f0d188d111f3bbed978fcbd3f" + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/conditionable/zipball/47c700320b7a419f0d188d111f3bbed978fcbd3f", - "reference": "47c700320b7a419f0d188d111f3bbed978fcbd3f", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195", + "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195", "shasum": "" }, "require": { - "php": "^8.0.2" + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.18|^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { "psr-4": { - "Illuminate\\Support\\": "" + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1604,46 +3651,79 @@ ], "authors": [ { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" + "name": "Mike van Riel", + "email": "me@mikevanriel.com" } ], - "description": "The Illuminate Conditionable package.", - "homepage": "https://laravel.com", + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0" }, - "time": "2025-03-24T11:47:24+00:00" + "time": "2025-11-21T15:09:14+00:00" }, { - "name": "illuminate/contracts", - "version": "v10.49.0", + "name": "phpoffice/phpspreadsheet", + "version": "5.8.0", "source": { "type": "git", - "url": "https://github.com/illuminate/contracts.git", - "reference": "2393ef579e020d88e24283913c815c3e2c143323" + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "01964d92536edf1a3a874b9580a52824bebf6fbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/2393ef579e020d88e24283913c815c3e2c143323", - "reference": "2393ef579e020d88e24283913c815c3e2c143323", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/01964d92536edf1a3a874b9580a52824bebf6fbb", + "reference": "01964d92536edf1a3a874b9580a52824bebf6fbb", "shasum": "" }, "require": { + "composer/pcre": "^1||^2||^3", + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-filter": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", "php": "^8.1", - "psr/container": "^1.1.1|^2.0.1", - "psr/simple-cache": "^1.0|^2.0|^3.0" + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^2.0 || ^3.0", + "ext-intl": "*", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.5", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1 || ^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0", + "phpstan/phpstan-phpunit": "^1.0 || ^2.0", + "phpunit/phpunit": "^10.5", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions, required for NumberFormat Wizard and StringHelper::setLocale()", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" }, + "type": "library", "autoload": { "psr-4": { - "Illuminate\\Contracts\\": "" + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" } }, "notification-url": "https://packagist.org/downloads/", @@ -1652,638 +3732,648 @@ ], "authors": [ { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + }, + { + "name": "Owen Leibman" } ], - "description": "The Illuminate Contracts package.", - "homepage": "https://laravel.com", + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/5.8.0" }, - "time": "2025-03-24T11:47:24+00:00" + "time": "2026-06-07T03:51:10+00:00" }, { - "name": "illuminate/macroable", - "version": "v10.49.0", + "name": "phpstan/phpdoc-parser", + "version": "2.3.2", "source": { "type": "git", - "url": "https://github.com/illuminate/macroable.git", - "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27" + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/macroable/zipball/dff667a46ac37b634dcf68909d9d41e94dc97c27", - "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "shasum": "" }, "require": { - "php": "^8.1" + "php": "^7.4 || ^8.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" }, + "type": "library", "autoload": { "psr-4": { - "Illuminate\\Support\\": "" + "PHPStan\\PhpDocParser\\": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Macroable package.", - "homepage": "https://laravel.com", + "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" }, - "time": "2023-06-05T12:46:42+00:00" + "time": "2026-01-25T14:56:51+00:00" }, { - "name": "laravel/pint", - "version": "v1.25.1", + "name": "phpunit/php-code-coverage", + "version": "11.0.12", "source": { "type": "git", - "url": "https://github.com/laravel/pint.git", - "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/5016e263f95d97670d71b9a987bd8996ade6d8d9", - "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", "shasum": "" }, "require": { - "ext-json": "*", - "ext-mbstring": "*", - "ext-tokenizer": "*", - "ext-xml": "*", - "php": "^8.2.0" + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.87.2", - "illuminate/view": "^11.46.0", - "larastan/larastan": "^3.7.1", - "laravel-zero/framework": "^11.45.0", - "mockery/mockery": "^1.6.12", - "nunomaduro/termwind": "^2.3.1", - "pestphp/pest": "^2.36.0" + "phpunit/phpunit": "^11.5.46" }, - "bin": [ - "builds/pint" - ], - "type": "project", - "autoload": { - "psr-4": { - "App\\": "app/", - "Database\\Seeders\\": "database/seeders/", - "Database\\Factories\\": "database/factories/" + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "An opinionated code formatter for PHP.", - "homepage": "https://laravel.com", + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", "keywords": [ - "format", - "formatter", - "lint", - "linter", - "php" + "coverage", + "testing", + "xunit" ], "support": { - "issues": "https://github.com/laravel/pint/issues", - "source": "https://github.com/laravel/pint" + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" }, - "time": "2025-09-19T02:57:12+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-24T07:01:01+00:00" }, { - "name": "lcobucci/clock", - "version": "3.5.0", + "name": "phpunit/php-file-iterator", + "version": "5.1.1", "source": { "type": "git", - "url": "https://github.com/lcobucci/clock.git", - "reference": "a3139d9e97d47826f27e6a17bb63f13621f86058" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/clock/zipball/a3139d9e97d47826f27e6a17bb63f13621f86058", - "reference": "a3139d9e97d47826f27e6a17bb63f13621f86058", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { - "php": "~8.3.0 || ~8.4.0 || ~8.5.0", - "psr/clock": "^1.0" - }, - "provide": { - "psr/clock-implementation": "1.0" + "php": ">=8.2" }, "require-dev": { - "infection/infection": "^0.31", - "lcobucci/coding-standard": "^11.2.0", - "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^2.0.0", - "phpstan/phpstan-deprecation-rules": "^2.0.0", - "phpstan/phpstan-phpunit": "^2.0.0", - "phpstan/phpstan-strict-rules": "^2.0.0", - "phpunit/phpunit": "^12.0.0" + "phpunit/phpunit": "^11.3" }, "type": "library", - "autoload": { - "psr-4": { - "Lcobucci\\Clock\\": "src" + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Luís Cobucci", - "email": "lcobucci@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Yet another clock abstraction", + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], "support": { - "issues": "https://github.com/lcobucci/clock/issues", - "source": "https://github.com/lcobucci/clock/tree/3.5.0" + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" }, "funding": [ { - "url": "https://github.com/lcobucci", + "url": "https://github.com/sebastianbergmann", "type": "github" }, { - "url": "https://www.patreon.com/lcobucci", - "type": "patreon" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2025-10-27T09:03:17+00:00" + "time": "2026-02-02T13:52:54+00:00" }, { - "name": "league/uri", - "version": "7.5.1", + "name": "phpunit/php-invoker", + "version": "5.0.1", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "php": ">=8.2" }, - "conflict": { - "league/uri-schemes": "^1.0" + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" }, "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", - "ext-fileinfo": "to create Data URI from file contennts", - "ext-gmp": "to improve IPV4 host parsing", - "ext-intl": "to handle IDN host with the best performance", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", - "php-64bit": "to improve IPV4 host parsing", - "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + "ext-pcntl": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-main": "5.0-dev" } }, "autoload": { - "psr-4": { - "League\\Uri\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://nyamsprod.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "URI manipulation library", - "homepage": "https://uri.thephpleague.com", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "data-uri", - "file-uri", - "ftp", - "hostname", - "http", - "https", - "middleware", - "parse_str", - "parse_url", - "psr-7", - "query-string", - "querystring", - "rfc3986", - "rfc3987", - "rfc6570", - "uri", - "uri-template", - "url", - "ws" + "process" ], "support": { - "docs": "https://uri.thephpleague.com", - "forum": "https://thephpleague.slack.com", - "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" }, "funding": [ { - "url": "https://github.com/sponsors/nyamsprod", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2024-07-03T05:07:44+00:00" }, { - "name": "league/uri-interfaces", - "version": "7.5.0", + "name": "phpunit/php-text-template", + "version": "4.0.1", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^8.1", - "psr/http-factory": "^1", - "psr/http-message": "^1.1 || ^2.0" - }, - "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", - "ext-gmp": "to improve IPV4 host parsing", - "ext-intl": "to handle IDN host with the best performance", - "php-64bit": "to improve IPV4 host parsing", - "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-main": "4.0-dev" } }, "autoload": { - "psr-4": { - "League\\Uri\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://nyamsprod.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Common interfaces and classes for URI representation and interaction", - "homepage": "https://uri.thephpleague.com", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ - "data-uri", - "file-uri", - "ftp", - "hostname", - "http", - "https", - "parse_str", - "parse_url", - "psr-7", - "query-string", - "querystring", - "rfc3986", - "rfc3987", - "rfc6570", - "uri", - "url", - "ws" + "template" ], "support": { - "docs": "https://uri.thephpleague.com", - "forum": "https://thephpleague.slack.com", - "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" }, "funding": [ { - "url": "https://github.com/sponsors/nyamsprod", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2024-12-08T08:18:47+00:00" + "time": "2024-07-03T05:08:43+00:00" }, { - "name": "masterminds/html5", - "version": "2.10.0", + "name": "phpunit/php-timer", + "version": "7.0.1", "source": { "type": "git", - "url": "https://github.com/Masterminds/html5-php.git", - "reference": "fcf91eb64359852f00d921887b219479b4f21251" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", - "reference": "fcf91eb64359852f00d921887b219479b4f21251", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", "shasum": "" }, "require": { - "ext-dom": "*", - "php": ">=5.3.0" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-main": "7.0-dev" } }, "autoload": { - "psr-4": { - "Masterminds\\": "src" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Matt Butcher", - "email": "technosophos@gmail.com" - }, - { - "name": "Matt Farina", - "email": "matt@mattfarina.com" - }, - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "An HTML5 parser and serializer.", - "homepage": "http://masterminds.github.io/html5-php", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "HTML5", - "dom", - "html", - "parser", - "querypath", - "serializer", - "xml" + "timer" ], "support": { - "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" }, - "time": "2025-07-25T09:04:22+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" }, { - "name": "mikehaertl/php-shellcommand", - "version": "1.7.0", + "name": "phpunit/phpunit", + "version": "11.5.55", "source": { "type": "git", - "url": "https://github.com/mikehaertl/php-shellcommand.git", - "reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545" + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mikehaertl/php-shellcommand/zipball/e79ea528be155ffdec6f3bf1a4a46307bb49e545", - "reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", "shasum": "" }, "require": { - "php": ">= 5.3.0" + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" }, - "require-dev": { - "phpunit/phpunit": ">4.0 <=9.4" + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" }, + "bin": [ + "phpunit" + ], "type": "library", - "autoload": { - "psr-4": { - "mikehaertl\\shellcommand\\": "src/" + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" } }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Michael Härtl", - "email": "haertl.mike@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "An object oriented interface to shell commands", + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", "keywords": [ - "shell" + "phpunit", + "testing", + "xunit" ], "support": { - "issues": "https://github.com/mikehaertl/php-shellcommand/issues", - "source": "https://github.com/mikehaertl/php-shellcommand/tree/1.7.0" + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" }, - "time": "2023-04-19T08:25:22+00:00" + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2026-02-18T12:37:06+00:00" }, { - "name": "moneyphp/money", - "version": "v4.8.0", + "name": "pixelandtonic/graphql-php", + "version": "v14.11.10.1", "source": { "type": "git", - "url": "https://github.com/moneyphp/money.git", - "reference": "b358727ea5a5cd2d7475e59c31dfc352440ae7ec" + "url": "https://github.com/pixelandtonic/graphql-php.git", + "reference": "fdb4a288878fc9ee449245e17209d676fc7c57fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/moneyphp/money/zipball/b358727ea5a5cd2d7475e59c31dfc352440ae7ec", - "reference": "b358727ea5a5cd2d7475e59c31dfc352440ae7ec", + "url": "https://api.github.com/repos/pixelandtonic/graphql-php/zipball/fdb4a288878fc9ee449245e17209d676fc7c57fd", + "reference": "fdb4a288878fc9ee449245e17209d676fc7c57fd", "shasum": "" }, "require": { - "ext-bcmath": "*", - "ext-filter": "*", "ext-json": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + "ext-mbstring": "*", + "php": "^7.1 || ^8" }, "require-dev": { - "cache/taggable-cache": "^1.1.0", - "doctrine/coding-standard": "^12.0", - "doctrine/instantiator": "^1.5.0 || ^2.0", - "ext-gmp": "*", - "ext-intl": "*", - "florianv/exchanger": "^2.8.1", - "florianv/swap": "^4.3.0", - "moneyphp/crypto-currencies": "^1.1.0", - "moneyphp/iso-currencies": "^3.4", - "php-http/message": "^1.16.0", - "php-http/mock-client": "^1.6.0", - "phpbench/phpbench": "^1.2.5", - "phpstan/extension-installer": "^1.4", - "phpstan/phpstan": "^2.1.9", - "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^10.5.9", - "psr/cache": "^1.0.1 || ^2.0 || ^3.0", - "ticketswap/phpstan-error-formatter": "^1.1" + "amphp/amp": "^2.3", + "doctrine/coding-standard": "^6.0", + "nyholm/psr7": "^1.2", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "0.12.82", + "phpstan/phpstan-phpunit": "0.12.18", + "phpstan/phpstan-strict-rules": "0.12.9", + "phpunit/phpunit": "^7.2 || ^8.5", + "psr/http-message": "^1.0", + "react/promise": "2.*", + "simpod/php-coveralls-mirror": "^3.0" }, "suggest": { - "ext-gmp": "Calculate without integer limits", - "ext-intl": "Format Money objects with intl", - "florianv/exchanger": "Exchange rates library for PHP", - "florianv/swap": "Exchange rates library for PHP", - "psr/cache-implementation": "Used for Currency caching" + "psr/http-message": "To use standard GraphQL server", + "react/promise": "To leverage async resolving on React PHP platform" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "autoload": { "psr-4": { - "Money\\": "src/" + "GraphQL\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Mathias Verraes", - "email": "mathias@verraes.net", - "homepage": "http://verraes.net" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - }, - { - "name": "Frederik Bosch", - "email": "f.bosch@genkgo.nl" - } - ], - "description": "PHP implementation of Fowler's Money pattern", - "homepage": "http://moneyphp.org", + "description": "A PHP port of GraphQL reference implementation", + "homepage": "https://github.com/webonyx/graphql-php", "keywords": [ - "Value Object", - "money", - "vo" + "api", + "graphql" ], "support": { - "issues": "https://github.com/moneyphp/money/issues", - "source": "https://github.com/moneyphp/money/tree/v4.8.0" + "source": "https://github.com/pixelandtonic/graphql-php/tree/v14.11.10.1" }, - "time": "2025-10-23T07:55:09+00:00" + "funding": [ + { + "url": "https://opencollective.com/webonyx-graphql-php", + "type": "open_collective" + } + ], + "time": "2026-04-14T15:27:52+00:00" }, { - "name": "monolog/monolog", - "version": "3.9.0", + "name": "pixelandtonic/imagine", + "version": "1.5.2.1", "source": { "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + "url": "https://github.com/pixelandtonic/Imagine.git", + "reference": "8e6c5cf929400142724b31482da51dc556277e15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "url": "https://api.github.com/repos/pixelandtonic/Imagine/zipball/8e6c5cf929400142724b31482da51dc556277e15", + "reference": "8e6c5cf929400142724b31482da51dc556277e15", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/log": "^2.0 || ^3.0" - }, - "provide": { - "psr/log-implementation": "3.0.0" + "php": ">=7.1" }, "require-dev": { - "aws/aws-sdk-php": "^3.0", - "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^7 || ^8", - "ext-json": "*", - "graylog2/gelf-php": "^1.4.2 || ^2.0", - "guzzlehttp/guzzle": "^7.4.5", - "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", - "php-amqplib/php-amqplib": "~2.4 || ^3", - "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", - "rollbar/rollbar": "^4.0", - "ruflin/elastica": "^7 || ^8", - "symfony/mailer": "^5.4 || ^6", - "symfony/mime": "^5.4 || ^6" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", - "ext-mbstring": "Allow to work properly with unicode symbols", - "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", - "ext-openssl": "Required to send log messages using SSL", - "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", - "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4 || ^9.3" + }, + "suggest": { + "ext-exif": "to read EXIF metadata", + "ext-gd": "to use the GD implementation", + "ext-gmagick": "to use the Gmagick implementation", + "ext-imagick": "to use the Imagick implementation" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.x-dev" + "dev-develop": "1.x-dev" } }, "autoload": { "psr-4": { - "Monolog\\": "src/Monolog" + "Imagine\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2292,61 +4382,50 @@ ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com", + "homepage": "http://avalanche123.com" } ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "https://github.com/Seldaek/monolog", + "description": "Image processing for PHP", + "homepage": "http://imagine.readthedocs.org/", "keywords": [ - "log", - "logging", - "psr-3" + "drawing", + "graphics", + "image manipulation", + "image processing" ], "support": { - "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + "source": "https://github.com/pixelandtonic/Imagine/tree/1.5.2.1" }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", - "type": "tidelift" - } - ], - "time": "2025-03-24T10:02:05+00:00" + "time": "2026-02-25T23:13:43+00:00" }, { - "name": "paragonie/constant_time_encoding", - "version": "v3.1.3", + "name": "pragmarx/google2fa", + "version": "v8.0.3", "source": { "type": "git", - "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" + "url": "https://github.com/antonioribeiro/google2fa.git", + "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", - "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad", + "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad", "shasum": "" }, "require": { - "php": "^8" + "paragonie/constant_time_encoding": "^1.0|^2.0|^3.0", + "php": "^7.1|^8.0" }, "require-dev": { - "infection/infection": "^0", - "nikic/php-fuzzer": "^0", - "phpunit/phpunit": "^9|^10|^11", - "vimeo/psalm": "^4|^5|^6" + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^7.5.15|^8.5|^9.0" }, "type": "library", "autoload": { "psr-4": { - "ParagonIE\\ConstantTime\\": "src/" + "PragmaRX\\Google2FA\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2355,116 +4434,126 @@ ], "authors": [ { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com", - "role": "Maintainer" - }, - { - "name": "Steve 'Sc00bz' Thomas", - "email": "steve@tobtu.com", - "homepage": "https://www.tobtu.com", - "role": "Original Developer" + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" } ], - "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "description": "A One Time Password Authentication package, compatible with Google Authenticator.", "keywords": [ - "base16", - "base32", - "base32_decode", - "base32_encode", - "base64", - "base64_decode", - "base64_encode", - "bin2hex", - "encoding", - "hex", - "hex2bin", - "rfc4648" + "2fa", + "Authentication", + "Two Factor Authentication", + "google2fa" ], "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/constant_time_encoding/issues", - "source": "https://github.com/paragonie/constant_time_encoding" + "issues": "https://github.com/antonioribeiro/google2fa/issues", + "source": "https://github.com/antonioribeiro/google2fa/tree/v8.0.3" }, - "time": "2025-09-24T15:06:41+00:00" + "time": "2024-09-05T11:56:40+00:00" }, { - "name": "paragonie/random_compat", - "version": "v9.99.100", + "name": "pragmarx/random", + "version": "v0.2.2", "source": { "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + "url": "https://github.com/antonioribeiro/random.git", + "reference": "daf08a189c5d2d40d1a827db46364d3a741a51b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "url": "https://api.github.com/repos/antonioribeiro/random/zipball/daf08a189c5d2d40d1a827db46364d3a741a51b7", + "reference": "daf08a189c5d2d40d1a827db46364d3a741a51b7", "shasum": "" }, "require": { - "php": ">= 7" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" + "fzaninotto/faker": "~1.7", + "phpunit/phpunit": "~6.4", + "pragmarx/trivia": "~0.1", + "squizlabs/php_codesniffer": "^2.3" }, "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + "fzaninotto/faker": "Allows you to get dozens of randomized types", + "pragmarx/trivia": "For the trivia database" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "PragmaRX\\Random\\": "src" + } + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "homepage": "https://antoniocarlosribeiro.com", + "role": "Developer" } ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "description": "Create random chars, numbers, strings", + "homepage": "https://github.com/antonioribeiro/random", "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" + "Randomize", + "faker", + "pragmarx", + "random", + "random number", + "random pattern", + "random string" ], "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/random_compat/issues", - "source": "https://github.com/paragonie/random_compat" + "issues": "https://github.com/antonioribeiro/random/issues", + "source": "https://github.com/antonioribeiro/random/tree/master" }, - "time": "2020-10-15T08:29:30+00:00" + "time": "2017-11-21T05:26:22+00:00" }, { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", + "name": "pragmarx/recovery", + "version": "v0.2.1", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + "url": "https://github.com/antonioribeiro/recovery.git", + "reference": "b5ce4082f059afac6761714a84497816f45271cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "url": "https://api.github.com/repos/antonioribeiro/recovery/zipball/b5ce4082f059afac6761714a84497816f45271cc", + "reference": "b5ce4082f059afac6761714a84497816f45271cc", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": ">=7.0", + "pragmarx/random": "~0.1" + }, + "require-dev": { + "phpunit/phpunit": ">=5.4.3", + "squizlabs/php_codesniffer": "^2.3", + "tightenco/collect": "^5.0" + }, + "suggest": { + "tightenco/collect": "Allows to generate recovery codes as collections" }, "type": "library", "extra": { "branch-alias": { - "dev-2.x": "2.x-dev" + "dev-master": "1.0-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src/" + "PragmaRX\\Recovery\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2473,66 +4562,52 @@ ], "authors": [ { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "homepage": "https://antoniocarlosribeiro.com", + "role": "Developer" } ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", + "description": "Create recovery codes for two factor auth", + "homepage": "https://github.com/antonioribeiro/recovery", "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" + "2fa", + "account recovery", + "auth", + "backup codes", + "google2fa", + "pragmarx", + "recovery", + "recovery codes", + "two factor auth" ], "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + "issues": "https://github.com/antonioribeiro/recovery/issues", + "source": "https://github.com/antonioribeiro/recovery/tree/v0.2.1" }, - "time": "2020-06-27T09:03:43+00:00" + "time": "2021-08-15T12:26:51+00:00" }, { - "name": "phpdocumentor/reflection-docblock", - "version": "5.6.3", + "name": "psr/clock", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", "shasum": "" }, "require": { - "doctrine/deprecations": "^1.1", - "ext-filter": "*", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7|^2.0", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.5 || ~1.6.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "^9.5", - "psalm/phar": "^5.26" + "php": "^7.0 || ^8.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src" + "Psr\\Clock\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2541,60 +4616,51 @@ ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" }, - "time": "2025-08-01T19:43:32+00:00" + "time": "2022-11-25T14:36:26+00:00" }, { - "name": "phpdocumentor/type-resolver", - "version": "1.10.0", + "name": "psr/container", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.18|^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" + "php": ">=7.4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-1.x": "1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src" + "Psr\\Container\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2603,99 +4669,102 @@ ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2024-11-09T15:12:26+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { - "name": "phpstan/phpdoc-parser", - "version": "2.3.0", + "name": "psr/event-dispatcher", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "symfony/process": "^5.2" + "php": ">=7.2.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] + "Psr\\EventDispatcher\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" }, - "time": "2025-08-30T15:50:23+00:00" + "time": "2019-01-08T18:20:26+00:00" }, { - "name": "pixelandtonic/imagine", - "version": "1.3.3.1", + "name": "psr/http-client", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/pixelandtonic/Imagine.git", - "reference": "4d9bb596ff60504e37ccf9103c0bb705dba7fec6" + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pixelandtonic/Imagine/zipball/4d9bb596ff60504e37ccf9103c0bb705dba7fec6", - "reference": "4d9bb596ff60504e37ccf9103c0bb705dba7fec6", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4 || ^9.3" - }, - "suggest": { - "ext-exif": "to read EXIF metadata", - "ext-gd": "to use the GD implementation", - "ext-gmagick": "to use the Gmagick implementation", - "ext-imagick": "to use the Imagick implementation" + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-develop": "1.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Imagine\\": "src/" + "Psr\\Http\\Client\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2704,50 +4773,50 @@ ], "authors": [ { - "name": "Bulat Shakirzyanov", - "email": "mallluhuct@gmail.com", - "homepage": "http://avalanche123.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Image processing for PHP 5.3", - "homepage": "http://imagine.readthedocs.org/", + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", "keywords": [ - "drawing", - "graphics", - "image manipulation", - "image processing" + "http", + "http-client", + "psr", + "psr-18" ], "support": { - "source": "https://github.com/pixelandtonic/Imagine/tree/1.3.3.1" + "source": "https://github.com/php-fig/http-client" }, - "time": "2023-01-03T19:18:06+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { - "name": "pragmarx/google2fa", - "version": "v8.0.3", + "name": "psr/http-factory", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/antonioribeiro/google2fa.git", - "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad" + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad", - "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "paragonie/constant_time_encoding": "^1.0|^2.0|^3.0", - "php": "^7.1|^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.9", - "phpunit/phpunit": "^7.5.15|^8.5|^9.0" + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "PragmaRX\\Google2FA\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2756,60 +4825,52 @@ ], "authors": [ { - "name": "Antonio Carlos Ribeiro", - "email": "acr@antoniocarlosribeiro.com", - "role": "Creator & Designer" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ - "2fa", - "Authentication", - "Two Factor Authentication", - "google2fa" + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/antonioribeiro/google2fa/issues", - "source": "https://github.com/antonioribeiro/google2fa/tree/v8.0.3" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2024-09-05T11:56:40+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { - "name": "pragmarx/random", - "version": "v0.2.2", + "name": "psr/http-message", + "version": "2.0", "source": { "type": "git", - "url": "https://github.com/antonioribeiro/random.git", - "reference": "daf08a189c5d2d40d1a827db46364d3a741a51b7" + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/random/zipball/daf08a189c5d2d40d1a827db46364d3a741a51b7", - "reference": "daf08a189c5d2d40d1a827db46364d3a741a51b7", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { - "php": ">=7.0" - }, - "require-dev": { - "fzaninotto/faker": "~1.7", - "phpunit/phpunit": "~6.4", - "pragmarx/trivia": "~0.1", - "squizlabs/php_codesniffer": "^2.3" - }, - "suggest": { - "fzaninotto/faker": "Allows you to get dozens of randomized types", - "pragmarx/trivia": "For the trivia database" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "PragmaRX\\Random\\": "src" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2818,64 +4879,51 @@ ], "authors": [ { - "name": "Antonio Carlos Ribeiro", - "email": "acr@antoniocarlosribeiro.com", - "homepage": "https://antoniocarlosribeiro.com", - "role": "Developer" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Create random chars, numbers, strings", - "homepage": "https://github.com/antonioribeiro/random", + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ - "Randomize", - "faker", - "pragmarx", - "random", - "random number", - "random pattern", - "random string" + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/antonioribeiro/random/issues", - "source": "https://github.com/antonioribeiro/random/tree/master" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2017-11-21T05:26:22+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { - "name": "pragmarx/recovery", - "version": "v0.2.1", + "name": "psr/log", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/antonioribeiro/recovery.git", - "reference": "b5ce4082f059afac6761714a84497816f45271cc" + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/recovery/zipball/b5ce4082f059afac6761714a84497816f45271cc", - "reference": "b5ce4082f059afac6761714a84497816f45271cc", - "shasum": "" - }, - "require": { - "php": ">=7.0", - "pragmarx/random": "~0.1" - }, - "require-dev": { - "phpunit/phpunit": ">=5.4.3", - "squizlabs/php_codesniffer": "^2.3", - "tightenco/collect": "^5.0" + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" }, - "suggest": { - "tightenco/collect": "Allows to generate recovery codes as collections" + "require": { + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "PragmaRX\\Recovery\\": "src" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2884,52 +4932,48 @@ ], "authors": [ { - "name": "Antonio Carlos Ribeiro", - "email": "acr@antoniocarlosribeiro.com", - "homepage": "https://antoniocarlosribeiro.com", - "role": "Developer" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Create recovery codes for two factor auth", - "homepage": "https://github.com/antonioribeiro/recovery", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ - "2fa", - "account recovery", - "auth", - "backup codes", - "google2fa", - "pragmarx", - "recovery", - "recovery codes", - "two factor auth" + "log", + "psr", + "psr-3" ], "support": { - "issues": "https://github.com/antonioribeiro/recovery/issues", - "source": "https://github.com/antonioribeiro/recovery/tree/v0.2.1" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-08-15T12:26:51+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { - "name": "psr/clock", - "version": "1.0.0", + "name": "psr/simple-cache", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/clock.git", - "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", - "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0" + "php": ">=8.0.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, "autoload": { "psr-4": { - "Psr\\Clock\\": "src/" + "Psr\\SimpleCache\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2942,48 +4986,45 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interface for reading the clock.", - "homepage": "https://github.com/php-fig/clock", + "description": "Common interfaces for simple caching", "keywords": [ - "clock", - "now", + "cache", + "caching", "psr", - "psr-20", - "time" + "psr-16", + "simple-cache" ], "support": { - "issues": "https://github.com/php-fig/clock/issues", - "source": "https://github.com/php-fig/clock/tree/1.0.0" + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" }, - "time": "2022-11-25T14:36:26+00:00" + "time": "2021-10-29T13:26:27+00:00" }, { - "name": "psr/container", - "version": "2.0.2", + "name": "ralouphie/getallheaders", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "php": ">=7.4.0" + "php": ">=5.6" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" }, + "type": "library", "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } + "files": [ + "src/getallheaders.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2991,1082 +5032,1095 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" } ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], + "description": "A polyfill for getallheaders.", "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/2.0.2" + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" }, - "time": "2021-11-05T16:47:00+00:00" + "time": "2019-03-08T08:55:37+00:00" }, { - "name": "psr/event-dispatcher", - "version": "1.0.0", + "name": "samdark/yii2-psr-log-target", + "version": "1.1.4", "source": { "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + "url": "https://github.com/samdark/yii2-psr-log-target.git", + "reference": "5f14f21d5ee4294fe9eb3e723ec8a3908ca082ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "url": "https://api.github.com/repos/samdark/yii2-psr-log-target/zipball/5f14f21d5ee4294fe9eb3e723ec8a3908ca082ea", + "reference": "5f14f21d5ee4294fe9eb3e723ec8a3908ca082ea", "shasum": "" }, "require": { - "php": ">=7.2.0" + "psr/log": "~1.0.2|~1.1.0|~3.0.0", + "yiisoft/yii2": "~2.0.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "require-dev": { + "phpunit/phpunit": "~4.4|~10.4.2" }, + "type": "yii2-extension", "autoload": { "psr-4": { - "Psr\\EventDispatcher\\": "src/" + "samdark\\log\\": "src", + "samdark\\log\\tests\\": "tests" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Alexander Makarov", + "email": "sam@rmcreative.ru" } ], - "description": "Standard interfaces for event handling.", + "description": "Yii 2 log target which uses PSR-3 compatible logger", + "homepage": "https://github.com/samdark/yii2-psr-log-target", "keywords": [ - "events", - "psr", - "psr-14" + "extension", + "log", + "psr-3", + "yii" ], "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + "issues": "https://github.com/samdark/yii2-psr-log-target/issues", + "source": "https://github.com/samdark/yii2-psr-log-target" }, - "time": "2019-01-08T18:20:26+00:00" + "funding": [ + { + "url": "https://github.com/samdark", + "type": "github" + }, + { + "url": "https://www.patreon.com/samdark", + "type": "patreon" + } + ], + "time": "2023-11-23T14:11:29+00:00" }, { - "name": "psr/http-client", - "version": "1.0.3", + "name": "sebastian/cli-parser", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-main": "3.0-dev" } }, "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { - "source": "https://github.com/php-fig/http-client" + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" }, - "time": "2023-09-23T14:17:50+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" }, { - "name": "psr/http-factory", - "version": "1.1.0", + "name": "sebastian/code-unit", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", "shasum": "" }, "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-main": "3.0-dev" } }, "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" + "BSD-3-Clause" ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { - "source": "https://github.com/php-fig/http-factory" + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" }, - "time": "2024-04-15T12:06:14+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" }, { - "name": "psr/http-message", - "version": "2.0", + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-main": "4.0-dev" } }, "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" }, - "time": "2023-04-04T09:54:51+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" }, { - "name": "psr/log", - "version": "3.0.2", + "name": "sebastian/comparator", + "version": "6.3.3", "source": { "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { - "php": ">=8.0.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-main": "6.3-dev" } }, "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" } ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ - "log", - "psr", - "psr-3" + "comparator", + "compare", + "equality" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.2" + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, - "time": "2024-09-11T13:17:53+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2026-01-24T09:26:40+00:00" }, { - "name": "psr/simple-cache", - "version": "3.0.0", + "name": "sebastian/complexity", + "version": "4.0.1", "source": { "type": "git", - "url": "https://github.com/php-fig/simple-cache.git", - "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", - "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", "shasum": "" }, "require": { - "php": ">=8.0.0" + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-main": "4.0-dev" } }, "autoload": { - "psr-4": { - "Psr\\SimpleCache\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Common interfaces for simple caching", - "keywords": [ - "cache", - "caching", - "psr", - "psr-16", - "simple-cache" - ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", "support": { - "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" }, - "time": "2021-10-29T13:26:27+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" }, { - "name": "ralouphie/getallheaders", - "version": "3.0.3", + "name": "sebastian/diff", + "version": "6.0.2", "source": { "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=8.2" }, "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, "autoload": { - "files": [ - "src/getallheaders.php" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], - "description": "A polyfill for getallheaders.", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" }, - "time": "2019-03-08T08:55:37+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" }, { - "name": "samdark/yii2-psr-log-target", - "version": "1.1.4", + "name": "sebastian/environment", + "version": "7.2.1", "source": { "type": "git", - "url": "https://github.com/samdark/yii2-psr-log-target.git", - "reference": "5f14f21d5ee4294fe9eb3e723ec8a3908ca082ea" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/samdark/yii2-psr-log-target/zipball/5f14f21d5ee4294fe9eb3e723ec8a3908ca082ea", - "reference": "5f14f21d5ee4294fe9eb3e723ec8a3908ca082ea", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", "shasum": "" }, "require": { - "psr/log": "~1.0.2|~1.1.0|~3.0.0", - "yiisoft/yii2": "~2.0.0" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "~4.4|~10.4.2" + "phpunit/phpunit": "^11.3" }, - "type": "yii2-extension", - "autoload": { - "psr-4": { - "samdark\\log\\": "src", - "samdark\\log\\tests\\": "tests" + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { - "name": "Alexander Makarov", - "email": "sam@rmcreative.ru" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Yii 2 log target which uses PSR-3 compatible logger", - "homepage": "https://github.com/samdark/yii2-psr-log-target", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ - "extension", - "log", - "psr-3", - "yii" + "Xdebug", + "environment", + "hhvm" ], "support": { - "issues": "https://github.com/samdark/yii2-psr-log-target/issues", - "source": "https://github.com/samdark/yii2-psr-log-target" + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" }, "funding": [ { - "url": "https://github.com/samdark", + "url": "https://github.com/sebastianbergmann", "type": "github" }, { - "url": "https://www.patreon.com/samdark", - "type": "patreon" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" } ], - "time": "2023-11-23T14:11:29+00:00" + "time": "2025-05-21T11:55:47+00:00" }, { - "name": "seld/cli-prompt", - "version": "1.0.4", + "name": "sebastian/exporter", + "version": "6.3.2", "source": { "type": "git", - "url": "https://github.com/Seldaek/cli-prompt.git", - "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b8dfcf02094b8c03b40322c229493bb2884423c5", - "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", "shasum": "" }, "require": { - "php": ">=5.3" + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.63" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "6.3-dev" } }, "autoload": { - "psr-4": { - "Seld\\CliPrompt\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], - "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ - "cli", - "console", - "hidden", - "input", - "prompt" + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } ], - "support": { - "issues": "https://github.com/Seldaek/cli-prompt/issues", - "source": "https://github.com/Seldaek/cli-prompt/tree/1.0.4" - }, - "time": "2020-12-15T21:32:01+00:00" + "time": "2025-09-24T06:12:51+00:00" }, { - "name": "spomky-labs/cbor-php", - "version": "3.1.1", + "name": "sebastian/global-state", + "version": "7.0.2", "source": { "type": "git", - "url": "https://github.com/Spomky-Labs/cbor-php.git", - "reference": "5404f3e21cbe72f5cf612aa23db2b922fd2f43bf" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/5404f3e21cbe72f5cf612aa23db2b922fd2f43bf", - "reference": "5404f3e21cbe72f5cf612aa23db2b922fd2f43bf", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13", - "ext-mbstring": "*", - "php": ">=8.0" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" }, "require-dev": { - "deptrac/deptrac": "^3.0", - "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", - "ext-json": "*", - "infection/infection": "^0.29", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0|^2.0", - "phpstan/phpstan-beberlei-assert": "^1.0|^2.0", - "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", - "phpstan/phpstan-phpunit": "^1.0|^2.0", - "phpstan/phpstan-strict-rules": "^1.0|^2.0", - "phpunit/phpunit": "^10.1|^11.0|^12.0", - "rector/rector": "^1.0|^2.0", - "roave/security-advisories": "dev-latest", - "symfony/var-dumper": "^6.0|^7.0", - "symplify/easy-coding-standard": "^12.0" - }, - "suggest": { - "ext-bcmath": "GMP or BCMath extensions will drastically improve the library performance. BCMath extension needed to handle the Big Float and Decimal Fraction Tags", - "ext-gmp": "GMP or BCMath extensions will drastically improve the library performance" + "ext-dom": "*", + "phpunit/phpunit": "^11.0" }, "type": "library", - "autoload": { - "psr-4": { - "CBOR\\": "src/" + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/Spomky-Labs/cbor-php/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "CBOR Encoder/Decoder for PHP", + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", "keywords": [ - "Concise Binary Object Representation", - "RFC7049", - "cbor" + "global state" ], "support": { - "issues": "https://github.com/Spomky-Labs/cbor-php/issues", - "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.1.1" + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" }, "funding": [ { - "url": "https://github.com/Spomky", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" } ], - "time": "2025-06-13T11:57:55+00:00" + "time": "2024-07-03T04:57:36+00:00" }, { - "name": "spomky-labs/pki-framework", - "version": "1.4.0", + "name": "sebastian/lines-of-code", + "version": "3.0.1", "source": { "type": "git", - "url": "https://github.com/Spomky-Labs/pki-framework.git", - "reference": "bf6f55a9d9eb25b7781640221cb54f5c727850d7" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/bf6f55a9d9eb25b7781640221cb54f5c727850d7", - "reference": "bf6f55a9d9eb25b7781640221cb54f5c727850d7", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", "shasum": "" }, "require": { - "brick/math": "^0.10|^0.11|^0.12|^0.13|^0.14", - "ext-mbstring": "*", - "php": ">=8.1" + "nikic/php-parser": "^5.0", + "php": ">=8.2" }, "require-dev": { - "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", - "ext-gmp": "*", - "ext-openssl": "*", - "infection/infection": "^0.28|^0.29|^0.31", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/extension-installer": "^1.3|^2.0", - "phpstan/phpstan": "^1.8|^2.0", - "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", - "phpstan/phpstan-phpunit": "^1.1|^2.0", - "phpstan/phpstan-strict-rules": "^1.3|^2.0", - "phpunit/phpunit": "^10.1|^11.0|^12.0", - "rector/rector": "^1.0|^2.0", - "roave/security-advisories": "dev-latest", - "symfony/string": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0", - "symplify/easy-coding-standard": "^12.0" - }, - "suggest": { - "ext-bcmath": "For better performance (or GMP)", - "ext-gmp": "For better performance (or BCMath)", - "ext-openssl": "For OpenSSL based cyphering" + "phpunit/phpunit": "^11.0" }, "type": "library", - "autoload": { - "psr-4": { - "SpomkyLabs\\Pki\\": "src/" + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Joni Eskelinen", - "email": "jonieske@gmail.com", - "role": "Original developer" - }, - { - "name": "Florent Morselli", - "email": "florent.morselli@spomky-labs.com", - "role": "Spomky-Labs PKI Framework developer" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.", - "homepage": "https://github.com/spomky-labs/pki-framework", - "keywords": [ - "DER", - "Private Key", - "ac", - "algorithm identifier", - "asn.1", - "asn1", - "attribute certificate", - "certificate", - "certification request", - "cryptography", - "csr", - "decrypt", - "ec", - "encrypt", - "pem", - "pkcs", - "public key", - "rsa", - "sign", - "signature", - "verify", - "x.509", - "x.690", - "x509", - "x690" - ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { - "issues": "https://github.com/Spomky-Labs/pki-framework/issues", - "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.4.0" + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" }, "funding": [ { - "url": "https://github.com/Spomky", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" } ], - "time": "2025-10-22T08:24:34+00:00" + "time": "2024-07-03T04:58:38+00:00" }, { - "name": "symfony/css-selector", - "version": "v7.3.0", + "name": "sebastian/object-enumerator", + "version": "6.0.1", "source": { "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, "autoload": { - "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Converts CSS selectors to XPath expressions", - "homepage": "https://symfony.com", + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.3.0" + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2024-07-03T05:00:13+00:00" }, { - "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "name": "sebastian/object-reflector", + "version": "4.0.1", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "4.0-dev" } }, "autoload": { - "files": [ - "function.php" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2024-07-03T05:01:32+00:00" }, { - "name": "symfony/dom-crawler", - "version": "v7.3.3", + "name": "sebastian/recursion-context", + "version": "6.0.3", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/efa076ea0eeff504383ff0dcf827ea5ce15690ba", - "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", "shasum": "" }, "require": { - "masterminds/html5": "^2.6", - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.2" }, "require-dev": { - "symfony/css-selector": "^6.4|^7.0" + "phpunit/phpunit": "^11.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "Eases DOM navigation for HTML and XML documents", - "homepage": "https://symfony.com", + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v7.3.3" + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" + "url": "https://github.com/sebastianbergmann", + "type": "github" }, { - "url": "https://github.com/fabpot", - "type": "github" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" }, { - "url": "https://github.com/nicolas-grekas", - "type": "github" + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", "type": "tidelift" } ], - "time": "2025-08-06T20:13:54+00:00" + "time": "2025-08-13T04:42:22+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v7.3.3", + "name": "sebastian/type", + "version": "5.1.3", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/event-dispatcher-contracts": "^2.5|^3" - }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/service-contracts": "<2.5" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0|3.0" + "php": ">=8.2" }, "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "phpunit/phpunit": "^11.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com", + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" + "url": "https://github.com/sebastianbergmann", + "type": "github" }, { - "url": "https://github.com/fabpot", - "type": "github" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" }, { - "url": "https://github.com/nicolas-grekas", - "type": "github" + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-08-09T06:55:48+00:00" }, { - "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", + "name": "sebastian/version", + "version": "5.0.2", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/event-dispatcher": "^1" + "php": ">=8.2" }, "type": "library", "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "5.0-dev" } }, "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2024-10-09T05:16:32+00:00" }, { - "name": "symfony/filesystem", - "version": "v6.4.24", + "name": "seld/cli-prompt", + "version": "1.0.4", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" + "url": "https://github.com/Seldaek/cli-prompt.git", + "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b8dfcf02094b8c03b40322c229493bb2884423c5", + "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" + "php": ">=5.3" }, "require-dev": { - "symfony/process": "^5.4|^6.4|^7.0" + "phpstan/phpstan": "^0.12.63" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Seld\\CliPrompt\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4074,96 +6128,58 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" } ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", + "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", + "keywords": [ + "cli", + "console", + "hidden", + "input", + "prompt" + ], "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.24" + "issues": "https://github.com/Seldaek/cli-prompt/issues", + "source": "https://github.com/Seldaek/cli-prompt/tree/1.0.4" }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2020-12-15T21:32:01+00:00" }, { - "name": "symfony/http-client", - "version": "v7.3.4", + "name": "spomky-labs/cbor-php", + "version": "3.2.3", "source": { "type": "git", - "url": "https://github.com/symfony/http-client.git", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" + "url": "https://github.com/Spomky-Labs/cbor-php.git", + "reference": "dd6eb84e6d92f7b8bd0da56b4b4dd7235aed0c32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/dd6eb84e6d92f7b8bd0da56b4b4dd7235aed0c32", + "reference": "dd6eb84e6d92f7b8bd0da56b4b4dd7235aed0c32", "shasum": "" }, "require": { - "php": ">=8.2", - "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.4|^3.5.2", - "symfony/polyfill-php83": "^1.29", - "symfony/service-contracts": "^2.5|^3" - }, - "conflict": { - "amphp/amp": "<2.5", - "amphp/socket": "<1.1", - "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.4" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "1.0", - "symfony/http-client-implementation": "3.0" + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13|^0.14|^0.15|^0.16|^0.17", + "ext-mbstring": "*", + "php": ">=8.0" }, "require-dev": { - "amphp/http-client": "^4.2.1|^5.0", - "amphp/http-tunnel": "^1.0|^2.0", - "guzzlehttp/promises": "^1.4|^2.0", - "nyholm/psr7": "^1.0", - "php-http/httplug": "^1.0|^2.0", - "psr/http-client": "^1.0", - "symfony/amphp-http-client-meta": "^1.0|^2.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0" + "ext-json": "*", + "roave/security-advisories": "dev-latest", + "symfony/error-handler": "^6.4|^7.1|^8.0", + "symfony/var-dumper": "^6.4|^7.1|^8.0" + }, + "suggest": { + "ext-bcmath": "GMP or BCMath extensions will drastically improve the library performance. BCMath extension needed to handle the Big Float and Decimal Fraction Tags", + "ext-gmp": "GMP or BCMath extensions will drastically improve the library performance" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\HttpClient\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "CBOR\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4171,76 +6187,84 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "All contributors", + "homepage": "https://github.com/Spomky-Labs/cbor-php/contributors" } ], - "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", - "homepage": "https://symfony.com", + "description": "CBOR Encoder/Decoder for PHP", "keywords": [ - "http" + "Concise Binary Object Representation", + "RFC7049", + "cbor" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.4" + "issues": "https://github.com/Spomky-Labs/cbor-php/issues", + "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.2.3" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", + "url": "https://github.com/Spomky", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2026-04-01T12:15:20+00:00" }, { - "name": "symfony/http-client-contracts", - "version": "v3.6.0", + "name": "spomky-labs/pki-framework", + "version": "1.4.2", "source": { "type": "git", - "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "75d7043853a42837e68111812f4d964b01e5101c" + "url": "https://github.com/Spomky-Labs/pki-framework.git", + "reference": "aa576cbd07128075bef97ac2f8af9854e67513d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", - "reference": "75d7043853a42837e68111812f4d964b01e5101c", + "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/aa576cbd07128075bef97ac2f8af9854e67513d8", + "reference": "aa576cbd07128075bef97ac2f8af9854e67513d8", "shasum": "" }, "require": { - "php": ">=8.1" + "brick/math": "^0.10|^0.11|^0.12|^0.13|^0.14|^0.15|^0.16|^0.17", + "ext-mbstring": "*", + "php": ">=8.1", + "psr/clock": "^1.0" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } + "require-dev": { + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", + "ext-gmp": "*", + "ext-openssl": "*", + "infection/infection": "^0.28|^0.29|^0.31|^0.32", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/extension-installer": "^1.3|^2.0", + "phpstan/phpstan": "^1.8|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.3|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0|^13.0", + "rector/rector": "^1.0|^2.0", + "roave/security-advisories": "dev-latest", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symplify/easy-coding-standard": "^12.0|^13.0" + }, + "suggest": { + "ext-bcmath": "For better performance (or GMP)", + "ext-gmp": "For better performance (or BCMath)", + "ext-openssl": "For OpenSSL based cyphering" }, + "type": "library", "autoload": { "psr-4": { - "Symfony\\Contracts\\HttpClient\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] + "SpomkyLabs\\Pki\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4248,167 +6272,142 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Joni Eskelinen", + "email": "jonieske@gmail.com", + "role": "Original developer" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Florent Morselli", + "email": "florent.morselli@spomky-labs.com", + "role": "Spomky-Labs PKI Framework developer" } ], - "description": "Generic abstractions related to HTTP clients", - "homepage": "https://symfony.com", + "description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.", + "homepage": "https://github.com/spomky-labs/pki-framework", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "DER", + "Private Key", + "ac", + "algorithm identifier", + "asn.1", + "asn1", + "attribute certificate", + "certificate", + "certification request", + "cryptography", + "csr", + "decrypt", + "ec", + "encrypt", + "pem", + "pkcs", + "public key", + "rsa", + "sign", + "signature", + "verify", + "x.509", + "x.690", + "x509", + "x690" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" + "issues": "https://github.com/Spomky-Labs/pki-framework/issues", + "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.4.2" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/Spomky", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" } ], - "time": "2025-04-29T11:18:49+00:00" + "time": "2026-03-23T22:56:56+00:00" }, { - "name": "symfony/mailer", - "version": "v7.3.5", + "name": "staabm/side-effects-detector", + "version": "1.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/mailer.git", - "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba" + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba", - "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", "shasum": "" }, "require": { - "egulias/email-validator": "^2.1.10|^3|^4", - "php": ">=8.2", - "psr/event-dispatcher": "^1", - "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^7.2", - "symfony/service-contracts": "^2.5|^3" - }, - "conflict": { - "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<6.4", - "symfony/messenger": "<6.4", - "symfony/mime": "<6.4", - "symfony/twig-bridge": "<6.4" + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\Mailer\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "lib/" ] }, "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": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" ], - "description": "Helps sending emails", - "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.5" + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", + "url": "https://github.com/staabm", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2025-10-24T14:27:20+00:00" + "time": "2024-10-20T05:08:20+00:00" }, { - "name": "symfony/mime", - "version": "v7.3.4", + "name": "symfony/clock", + "version": "v7.4.8", "source": { "type": "git", - "url": "https://github.com/symfony/mime.git", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35" + "url": "https://github.com/symfony/clock.git", + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35", + "url": "https://api.github.com/repos/symfony/clock/zipball/674fa3b98e21531dd040e613479f5f6fa8f32111", + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" - }, - "conflict": { - "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<6.4", - "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" }, - "require-dev": { - "egulias/email-validator": "^2.1.10|^3.1|^4", - "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "provide": { + "psr/clock-implementation": "1.0" }, "type": "library", "autoload": { + "files": [ + "Resources/now.php" + ], "psr-4": { - "Symfony\\Component\\Mime\\": "" + "Symfony\\Component\\Clock\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4420,22 +6419,23 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Allows manipulating MIME messages", + "description": "Decouples applications from the system clock", "homepage": "https://symfony.com", "keywords": [ - "mime", - "mime-type" + "clock", + "psr20", + "time" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.4" + "source": "https://github.com/symfony/clock/tree/v7.4.8" }, "funding": [ { @@ -4455,45 +6455,33 @@ "type": "tidelift" } ], - "time": "2025-09-16T08:38:17+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.33.0", + "name": "symfony/css-selector", + "version": "v7.4.9", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "url": "https://github.com/symfony/css-selector.git", + "reference": "b75663ed96cf4756e28e3105476f220f92886cc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b75663ed96cf4756e28e3105476f220f92886cc4", + "reference": "b75663ed96cf4756e28e3105476f220f92886cc4", "shasum": "" }, "require": { - "php": ">=7.2" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" + "php": ">=8.2" }, "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4501,24 +6489,22 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/css-selector/tree/v7.4.9" }, "funding": [ { @@ -4538,45 +6524,40 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-18T13:18:21+00:00" }, { - "name": "symfony/polyfill-iconv", - "version": "v1.33.0", + "name": "symfony/dom-crawler", + "version": "v7.4.12", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa" + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "b59b59122690976550fd142c23fab62c84738db6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa", - "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b59b59122690976550fd142c23fab62c84738db6", + "reference": "b59b59122690976550fd142c23fab62c84738db6", "shasum": "" }, "require": { - "php": ">=7.2" - }, - "provide": { - "ext-iconv": "*" + "masterminds/html5": "^2.6", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" }, - "suggest": { - "ext-iconv": "For best performance" + "require-dev": { + "symfony/css-selector": "^6.4|^7.0|^8.0" }, "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Iconv\\": "" - } + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4584,25 +6565,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 for the Iconv extension", + "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "iconv", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.33.0" + "source": "https://github.com/symfony/dom-crawler/tree/v7.4.12" }, "funding": [ { @@ -4622,42 +6596,54 @@ "type": "tidelift" } ], - "time": "2024-09-17T14:58:18+00:00" + "time": "2026-05-20T07:20:23+00:00" }, { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", + "name": "symfony/event-dispatcher", + "version": "v8.1.1", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abd6c11dc468725d1627302ad10f6cd486e9e3d0", + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher-contracts": "^2.5|^3" }, - "suggest": { - "ext-intl": "For best performance" + "conflict": { + "symfony/security-http": "<7.4", + "symfony/service-contracts": "<2.5" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^7.4|^8.0" }, + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4665,26 +6651,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 for intl's grapheme_* functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], + "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/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.1.1" }, "funding": [ { @@ -4704,42 +6682,39 @@ "type": "tidelift" } ], - "time": "2025-06-27T09:58:17+00:00" + "time": "2026-06-09T12:28:30+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.33.0", + "name": "symfony/event-dispatcher-contracts", + "version": "v3.7.1", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", - "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", "shasum": "" }, "require": { - "php": ">=7.2", - "symfony/polyfill-intl-normalizer": "^1.10" - }, - "suggest": { - "ext-intl": "For best performance" + "php": ">=8.1", + "psr/event-dispatcher": "^1" }, "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" + "Symfony\\Contracts\\EventDispatcher\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -4748,30 +6723,26 @@ ], "authors": [ { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - }, - { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" }, "funding": [ { @@ -4791,44 +6762,37 @@ "type": "tidelift" } ], - "time": "2024-09-10T14:38:51+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "name": "symfony/filesystem", + "version": "v6.4.39", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" + "url": "https://github.com/symfony/filesystem.git", + "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/c507b077756b4e3e09adbbe7975fac81cd3722ca", + "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" }, - "suggest": { - "ext-intl": "For best performance" + "require-dev": { + "symfony/process": "^5.4|^6.4|^7.0" }, "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + "Symfony\\Component\\Filesystem\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -4837,26 +6801,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 for intl's Normalizer class and related functions", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/filesystem/tree/v6.4.39" }, "funding": [ { @@ -4876,46 +6832,66 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-05-07T13:11:42+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "name": "symfony/http-client", + "version": "v7.4.14", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "url": "https://github.com/symfony/http-client.git", + "reference": "f6bc6b5a54ff5afac4725cacec9bf2f52eb15920" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/http-client/zipball/f6bc6b5a54ff5afac4725cacec9bf2f52eb15920", + "reference": "f6bc6b5a54ff5afac4725cacec9bf2f52eb15920", "shasum": "" }, "require": { - "ext-iconv": "*", - "php": ">=7.2" + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "amphp/amp": "<2.5", + "amphp/socket": "<1.1", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" }, "provide": { - "ext-mbstring": "*" + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" }, - "suggest": { - "ext-mbstring": "For best performance" + "require-dev": { + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4931,17 +6907,13 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" + "http" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/http-client/tree/v7.4.14" }, "funding": [ { @@ -4961,32 +6933,43 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2026-06-16T11:50:14+00:00" }, { - "name": "symfony/polyfill-php72", - "version": "v1.31.0", + "name": "symfony/http-client-contracts", + "version": "v3.7.1", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "41fc42d276aeff21192465331ebbab7d83a743c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", - "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/41fc42d276aeff21192465331ebbab7d83a743c0", + "reference": "41fc42d276aeff21192465331ebbab7d83a743c0", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.1" }, - "type": "metapackage", + "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" } }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -5001,16 +6984,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "description": "Generic abstractions related to HTTP clients", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.7.1" }, "funding": [ { @@ -5021,46 +7006,60 @@ "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": "2026-06-05T06:23:12+00:00" }, { - "name": "symfony/polyfill-php81", - "version": "v1.33.0", + "name": "symfony/mailer", + "version": "v7.4.14", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + "url": "https://github.com/symfony/mailer.git", + "reference": "f88ce03ae73e3edb5c176ce1f337709996e88495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f88ce03ae73e3edb5c176ce1f337709996e88495", + "reference": "f88ce03ae73e3edb5c176ce1f337709996e88495", "shasum": "" }, "require": { - "php": ">=7.2" + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", + "symfony/service-contracts": "^2.5|^3" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" }, + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" + "Symfony\\Component\\Mailer\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5069,24 +7068,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.1+ features to lower PHP versions", + "description": "Helps sending emails", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" + "source": "https://github.com/symfony/mailer/tree/v7.4.14" }, "funding": [ { @@ -5106,41 +7099,52 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-06-13T08:51:35+00:00" }, { - "name": "symfony/polyfill-php83", - "version": "v1.33.0", + "name": "symfony/mime", + "version": "v7.4.13", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + "url": "https://github.com/symfony/mime.git", + "reference": "a845722765c4f6b2ce88beaf4f4479975b186770" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "url": "https://api.github.com/repos/symfony/mime/zipball/a845722765c4f6b2ce88beaf4f4479975b186770", + "reference": "a845722765c4f6b2ce88beaf4f4479975b186770", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" }, + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" + "Symfony\\Component\\Mime\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5149,24 +7153,22 @@ ], "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": "Allows manipulating MIME messages", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "mime", + "mime-type" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + "source": "https://github.com/symfony/mime/tree/v7.4.13" }, "funding": [ { @@ -5186,25 +7188,28 @@ "type": "tidelift" } ], - "time": "2025-07-08T02:45:35+00:00" + "time": "2026-05-23T16:22:37+00:00" }, { - "name": "symfony/polyfill-php84", - "version": "v1.33.0", + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.38.1", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603", "shasum": "" }, "require": { "php": ">=7.2" }, + "suggest": { + "ext-intl": "For best performance" + }, "type": "library", "extra": { "thanks": { @@ -5217,11 +7222,8 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php84\\": "" - }, - "classmap": [ - "Resources/stubs" - ] + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5237,16 +7239,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "description": "Symfony polyfill for intl's grapheme_* functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "grapheme", + "intl", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" }, "funding": [ { @@ -5266,30 +7270,28 @@ "type": "tidelift" } ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2026-05-26T05:58:03+00:00" }, { - "name": "symfony/polyfill-uuid", - "version": "v1.33.0", + "name": "symfony/polyfill-intl-idn", + "version": "v1.38.1", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "dc21118016c039a66235cf93d96b435ffb282412" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/dc21118016c039a66235cf93d96b435ffb282412", + "reference": "dc21118016c039a66235cf93d96b435ffb282412", "shasum": "" }, "require": { - "php": ">=7.2" - }, - "provide": { - "ext-uuid": "*" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "suggest": { - "ext-uuid": "For best performance" + "ext-intl": "For best performance" }, "type": "library", "extra": { @@ -5303,7 +7305,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Uuid\\": "" + "Symfony\\Polyfill\\Intl\\Idn\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -5312,24 +7314,30 @@ ], "authors": [ { - "name": "Grégoire Pineau", - "email": "lyrixx@lyrixx.info" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for uuid functions", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "idn", + "intl", "polyfill", "portable", - "uuid" + "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.38.1" }, "funding": [ { @@ -5349,32 +7357,44 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-05-25T15:22:23+00:00" }, { - "name": "symfony/process", - "version": "v7.3.4", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.38.0", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Process\\": "" + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5383,18 +7403,26 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Executes commands in sub-processes", + "description": "Symfony polyfill for intl's Normalizer class and related functions", "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], "support": { - "source": "https://github.com/symfony/process/tree/v7.3.4" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" }, "funding": [ { @@ -5414,36 +7442,41 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2026-05-25T13:48:31+00:00" }, { - "name": "symfony/property-access", - "version": "v7.3.3", + "name": "symfony/polyfill-php80", + "version": "v1.37.0", "source": { "type": "git", - "url": "https://github.com/symfony/property-access.git", - "reference": "4a4389e5c8bd1d0320d80a23caa6a1ac71cb81a7" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/4a4389e5c8bd1d0320d80a23caa6a1ac71cb81a7", - "reference": "4a4389e5c8bd1d0320d80a23caa6a1ac71cb81a7", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/property-info": "^6.4|^7.0" - }, - "require-dev": { - "symfony/cache": "^6.4|^7.0" + "php": ">=7.2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\PropertyAccess\\": "" + "Symfony\\Polyfill\\Php80\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5452,29 +7485,28 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ - "access", - "array", - "extraction", - "index", - "injection", - "object", - "property", - "property-path", - "reflection" + "compatibility", + "polyfill", + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v7.3.3" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" }, "funding": [ { @@ -5494,49 +7526,41 @@ "type": "tidelift" } ], - "time": "2025-08-04T15:15:28+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { - "name": "symfony/property-info", - "version": "v7.3.5", + "name": "symfony/polyfill-php83", + "version": "v1.38.2", "source": { "type": "git", - "url": "https://github.com/symfony/property-info.git", - "reference": "0b346ed259dc5da43535caf243005fe7d4b0f051" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/0b346ed259dc5da43535caf243005fe7d4b0f051", - "reference": "0b346ed259dc5da43535caf243005fe7d4b0f051", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/796a26abb75ce49f3a84433cd81bf1009d73d5f8", + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/string": "^6.4|^7.0", - "symfony/type-info": "^7.3.5" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "<5.2", - "phpdocumentor/type-resolver": "<1.5.1", - "symfony/cache": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/serializer": "<6.4" - }, - "require-dev": { - "phpdocumentor/reflection-docblock": "^5.2", - "phpstan/phpdoc-parser": "^1.0|^2.0", - "symfony/cache": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0" + "php": ">=7.2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\PropertyInfo\\": "" + "Symfony\\Polyfill\\Php83\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5545,26 +7569,24 @@ ], "authors": [ { - "name": "Kévin Dunglas", - "email": "dunglas@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Extracts information about PHP class' properties using metadata of popular sources", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ - "doctrine", - "phpdoc", - "property", - "symfony", - "type", - "validator" + "compatibility", + "polyfill", + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v7.3.5" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.2" }, "funding": [ { @@ -5584,69 +7606,41 @@ "type": "tidelift" } ], - "time": "2025-10-05T22:12:41+00:00" + "time": "2026-05-27T06:51:48+00:00" }, { - "name": "symfony/serializer", - "version": "v6.4.27", + "name": "symfony/polyfill-php84", + "version": "v1.38.1", "source": { "type": "git", - "url": "https://github.com/symfony/serializer.git", - "reference": "28779bbdb398cac3421d0e51f7ca669e4a27c5ac" + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/28779bbdb398cac3421d0e51f7ca669e4a27c5ac", - "reference": "28779bbdb398cac3421d0e51f7ca669e4a27c5ac", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "doctrine/annotations": "<1.12", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<5.4", - "symfony/property-access": "<5.4", - "symfony/property-info": "<5.4.24|>=6,<6.2.11", - "symfony/uid": "<5.4", - "symfony/validator": "<6.4", - "symfony/yaml": "<5.4" - }, - "require-dev": { - "doctrine/annotations": "^1.12|^2", - "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", - "seld/jsonlint": "^1.10", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4.26|^6.3|^7.0", - "symfony/property-info": "^5.4.24|^6.2.11|^7.0", - "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "php": ">=7.2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Serializer\\": "" + "Symfony\\Polyfill\\Php84\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5655,18 +7649,24 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], "support": { - "source": "https://github.com/symfony/serializer/tree/v6.4.27" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.38.1" }, "funding": [ { @@ -5686,47 +7686,45 @@ "type": "tidelift" } ], - "time": "2025-10-08T04:24:22+00:00" + "time": "2026-05-26T12:51:13+00:00" }, { - "name": "symfony/service-contracts", - "version": "v3.6.0", + "name": "symfony/polyfill-uuid", + "version": "v1.37.0", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/26dfec253c4cf3e51b541b52ddf7e42cb0908e94", + "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=7.2" }, - "conflict": { - "ext-psr": "<1.1|>=2" + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" }, "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5734,26 +7732,24 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to writing services", + "description": "Symfony polyfill for uuid functions", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "compatibility", + "polyfill", + "portable", + "uuid" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.37.0" }, "funding": [ { @@ -5764,51 +7760,38 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { - "name": "symfony/string", - "version": "v7.3.4", + "name": "symfony/process", + "version": "v7.4.13", "source": { "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" + "url": "https://github.com/symfony/process.git", + "reference": "f5804be144caceb570f6747519999636b664f24c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", + "url": "https://api.github.com/repos/symfony/process/zipball/f5804be144caceb570f6747519999636b664f24c", + "reference": "f5804be144caceb570f6747519999636b664f24c", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/translation-contracts": "<2.5" - }, - "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "php": ">=8.2" }, "type": "library", "autoload": { - "files": [ - "Resources/functions.php" - ], "psr-4": { - "Symfony\\Component\\String\\": "" + "Symfony\\Component\\Process\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5820,26 +7803,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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.4" + "source": "https://github.com/symfony/process/tree/v7.4.13" }, "funding": [ { @@ -5859,37 +7834,34 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:36:48+00:00" + "time": "2026-05-23T16:05:06+00:00" }, { - "name": "symfony/type-info", - "version": "v7.3.5", + "name": "symfony/property-access", + "version": "v7.4.8", "source": { "type": "git", - "url": "https://github.com/symfony/type-info.git", - "reference": "8b36f41421160db56914f897b57eaa6a830758b3" + "url": "https://github.com/symfony/property-access.git", + "reference": "b7dad9dae8b8a47ef7ecc76c8569e7d8c7d90cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/8b36f41421160db56914f897b57eaa6a830758b3", - "reference": "8b36f41421160db56914f897b57eaa6a830758b3", + "url": "https://api.github.com/repos/symfony/property-access/zipball/b7dad9dae8b8a47ef7ecc76c8569e7d8c7d90cfc", + "reference": "b7dad9dae8b8a47ef7ecc76c8569e7d8c7d90cfc", "shasum": "" }, "require": { "php": ">=8.2", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "conflict": { - "phpstan/phpdoc-parser": "<1.30" + "symfony/property-info": "^6.4.32|~7.3.10|^7.4.4|^8.0.4" }, "require-dev": { - "phpstan/phpdoc-parser": "^1.30|^2.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4.1|^7.0.1|^8.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\TypeInfo\\": "" + "Symfony\\Component\\PropertyAccess\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5901,28 +7873,29 @@ ], "authors": [ { - "name": "Mathias Arlaud", - "email": "mathias.arlaud@gmail.com" - }, - { - "name": "Baptiste LEDUC", - "email": "baptiste.leduc@gmail.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Extracts PHP types information.", + "description": "Provides functions to read and write from/to an object or array using a simple string notation", "homepage": "https://symfony.com", "keywords": [ - "PHPStan", - "phpdoc", - "symfony", - "type" + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property-path", + "reflection" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v7.3.5" + "source": "https://github.com/symfony/property-access/tree/v7.4.8" }, "funding": [ { @@ -5942,33 +7915,46 @@ "type": "tidelift" } ], - "time": "2025-10-16T12:30:12+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { - "name": "symfony/uid", - "version": "v7.3.1", + "name": "symfony/property-info", + "version": "v7.4.8", "source": { "type": "git", - "url": "https://github.com/symfony/uid.git", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb" + "url": "https://github.com/symfony/property-info.git", + "reference": "ac5e82528b986c4f7cfccbf7764b5d2e824d6175" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb", + "url": "https://api.github.com/repos/symfony/property-info/zipball/ac5e82528b986c4f7cfccbf7764b5d2e824d6175", + "reference": "ac5e82528b986c4f7cfccbf7764b5d2e824d6175", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/polyfill-uuid": "^1.15" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/type-info": "^7.4.7|^8.0.7" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/cache": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Uid\\": "" + "Symfony\\Component\\PropertyInfo\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5980,27 +7966,26 @@ ], "authors": [ { - "name": "Grégoire Pineau", - "email": "lyrixx@lyrixx.info" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Provides an object-oriented API to generate and represent UIDs", + "description": "Extracts information about PHP class' properties using metadata of popular sources", "homepage": "https://symfony.com", "keywords": [ - "UID", - "ulid", - "uuid" + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.3.1" + "source": "https://github.com/symfony/property-info/tree/v7.4.8" }, "funding": [ { @@ -6011,52 +7996,77 @@ "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-06-27T19:55:54+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { - "name": "symfony/var-dumper", - "version": "v7.3.5", + "name": "symfony/serializer", + "version": "v7.4.14", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d" + "url": "https://github.com/symfony/serializer.git", + "reference": "55acb01b9c8a5211dfbaf68c314d90d0ed2cc3d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d", + "url": "https://api.github.com/repos/symfony/serializer/zipball/55acb01b9c8a5211dfbaf68c314d90d0ed2cc3d1", + "reference": "55acb01b9c8a5211dfbaf68c314d90d0ed2cc3d1", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php84": "^1.30" }, "conflict": { - "symfony/console": "<6.4" + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/dependency-injection": "<6.4", + "symfony/property-access": "<6.4.31|>=7.0,<7.4.2|>=8.0,<8.0.2", + "symfony/property-info": "<6.4", + "symfony/type-info": "<7.2.5", + "symfony/uid": "<6.4", + "symfony/validator": "<6.4", + "symfony/yaml": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", - "twig/twig": "^3.12" + "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "seld/jsonlint": "^1.10", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^7.2|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4.31|^7.4.2|^8.0.2", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/type-info": "^7.2.5|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, - "bin": [ - "Resources/bin/var-dump-server" - ], "type": "library", "autoload": { - "files": [ - "Resources/functions/dump.php" - ], "psr-4": { - "Symfony\\Component\\VarDumper\\": "" + "Symfony\\Component\\Serializer\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -6068,22 +8078,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": "Provides mechanisms for walking through any arbitrary PHP variable", + "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", - "keywords": [ - "debug", - "dump" - ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.5" + "source": "https://github.com/symfony/serializer/tree/v7.4.14" }, "funding": [ { @@ -6103,43 +8109,46 @@ "type": "tidelift" } ], - "time": "2025-09-27T09:00:46+00:00" + "time": "2026-06-27T08:31:18+00:00" }, { - "name": "symfony/yaml", - "version": "v7.3.5", + "name": "symfony/service-contracts", + "version": "v3.7.1", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc", - "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-ctype": "^1.8" + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<6.4" - }, - "require-dev": { - "symfony/console": "^6.4|^7.0" + "ext-psr": "<1.1|>=2" }, - "bin": [ - "Resources/bin/yaml-lint" - ], "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, "autoload": { "psr-4": { - "Symfony\\Component\\Yaml\\": "" + "Symfony\\Contracts\\Service\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -6148,18 +8157,26 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Loads and dumps YAML files", + "description": "Generic abstractions related to writing services", "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.5" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" }, "funding": [ { @@ -6179,166 +8196,231 @@ "type": "tidelift" } ], - "time": "2025-09-27T09:00:46+00:00" + "time": "2026-06-16T09:55:08+00:00" }, { - "name": "theiconic/name-parser", - "version": "v1.2.11", + "name": "symfony/string", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/theiconic/name-parser.git", - "reference": "9a54a713bf5b2e7fd990828147d42de16bf8a253" + "url": "https://github.com/symfony/string.git", + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theiconic/name-parser/zipball/9a54a713bf5b2e7fd990828147d42de16bf8a253", - "reference": "9a54a713bf5b2e7fd990828147d42de16bf8a253", + "url": "https://api.github.com/repos/symfony/string/zipball/afd5944f4005862d961efb85c8bbd5c523c4e3c9", + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.4.1", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "php-mock/php-mock-phpunit": "^2.1", - "phpunit/phpunit": "^7.0" + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { - "TheIconic\\NameParser\\": [ - "src/", - "tests/" - ] - } + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v8.1.0" + }, + "funding": [ { - "name": "The Iconic", - "email": "engineering@theiconic.com.au" + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "PHP library for parsing a string containing a full name into its parts", - "support": { - "issues": "https://github.com/theiconic/name-parser/issues", - "source": "https://github.com/theiconic/name-parser/tree/v1.2.11" - }, - "time": "2019-11-14T14:08:48+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "twig/twig", - "version": "v3.15.0", + "name": "symfony/translation", + "version": "v6.4.42", "source": { "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02" + "url": "https://github.com/symfony/translation.git", + "reference": "fef99cef37890b350976f5f492854faefadd4e15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/2d5b3964cc21d0188633d7ddce732dc8e874db02", - "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02", + "url": "https://api.github.com/repos/symfony/translation/zipball/fef99cef37890b350976f5f492854faefadd4e15", + "reference": "fef99cef37890b350976f5f492854faefadd4e15", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "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.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "symfony/config": "<5.4", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<5.4", + "symfony/yaml": "<5.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { - "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" + "nikic/php-parser": "^4.18|^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { "files": [ - "src/Resources/core.php", - "src/Resources/debug.php", - "src/Resources/escaper.php", - "src/Resources/string_loader.php" + "Resources/functions.php" ], "psr-4": { - "Twig\\": "src/" - } + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "role": "Contributors" + "email": "fabien@symfony.com" }, { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.15.0" + "source": "https://github.com/symfony/translation/tree/v6.4.42" }, "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, { "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-17T15:59:19+00:00" + "time": "2026-06-05T16:46:18+00:00" }, { - "name": "voku/anti-xss", - "version": "4.1.42", + "name": "symfony/translation-contracts", + "version": "v3.7.1", "source": { "type": "git", - "url": "https://github.com/voku/anti-xss.git", - "reference": "bca1f8607e55a3c5077483615cd93bd8f11bd675" + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/anti-xss/zipball/bca1f8607e55a3c5077483615cd93bd8f11bd675", - "reference": "bca1f8607e55a3c5077483615cd93bd8f11bd675", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/ccb206b98faccc511ebae8e5fad50f2dc0b30621", + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621", "shasum": "" }, "require": { - "php": ">=7.0.0", - "voku/portable-utf8": "~6.0.2" - }, - "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + "php": ">=8.1" }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-master": "4.1.x-dev" + "dev-main": "3.7-dev" } }, "autoload": { "psr-4": { - "voku\\helper\\": "src/voku/helper/" - } + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6346,82 +8428,79 @@ ], "authors": [ { - "name": "EllisLab Dev Team", - "homepage": "http://ellislab.com/" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Lars Moelleken", - "email": "lars@moelleken.org", - "homepage": "https://www.moelleken.org/" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "anti xss-library", - "homepage": "https://github.com/voku/anti-xss", + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", "keywords": [ - "anti-xss", - "clean", - "security", - "xss" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "issues": "https://github.com/voku/anti-xss/issues", - "source": "https://github.com/voku/anti-xss/tree/4.1.42" + "source": "https://github.com/symfony/translation-contracts/tree/v3.7.1" }, "funding": [ { - "url": "https://www.paypal.me/moelleken", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/voku", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://opencollective.com/anti-xss", - "type": "open_collective" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/voku/anti-xss", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-07-03T14:40:46+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { - "name": "voku/arrayy", - "version": "7.9.6", + "name": "symfony/type-info", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/voku/Arrayy.git", - "reference": "0e20b8c6eef7fc46694a2906e0eae2f9fc11cade" + "url": "https://github.com/symfony/type-info.git", + "reference": "9f24df8a79781b9b9f030fea7dfd2f3bd1e7e7e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/Arrayy/zipball/0e20b8c6eef7fc46694a2906e0eae2f9fc11cade", - "reference": "0e20b8c6eef7fc46694a2906e0eae2f9fc11cade", + "url": "https://api.github.com/repos/symfony/type-info/zipball/9f24df8a79781b9b9f030fea7dfd2f3bd1e7e7e7", + "reference": "9f24df8a79781b9b9f030fea7dfd2f3bd1e7e7e7", "shasum": "" }, "require": { - "ext-json": "*", - "php": ">=7.0.0", - "phpdocumentor/reflection-docblock": "~4.3 || ~5.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4.1", + "psr/container": "^1.1|^2.0" + }, + "conflict": { + "phpstan/phpdoc-parser": "<1.30" }, "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + "phpstan/phpdoc-parser": "^1.30|^2.0" }, "type": "library", "autoload": { - "files": [ - "src/Create.php" - ], "psr-4": { - "Arrayy\\": "src/" - } + "Symfony\\Component\\TypeInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6429,81 +8508,78 @@ ], "authors": [ { - "name": "Lars Moelleken", - "email": "lars@moelleken.org", - "homepage": "https://www.moelleken.org/", - "role": "Maintainer" + "name": "Mathias Arlaud", + "email": "mathias.arlaud@gmail.com" + }, + { + "name": "Baptiste LEDUC", + "email": "baptiste.leduc@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Array manipulation library for PHP, called Arrayy!", + "description": "Extracts PHP types information.", + "homepage": "https://symfony.com", "keywords": [ - "Arrayy", - "array", - "helpers", - "manipulation", - "methods", - "utility", - "utils" + "PHPStan", + "phpdoc", + "symfony", + "type" ], "support": { - "docs": "https://voku.github.io/Arrayy/", - "issues": "https://github.com/voku/Arrayy/issues", - "source": "https://github.com/voku/Arrayy" + "source": "https://github.com/symfony/type-info/tree/v8.1.0" }, "funding": [ { - "url": "https://www.paypal.me/moelleken", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/voku", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://opencollective.com/arrayy", - "type": "open_collective" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/voku/arrayy", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2022-12-27T12:58:32+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "voku/email-check", - "version": "3.1.0", + "name": "symfony/uid", + "version": "v7.4.9", "source": { "type": "git", - "url": "https://github.com/voku/email-check.git", - "reference": "6ea842920bbef6758b8c1e619fd1710e7a1a2cac" + "url": "https://github.com/symfony/uid.git", + "reference": "2676b524340abcfe4d6151ec698463cebafee439" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/email-check/zipball/6ea842920bbef6758b8c1e619fd1710e7a1a2cac", - "reference": "6ea842920bbef6758b8c1e619fd1710e7a1a2cac", + "url": "https://api.github.com/repos/symfony/uid/zipball/2676b524340abcfe4d6151ec698463cebafee439", + "reference": "2676b524340abcfe4d6151ec698463cebafee439", "shasum": "" }, "require": { - "php": ">=7.0.0", - "symfony/polyfill-intl-idn": "~1.10" + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "fzaninotto/faker": "~1.7", - "phpunit/phpunit": "~6.0 || ~7.0" - }, - "suggest": { - "ext-intl": "Use Intl for best performance" + "symfony/console": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { "psr-4": { - "voku\\helper\\": "src/voku/helper/" - } + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6511,73 +8587,91 @@ ], "authors": [ { - "name": "Lars Moelleken", - "homepage": "http://www.moelleken.org/" + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "email-check (syntax, dns, trash, ...) library", - "homepage": "https://github.com/voku/email-check", + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", "keywords": [ - "check-email", - "email", - "mail", - "mail-check", - "validate-email", - "validate-email-address", - "validate-mail" + "UID", + "ulid", + "uuid" ], "support": { - "issues": "https://github.com/voku/email-check/issues", - "source": "https://github.com/voku/email-check/tree/3.1.0" + "source": "https://github.com/symfony/uid/tree/v7.4.9" }, "funding": [ { - "url": "https://www.paypal.me/moelleken", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/voku", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://www.patreon.com/voku", - "type": "patreon" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/voku/email-check", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-01-27T14:14:33+00:00" + "time": "2026-04-30T15:19:22+00:00" }, { - "name": "voku/portable-ascii", - "version": "2.0.3", + "name": "symfony/var-dumper", + "version": "v7.4.14", "source": { "type": "git", - "url": "https://github.com/voku/portable-ascii.git", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358", + "reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358", "shasum": "" }, "require": { - "php": ">=7.0.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" }, - "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + "conflict": { + "symfony/console": "<6.4" }, - "suggest": { - "ext-intl": "Use Intl for transliterator_transliterate() support" + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" }, + "bin": [ + "Resources/bin/var-dump-server" + ], "type": "library", "autoload": { + "files": [ + "Resources/functions/dump.php" + ], "psr-4": { - "voku\\": "src/voku/" - } + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6585,172 +8679,148 @@ ], "authors": [ { - "name": "Lars Moelleken", - "homepage": "https://www.moelleken.org/" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", - "homepage": "https://github.com/voku/portable-ascii", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", "keywords": [ - "ascii", - "clean", - "php" + "debug", + "dump" ], "support": { - "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.14" }, "funding": [ { - "url": "https://www.paypal.me/moelleken", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/voku", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://opencollective.com/portable-ascii", - "type": "open_collective" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-21T01:49:47+00:00" + "time": "2026-06-08T20:24:16+00:00" }, { - "name": "voku/portable-utf8", - "version": "6.0.13", + "name": "symfony/yaml", + "version": "v7.4.14", "source": { "type": "git", - "url": "https://github.com/voku/portable-utf8.git", - "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f" + "url": "https://github.com/symfony/yaml.git", + "reference": "f8f328665ace2370d1e10645b807ba1646dc7dcc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-utf8/zipball/b8ce36bf26593e5c2e81b1850ef0ffb299d2043f", - "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f", + "url": "https://api.github.com/repos/symfony/yaml/zipball/f8f328665ace2370d1e10645b807ba1646dc7dcc", + "reference": "f8f328665ace2370d1e10645b807ba1646dc7dcc", "shasum": "" }, "require": { - "php": ">=7.0.0", - "symfony/polyfill-iconv": "~1.0", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php72": "~1.0", - "voku/portable-ascii": "~2.0.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" }, - "require-dev": { - "phpstan/phpstan": "1.9.*@dev", - "phpstan/phpstan-strict-rules": "1.4.*@dev", - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0", - "thecodingmachine/phpstan-strict-rules": "1.0.*@dev", - "voku/phpstan-rules": "3.1.*@dev" + "conflict": { + "symfony/console": "<6.4" }, - "suggest": { - "ext-ctype": "Use Ctype for e.g. hexadecimal digit detection", - "ext-fileinfo": "Use Fileinfo for better binary file detection", - "ext-iconv": "Use iconv for best performance", - "ext-intl": "Use Intl for best performance", - "ext-json": "Use JSON for string detection", - "ext-mbstring": "Use Mbstring for best performance" + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" }, + "bin": [ + "Resources/bin/yaml-lint" + ], "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "voku\\": "src/voku/" - } + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "(Apache-2.0 or GPL-2.0)" + "MIT" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Hamid Sarfraz", - "homepage": "http://pageconfig.com/" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Lars Moelleken", - "homepage": "http://www.moelleken.org/" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Portable UTF-8 library - performance optimized (unicode) string functions for php.", - "homepage": "https://github.com/voku/portable-utf8", - "keywords": [ - "UTF", - "clean", - "php", - "unicode", - "utf-8", - "utf8" - ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/voku/portable-utf8/issues", - "source": "https://github.com/voku/portable-utf8/tree/6.0.13" + "source": "https://github.com/symfony/yaml/tree/v7.4.14" }, "funding": [ { - "url": "https://www.paypal.me/moelleken", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/voku", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://opencollective.com/portable-utf8", - "type": "open_collective" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/voku/portable-utf8", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-03-08T08:35:38+00:00" + "time": "2026-06-08T20:24:16+00:00" }, { - "name": "voku/stop-words", - "version": "2.0.1", + "name": "theiconic/name-parser", + "version": "v1.2.11", "source": { "type": "git", - "url": "https://github.com/voku/stop-words.git", - "reference": "8e63c0af20f800b1600783764e0ce19e53969f71" + "url": "https://github.com/theiconic/name-parser.git", + "reference": "9a54a713bf5b2e7fd990828147d42de16bf8a253" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/stop-words/zipball/8e63c0af20f800b1600783764e0ce19e53969f71", - "reference": "8e63c0af20f800b1600783764e0ce19e53969f71", + "url": "https://api.github.com/repos/theiconic/name-parser/zipball/9a54a713bf5b2e7fd990828147d42de16bf8a253", + "reference": "9a54a713bf5b2e7fd990828147d42de16bf8a253", "shasum": "" }, "require": { - "php": ">=7.0.0" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~6.0" + "php-coveralls/php-coveralls": "^2.1", + "php-mock/php-mock-phpunit": "^2.1", + "phpunit/phpunit": "^7.0" }, "type": "library", "autoload": { "psr-4": { - "voku\\": "src/voku/" + "TheIconic\\NameParser\\": [ + "src/", + "tests/" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -6759,177 +8829,116 @@ ], "authors": [ { - "name": "Lars Moelleken", - "homepage": "http://www.moelleken.org/" + "name": "The Iconic", + "email": "engineering@theiconic.com.au" } ], - "description": "Stop-Words via PHP", - "keywords": [ - "stop words", - "stop-words" - ], + "description": "PHP library for parsing a string containing a full name into its parts", "support": { - "issues": "https://github.com/voku/stop-words/issues", - "source": "https://github.com/voku/stop-words/tree/master" + "issues": "https://github.com/theiconic/name-parser/issues", + "source": "https://github.com/theiconic/name-parser/tree/v1.2.11" }, - "time": "2018-11-23T01:37:27+00:00" + "time": "2019-11-14T14:08:48+00:00" }, { - "name": "voku/stringy", - "version": "6.5.3", + "name": "theseer/tokenizer", + "version": "1.3.1", "source": { "type": "git", - "url": "https://github.com/voku/Stringy.git", - "reference": "c453c88fbff298f042c836ef44306f8703b2d537" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/Stringy/zipball/c453c88fbff298f042c836ef44306f8703b2d537", - "reference": "c453c88fbff298f042c836ef44306f8703b2d537", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { - "defuse/php-encryption": "~2.0", - "ext-json": "*", - "php": ">=7.0.0", - "voku/anti-xss": "~4.1", - "voku/arrayy": "~7.8", - "voku/email-check": "~3.1", - "voku/portable-ascii": "~2.0", - "voku/portable-utf8": "~6.0", - "voku/urlify": "~5.0" - }, - "replace": { - "danielstjules/stringy": "~3.0" - }, - "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { - "files": [ - "src/Create.php" - ], - "psr-4": { - "Stringy\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Daniel St. Jules", - "email": "danielst.jules@gmail.com", - "homepage": "http://www.danielstjules.com", - "role": "Maintainer" - }, - { - "name": "Lars Moelleken", - "email": "lars@moelleken.org", - "homepage": "https://www.moelleken.org/", - "role": "Fork-Maintainer" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" } ], - "description": "A string manipulation library with multibyte support", - "homepage": "https://github.com/danielstjules/Stringy", - "keywords": [ - "UTF", - "helpers", - "manipulation", - "methods", - "multibyte", - "string", - "utf-8", - "utility", - "utils" - ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { - "issues": "https://github.com/voku/Stringy/issues", - "source": "https://github.com/voku/Stringy" + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { - "url": "https://www.paypal.me/moelleken", - "type": "custom" - }, - { - "url": "https://github.com/voku", + "url": "https://github.com/theseer", "type": "github" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/voku/stringy", - "type": "tidelift" } ], - "time": "2022-03-28T14:52:20+00:00" + "time": "2025-11-17T20:03:58+00:00" }, { - "name": "voku/urlify", - "version": "5.0.7", + "name": "voku/portable-ascii", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/voku/urlify.git", - "reference": "014b2074407b5db5968f836c27d8731934b330e4" + "url": "https://github.com/voku/portable-ascii.git", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/urlify/zipball/014b2074407b5db5968f836c27d8731934b330e4", - "reference": "014b2074407b5db5968f836c27d8731934b330e4", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", "shasum": "" }, "require": { - "php": ">=7.0.0", - "voku/portable-ascii": "~2.0", - "voku/portable-utf8": "~6.0", - "voku/stop-words": "~2.0" + "php": ">=7.0.0" }, "require-dev": { "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, "type": "library", "autoload": { "psr-4": { - "voku\\helper\\": "src/voku/helper/" + "voku\\": "src/voku/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ - { - "name": "Johnny Broadway", - "email": "johnny@johnnybroadway.com", - "homepage": "http://www.johnnybroadway.com/" - }, { "name": "Lars Moelleken", - "email": "lars@moelleken.org", - "homepage": "https://moelleken.org/" + "homepage": "https://www.moelleken.org/" } ], - "description": "PHP port of URLify.js from the Django project. Transliterates non-ascii characters for use in URLs.", - "homepage": "https://github.com/voku/urlify", + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", "keywords": [ - "encode", - "iconv", - "link", - "slug", - "translit", - "transliterate", - "transliteration", - "url", - "urlify" + "ascii", + "clean", + "php" ], "support": { - "issues": "https://github.com/voku/urlify/issues", - "source": "https://github.com/voku/urlify/tree/5.0.7" + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" }, "funding": [ { @@ -6940,56 +8949,49 @@ "url": "https://github.com/voku", "type": "github" }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, { "url": "https://www.patreon.com/voku", "type": "patreon" }, { - "url": "https://tidelift.com/funding/github/packagist/voku/urlify", + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", "type": "tidelift" } ], - "time": "2022-01-24T19:08:46+00:00" + "time": "2024-11-21T01:49:47+00:00" }, { "name": "web-auth/cose-lib", - "version": "4.4.2", + "version": "4.5.2", "source": { "type": "git", "url": "https://github.com/web-auth/cose-lib.git", - "reference": "a93b61c48fb587855f64a9ec11ad7b60e867cb15" + "reference": "5b38660f90070a8e45f3dbc9528ade3b608dd77d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/a93b61c48fb587855f64a9ec11ad7b60e867cb15", - "reference": "a93b61c48fb587855f64a9ec11ad7b60e867cb15", + "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/5b38660f90070a8e45f3dbc9528ade3b608dd77d", + "reference": "5b38660f90070a8e45f3dbc9528ade3b608dd77d", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13", + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13|^0.14|^0.15|^0.16|^0.17", "ext-json": "*", "ext-openssl": "*", "php": ">=8.1", "spomky-labs/pki-framework": "^1.0" }, "require-dev": { - "deptrac/deptrac": "^3.0", - "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", - "infection/infection": "^0.29", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/extension-installer": "^1.3", - "phpstan/phpstan": "^1.7|^2.0", - "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", - "phpstan/phpstan-phpunit": "^1.1|^2.0", - "phpstan/phpstan-strict-rules": "^1.0|^2.0", - "phpunit/phpunit": "^10.1|^11.0|^12.0", - "rector/rector": "^2.0", - "symfony/phpunit-bridge": "^6.4|^7.0", - "symplify/easy-coding-standard": "^12.0" + "spomky-labs/cbor-php": "^3.2.2" }, "suggest": { "ext-bcmath": "For better performance, please install either GMP (recommended) or BCMath extension", - "ext-gmp": "For better performance, please install either GMP (recommended) or BCMath extension" + "ext-gmp": "For better performance, please install either GMP (recommended) or BCMath extension", + "spomky-labs/cbor-php": "For COSE Signature support" }, "type": "library", "autoload": { @@ -7019,7 +9021,7 @@ ], "support": { "issues": "https://github.com/web-auth/cose-lib/issues", - "source": "https://github.com/web-auth/cose-lib/tree/4.4.2" + "source": "https://github.com/web-auth/cose-lib/tree/4.5.2" }, "funding": [ { @@ -7031,48 +9033,44 @@ "type": "patreon" } ], - "time": "2025-08-14T20:33:29+00:00" + "time": "2026-05-03T09:49:50+00:00" }, { "name": "web-auth/webauthn-lib", - "version": "4.9.2", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-lib.git", - "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a" + "reference": "0785f55f242c1cc026ec24a9c8653eac59fe3493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/008b25171c27cf4813420d0de31cc059bcc71f1a", - "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/0785f55f242c1cc026ec24a9c8653eac59fe3493", + "reference": "0785f55f242c1cc026ec24a9c8653eac59fe3493", "shasum": "" }, "require": { "ext-json": "*", - "ext-mbstring": "*", "ext-openssl": "*", - "lcobucci/clock": "^2.2|^3.0", "paragonie/constant_time_encoding": "^2.6|^3.0", - "php": ">=8.1", + "php": ">=8.2", + "phpdocumentor/reflection-docblock": "^5.3", "psr/clock": "^1.0", "psr/event-dispatcher": "^1.0", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", "psr/log": "^1.0|^2.0|^3.0", "spomky-labs/cbor-php": "^3.0", "spomky-labs/pki-framework": "^1.0", + "symfony/clock": "^6.4|^7.0", "symfony/deprecation-contracts": "^3.2", - "symfony/uid": "^6.1|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", "web-auth/cose-lib": "^4.2.3" }, "suggest": { - "phpdocumentor/reflection-docblock": "As of 4.5.x, the phpdocumentor/reflection-docblock component will become mandatory for converting objects such as the Metadata Statement", - "psr/clock-implementation": "As of 4.5.x, the PSR Clock implementation will replace lcobucci/clock", "psr/log-implementation": "Recommended to receive logs from the library", "symfony/event-dispatcher": "Recommended to use dispatched events", - "symfony/property-access": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", - "symfony/property-info": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", - "symfony/serializer": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", "web-token/jwt-library": "Mandatory for fetching Metadata Statement from distant sources" }, "type": "library", @@ -7109,7 +9107,7 @@ "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-lib/tree/4.9.2" + "source": "https://github.com/web-auth/webauthn-lib/tree/5.2.6" }, "funding": [ { @@ -7121,27 +9119,27 @@ "type": "patreon" } ], - "time": "2025-01-04T09:47:58+00:00" + "time": "2026-03-23T22:13:50+00:00" }, { "name": "webmozart/assert", - "version": "1.12.1", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + "reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/2ccb7c2e821038c03a3e6e1700c570c158c55f70", + "reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70", "shasum": "" }, "require": { "ext-ctype": "*", "ext-date": "*", "ext-filter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.2" }, "suggest": { "ext-intl": "", @@ -7150,8 +9148,12 @@ }, "type": "library", "extra": { + "psalm": { + "pluginClass": "Webmozart\\Assert\\PsalmPlugin" + }, "branch-alias": { - "dev-master": "1.10-dev" + "dev-master": "2.0-dev", + "dev-feature/2-0": "2.0-dev" } }, "autoload": { @@ -7167,6 +9169,10 @@ { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" } ], "description": "Assertions to validate method input/output with nice error messages.", @@ -7177,100 +9183,35 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.1" - }, - "time": "2025-10-29T15:56:20+00:00" - }, - { - "name": "webonyx/graphql-php", - "version": "v14.11.10", - "source": { - "type": "git", - "url": "https://github.com/webonyx/graphql-php.git", - "reference": "d9c2fdebc6aa01d831bc2969da00e8588cffef19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/d9c2fdebc6aa01d831bc2969da00e8588cffef19", - "reference": "d9c2fdebc6aa01d831bc2969da00e8588cffef19", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": "^7.1 || ^8" - }, - "require-dev": { - "amphp/amp": "^2.3", - "doctrine/coding-standard": "^6.0", - "nyholm/psr7": "^1.2", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.82", - "phpstan/phpstan-phpunit": "0.12.18", - "phpstan/phpstan-strict-rules": "0.12.9", - "phpunit/phpunit": "^7.2 || ^8.5", - "psr/http-message": "^1.0", - "react/promise": "2.*", - "simpod/php-coveralls-mirror": "^3.0" - }, - "suggest": { - "psr/http-message": "To use standard GraphQL server", - "react/promise": "To leverage async resolving on React PHP platform" - }, - "type": "library", - "autoload": { - "psr-4": { - "GraphQL\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A PHP port of GraphQL reference implementation", - "homepage": "https://github.com/webonyx/graphql-php", - "keywords": [ - "api", - "graphql" - ], - "support": { - "issues": "https://github.com/webonyx/graphql-php/issues", - "source": "https://github.com/webonyx/graphql-php/tree/v14.11.10" + "source": "https://github.com/webmozarts/assert/tree/2.4.1" }, - "funding": [ - { - "url": "https://opencollective.com/webonyx-graphql-php", - "type": "open_collective" - } - ], - "time": "2023-07-05T14:23:37+00:00" + "time": "2026-06-15T15:31:57+00:00" }, { "name": "yiisoft/yii2", - "version": "2.0.52", + "version": "2.0.55", "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-framework.git", - "reference": "540e7387d934c52e415614aa081fb38d04c72d9a" + "reference": "b900eecdb225041a4c4e0f5e0e5336f606a23bdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/540e7387d934c52e415614aa081fb38d04c72d9a", - "reference": "540e7387d934c52e415614aa081fb38d04c72d9a", + "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/b900eecdb225041a4c4e0f5e0e5336f606a23bdb", + "reference": "b900eecdb225041a4c4e0f5e0e5336f606a23bdb", "shasum": "" }, "require": { "bower-asset/inputmask": "^5.0.8 ", "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", - "bower-asset/punycode": "^1.4", + "bower-asset/punycode": "^2.2", "bower-asset/yii2-pjax": "~2.0.1", "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0", "ext-ctype": "*", "ext-mbstring": "*", "ezyang/htmlpurifier": "^4.17", "lib-pcre": "*", - "php": ">=7.3.0", + "php": ">=7.4.0", "yiisoft/yii2-composer": "~2.0.4" }, "bin": [ @@ -7365,7 +9306,7 @@ "type": "tidelift" } ], - "time": "2025-02-13T20:02:28+00:00" + "time": "2026-05-09T14:50:57+00:00" }, { "name": "yiisoft/yii2-composer", @@ -7536,16 +9477,16 @@ }, { "name": "yiisoft/yii2-queue", - "version": "2.3.7", + "version": "2.3.8", "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-queue.git", - "reference": "dbc9d4a7b2a6995cd19c3e334227482ef55e559b" + "reference": "e0f935e5b868d53347acfb14ec19faaf16085005" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-queue/zipball/dbc9d4a7b2a6995cd19c3e334227482ef55e559b", - "reference": "dbc9d4a7b2a6995cd19c3e334227482ef55e559b", + "url": "https://api.github.com/repos/yiisoft/yii2-queue/zipball/e0f935e5b868d53347acfb14ec19faaf16085005", + "reference": "e0f935e5b868d53347acfb14ec19faaf16085005", "shasum": "" }, "require": { @@ -7557,14 +9498,14 @@ "aws/aws-sdk-php": ">=2.4", "cweagans/composer-patches": "^1.7", "enqueue/amqp-lib": "^0.8||^0.9.10||^0.10.0", - "enqueue/stomp": "^0.8.39||^0.10.0", + "enqueue/stomp": "^0.8.39||0.10.19", "opis/closure": "*", "pda/pheanstalk": "~3.2.1", "php-amqplib/php-amqplib": "^2.8.0||^3.0.0", "phpunit/phpunit": "4.8.34", "yiisoft/yii2-debug": "~2.1.0", "yiisoft/yii2-gii": "~2.2.0", - "yiisoft/yii2-redis": "~2.0.0" + "yiisoft/yii2-redis": "2.0.19" }, "suggest": { "aws/aws-sdk-php": "Need for aws SQS.", @@ -7617,7 +9558,7 @@ "email": "zhuravljov@gmail.com" } ], - "description": "Yii2 Queue Extension which supported DB, Redis, RabbitMQ, Beanstalk, SQS and Gearman", + "description": "Yii2 Queue Extension which supports queues based on DB, Redis, RabbitMQ, Beanstalk, SQS, and Gearman", "keywords": [ "async", "beanstalk", @@ -7649,7 +9590,7 @@ "type": "tidelift" } ], - "time": "2024-04-29T09:40:52+00:00" + "time": "2026-01-08T07:52:05+00:00" }, { "name": "yiisoft/yii2-symfonymailer", diff --git a/extension.neon b/extension.neon index 4d2b4bb..785f8b6 100644 --- a/extension.neon +++ b/extension.neon @@ -7,8 +7,25 @@ parameters: - %currentWorkingDirectory%/modules - %currentWorkingDirectory%/plugins handleMap: [] + craftTemplateScan: + # Directory names (not paths) pruned from the template walk. Keeps + # third-party templates bundled under vendor/ (Craft's own CP templates, + # other plugins' example/asset templates) out of scanning when a + # template path points at a directory that contains them. + excludeDirectories: + - vendor + - node_modules craftcms: projectConfigPath: %currentWorkingDirectory%/config/project + craftTwigPerformance: + enabled: true + templatePaths: %craftActionInput.templatePaths% + checks: + nPlusOne: true + nestedRelationAll: true + queryInLoop: true + lengthOnQuery: true + unboundedAll: false reportUnmatchedIgnoredErrors: false excludePaths: - ../../craftcms/cms/src/test/internal/* @@ -45,9 +62,23 @@ parametersSchema: templatePaths: listOf(string()) handleMap: schema(arrayOf(string())) ]) + craftTemplateScan: structure([ + excludeDirectories: listOf(string()) + ]) craftcms: structure([ projectConfigPath: schema(string()) ]) + craftTwigPerformance: structure([ + enabled: schema(bool()) + templatePaths: listOf(string()) + checks: structure([ + nPlusOne: schema(bool()) + nestedRelationAll: schema(bool()) + queryInLoop: schema(bool()) + lengthOnQuery: schema(bool()) + unboundedAll: schema(bool()) + ]) + ]) services: - @@ -68,10 +99,27 @@ services: class: Jensderond\PhpstanCraftcms\Collector\ControllerActionCollector tags: - phpstan.collector + - + class: Jensderond\PhpstanCraftcms\Collector\AnalysisMarkerCollector + tags: + - phpstan.collector + - + class: Jensderond\PhpstanCraftcms\Twig\TwigTemplateScanner + arguments: + parser: @Jensderond\PhpstanCraftcms\Twig\TwigTemplateParser + actionInputPaths: %craftActionInput.templatePaths% + performancePaths: %craftTwigPerformance.templatePaths% + excludeDirectories: %craftTemplateScan.excludeDirectories% + - + class: Jensderond\PhpstanCraftcms\Twig\TwigTemplateCacheMetaExtension + arguments: + scanner: @Jensderond\PhpstanCraftcms\Twig\TwigTemplateScanner + tags: + - phpstan.resultCacheMetaExtension - class: Jensderond\PhpstanCraftcms\Rule\TwigActionInputRule arguments: - templatePaths: %craftActionInput.templatePaths% + scanner: @Jensderond\PhpstanCraftcms\Twig\TwigTemplateScanner tags: - phpstan.rules.rule - @@ -86,3 +134,18 @@ services: class: Jensderond\PhpstanCraftcms\Reflection\CustomFieldQueryMethodsExtension tags: - phpstan.broker.methodsClassReflectionExtension + - Jensderond\PhpstanCraftcms\Twig\TwigTemplateParser + - Jensderond\PhpstanCraftcms\Helper\RelationFieldRegistry(%craftcms.projectConfigPath%) + - + class: Jensderond\PhpstanCraftcms\Twig\TwigPerformanceAnalyzer + arguments: + relations: @Jensderond\PhpstanCraftcms\Helper\RelationFieldRegistry + enabledChecks: %craftTwigPerformance.checks% + - + class: Jensderond\PhpstanCraftcms\Rule\TwigPerformanceRule + arguments: + scanner: @Jensderond\PhpstanCraftcms\Twig\TwigTemplateScanner + analyzer: @Jensderond\PhpstanCraftcms\Twig\TwigPerformanceAnalyzer + enabled: %craftTwigPerformance.enabled% + tags: + - phpstan.rules.rule diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..5c8474e --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,13 @@ + + + + + tests + + + diff --git a/src/Collector/AnalysisMarkerCollector.php b/src/Collector/AnalysisMarkerCollector.php new file mode 100644 index 0000000..96b2d27 --- /dev/null +++ b/src/Collector/AnalysisMarkerCollector.php @@ -0,0 +1,41 @@ + + */ +final class AnalysisMarkerCollector implements Collector +{ + public function getNodeType(): string + { + return FileNode::class; + } + + /** + * @param FileNode $node + */ + public function processNode(Node $node, Scope $scope): bool + { + return true; + } +} diff --git a/src/Helper/RelationFieldRegistry.php b/src/Helper/RelationFieldRegistry.php new file mode 100644 index 0000000..f69d6c5 --- /dev/null +++ b/src/Helper/RelationFieldRegistry.php @@ -0,0 +1,99 @@ + + */ + private const RELATIONAL_FIELD_TYPES = [ + 'craft\\fields\\Entries', + 'craft\\fields\\Categories', + 'craft\\fields\\Assets', + 'craft\\fields\\Users', + 'craft\\fields\\Tags', + 'craft\\fields\\Matrix', + 'craft\\fields\\Addresses', + ]; + + /** + * Native element accessors that lazily query related elements. + * + * @var array + */ + private const BUILT_IN_RELATIONS = [ + 'author' => true, + 'parent' => true, + 'children' => true, + 'ancestors' => true, + 'descendants' => true, + 'siblings' => true, + 'prevSibling' => true, + 'nextSibling' => true, + 'currentRevision' => true, + ]; + + /** @var array|null */ + private ?array $relationHandles = null; + + public function __construct(private readonly string $projectConfigPath) {} + + public function isRelation(string $handle): bool + { + if (isset(self::BUILT_IN_RELATIONS[$handle])) { + return true; + } + + return isset($this->relationalHandles()[$handle]); + } + + /** + * @return array + */ + private function relationalHandles(): array + { + if ($this->relationHandles !== null) { + return $this->relationHandles; + } + + $handles = []; + $root = rtrim($this->projectConfigPath, '/'); + + foreach (glob($root.'/fields/*.yaml') ?: [] as $file) { + $handle = $this->relationalHandleFromFile($file); + if ($handle !== null) { + $handles[$handle] = true; + } + } + + return $this->relationHandles = $handles; + } + + private function relationalHandleFromFile(string $file): ?string + { + $contents = @file_get_contents($file); + if ($contents === false) { + return null; + } + + if (preg_match('/^type:\s*(\S+)\s*$/m', $contents, $typeMatch) !== 1) { + return null; + } + + $type = trim($typeMatch[1], "\"'"); + if (! in_array($type, self::RELATIONAL_FIELD_TYPES, true)) { + return null; + } + + if (preg_match('/^handle:\s*(\S+)\s*$/m', $contents, $handleMatch) !== 1) { + return null; + } + + return trim($handleMatch[1], "\"'"); + } +} diff --git a/src/Rule/TwigActionInputRule.php b/src/Rule/TwigActionInputRule.php index caeb46d..2265b63 100644 --- a/src/Rule/TwigActionInputRule.php +++ b/src/Rule/TwigActionInputRule.php @@ -7,29 +7,28 @@ use Jensderond\PhpstanCraftcms\Collector\ControllerActionCollector; use Jensderond\PhpstanCraftcms\Helper\ActionRouteMap; use Jensderond\PhpstanCraftcms\Helper\ActionRouteResolver; +use Jensderond\PhpstanCraftcms\Twig\TwigTemplateScanner; use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\CollectedDataNode; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; -use SplFileInfo; /** * Validates that actionInput() calls in Twig templates reference valid controller action routes. * + * Template traversal is delegated to {@see TwigTemplateScanner} (shared with + * the performance scanning); this rule only needs each template's raw contents + * for its regex match. + * * @implements Rule */ final class TwigActionInputRule implements Rule { - /** - * @param list $templatePaths - */ public function __construct( private readonly ActionRouteMap $actionRouteMap, - private readonly array $templatePaths, + private readonly TwigTemplateScanner $scanner, ) {} public function getNodeType(): string @@ -75,12 +74,14 @@ public function processNode(Node $node, Scope $scope): array /** @var list $errors */ $errors = []; - foreach ($this->templatePaths as $templatePath) { - if (! is_dir($templatePath)) { + foreach ($this->scanner->scan() as $template) { + $contents = $template->contents(); + + if ($contents === null) { continue; } - $this->scanDirectory($templatePath, $validRoutes, $errors); + $this->scanTwigFile($template->path(), $contents, $validRoutes, $errors); } return $errors; @@ -90,40 +91,8 @@ public function processNode(Node $node, Scope $scope): array * @param array $validRoutes * @param list $errors */ - private function scanDirectory(string $directory, array $validRoutes, array &$errors): void + private function scanTwigFile(string $filePath, string $contents, array $validRoutes, array &$errors): void { - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($directory), - ); - - /** @var SplFileInfo $file */ - foreach ($iterator as $file) { - if ($file->getExtension() !== 'twig') { - continue; - } - - $realPath = $file->getRealPath(); - - if ($realPath === false) { - continue; - } - - $this->scanTwigFile($realPath, $validRoutes, $errors); - } - } - - /** - * @param array $validRoutes - * @param list $errors - */ - private function scanTwigFile(string $filePath, array $validRoutes, array &$errors): void - { - $contents = file_get_contents($filePath); - - if ($contents === false) { - return; - } - // Match actionInput('route/string') or actionInput("route/string") if (! preg_match_all('/actionInput\(\s*[\'"]([^\'"]+)[\'"]/m', $contents, $matches, PREG_OFFSET_CAPTURE)) { return; diff --git a/src/Rule/TwigPerformanceRule.php b/src/Rule/TwigPerformanceRule.php new file mode 100644 index 0000000..6ed1b77 --- /dev/null +++ b/src/Rule/TwigPerformanceRule.php @@ -0,0 +1,82 @@ + + */ +final class TwigPerformanceRule implements Rule +{ + public function __construct( + private readonly TwigTemplateScanner $scanner, + private readonly TwigPerformanceAnalyzer $analyzer, + private readonly bool $enabled, + ) {} + + public function getNodeType(): string + { + return CollectedDataNode::class; + } + + /** + * @param CollectedDataNode $node + * @return list + */ + public function processNode(Node $node, Scope $scope): array + { + return $this->scanTemplates(); + } + + /** + * @return list + */ + public function scanTemplates(): array + { + if (! $this->enabled) { + return []; + } + + /** @var list $errors */ + $errors = []; + + foreach ($this->scanner->scan() as $template) { + $module = $template->module(); + if ($module === null) { + continue; + } + + foreach ($this->analyzer->analyze($module) as $finding) { + $builder = RuleErrorBuilder::message($finding->message) + ->file($template->path()) + ->line($finding->line) + ->identifier($finding->identifier); + + if ($finding->tip !== null) { + $builder->tip($finding->tip); + } + + $errors[] = $builder->build(); + } + } + + return $errors; + } +} diff --git a/src/Twig/Finding.php b/src/Twig/Finding.php new file mode 100644 index 0000000..a2828da --- /dev/null +++ b/src/Twig/Finding.php @@ -0,0 +1,15 @@ +parser->getStream(); + + // Drop every token of this tag statement until its closing `%}`. + while (! $stream->test(Token::BLOCK_END_TYPE)) { + $stream->next(); + } + $stream->expect(Token::BLOCK_END_TYPE); + + return new Nodes([], $token->getLine()); + } + + public function getTag(): string + { + return $this->tag; + } +} diff --git a/src/Twig/ScannedTemplate.php b/src/Twig/ScannedTemplate.php new file mode 100644 index 0000000..f587ed7 --- /dev/null +++ b/src/Twig/ScannedTemplate.php @@ -0,0 +1,61 @@ +path; + } + + /** + * Raw file contents, or null when the file could not be read. + */ + public function contents(): ?string + { + if ($this->contents === null) { + $this->contents = @file_get_contents($this->path); + } + + return $this->contents === false ? null : $this->contents; + } + + /** + * The parsed Twig module, or null when the file could not be read or parsed. + */ + public function module(): ?ModuleNode + { + if (! $this->parsed) { + $this->parsed = true; + + $contents = $this->contents(); + if ($contents !== null) { + $this->module = $this->parser->parseSource($contents, $this->path); + } + } + + return $this->module; + } +} diff --git a/src/Twig/TwigNodeHelper.php b/src/Twig/TwigNodeHelper.php new file mode 100644 index 0000000..1300bdc --- /dev/null +++ b/src/Twig/TwigNodeHelper.php @@ -0,0 +1,245 @@ +hasAttribute('name') && ! $node->hasNode('node')) { + $name = $node->getAttribute('name'); + + return is_string($name) ? $name : null; + } + + return null; + } + + /** + * The accessor name of a GetAttr node (e.g. `author` in `entry.author`). + */ + public static function attrName(GetAttrExpression $node): ?string + { + if (! $node->hasNode('attribute')) { + return null; + } + + $attr = $node->getNode('attribute'); + if ($attr instanceof ConstantExpression) { + $value = $attr->getAttribute('value'); + + return is_string($value) ? $value : null; + } + + return null; + } + + /** + * True when the GetAttr is a method call (`foo.bar(...)`) rather than a + * property/array access. + */ + public static function isMethodCall(GetAttrExpression $node): bool + { + return $node->hasAttribute('type') && $node->getAttribute('type') === 'method'; + } + + /** + * Walks a GetAttr/method chain and returns the set of accessor names used, + * e.g. for `q.with([...]).all()` → ['with' => true, 'all' => true]. + * + * @return array + */ + public static function methodsInChain(Node $node): array + { + $methods = []; + $current = $node; + + while ($current instanceof GetAttrExpression) { + if (self::isMethodCall($current)) { + $name = self::attrName($current); + if ($name !== null) { + $methods[$name] = true; + } + } + $current = $current->hasNode('node') ? $current->getNode('node') : null; + if (! $current instanceof Node) { + break; + } + } + + return $methods; + } + + /** + * For a `with([...])` call somewhere in the chain rooted at $node, return the + * literal string relation handles it eager-loads. Returns null when a + * `with(...)` exists but its argument is not a literal string array (dynamic + * args → caller must treat relations as possibly eager-loaded). + * + * @return array|null + */ + public static function eagerLoadedRelations(Node $node): ?array + { + $current = $node; + + while ($current instanceof GetAttrExpression) { + if (self::isMethodCall($current) && self::attrName($current) === 'with' && $current->hasNode('arguments')) { + return self::literalStringsFromArguments($current->getNode('arguments')); + } + $current = $current->hasNode('node') ? $current->getNode('node') : null; + if (! $current instanceof Node) { + break; + } + } + + return []; + } + + /** + * @return array|null null when args are not a literal string list + */ + private static function literalStringsFromArguments(Node $arguments): ?array + { + // $arguments is an ArrayExpression of call args: its children alternate + // key (a LocalVariable holding the positional index) / value (the actual + // argument expression). The first call argument's value is therefore at + // index 1, not index 0. + $first = self::firstArgumentValue($arguments); + + if ($first instanceof ConstantExpression) { + $value = $first->getAttribute('value'); + + return is_string($value) ? [$value => true] : null; + } + + if ($first instanceof ArrayExpression) { + $relations = []; + foreach ($first->getKeyValuePairs() as $pair) { + $element = $pair['value']; + if (! $element instanceof ConstantExpression) { + return null; // dynamic element → unknown + } + $value = $element->getAttribute('value'); + if (is_string($value)) { + $relations[$value] = true; + } + } + + return $relations; + } + + return null; // not a literal → unknown + } + + private static function firstArgumentValue(Node $arguments): ?Node + { + if ($arguments instanceof ArrayExpression) { + $pairs = $arguments->getKeyValuePairs(); + + return $pairs === [] ? null : $pairs[0]['value']; + } + + foreach ($arguments as $arg) { + return $arg; + } + + return null; + } + + /** + * Root variable name of a GetAttr/method chain, e.g. `craft` in + * `craft.entries.all()`. + */ + public static function rootName(Node $node): ?string + { + $current = $node; + while ($current instanceof GetAttrExpression && $current->hasNode('node')) { + $current = $current->getNode('node'); + } + + return self::nameOf($current); + } + + /** + * Heuristic: the chain looks like a Craft element query (`craft.entries`, + * `craft.assets`, ... or a `.find()`/`.relatedTo()` builder). + */ + public static function isQueryRooted(Node $node): bool + { + if (self::rootName($node) === 'craft') { + return self::chainHasAnyAttr($node, ['entries', 'assets', 'users', 'categories', 'tags', 'addresses']); + } + + $methods = self::methodsInChain($node); + + return isset($methods['find']) || isset($methods['relatedTo']); + } + + /** + * @param list $names + */ + public static function chainHasAnyAttr(Node $node, array $names): bool + { + foreach ($names as $name) { + if (self::chainHasAttr($node, $name)) { + return true; + } + } + + return false; + } + + public static function chainHasAttr(Node $node, string $name): bool + { + $current = $node; + while ($current instanceof GetAttrExpression) { + if (self::attrName($current) === $name) { + return true; + } + $current = $current->hasNode('node') ? $current->getNode('node') : null; + if (! $current instanceof Node) { + break; + } + } + + return false; + } + + /** + * The filter name of a FilterExpression (e.g. `length` in `foo|length`). + * Verified against Twig 3.27 (the required floor): the `name` attribute is + * always set by the FilterExpression constructor regardless of how it was + * built, and the `filter` child node (when present) is a ConstantExpression + * carrying the same value. + */ + public static function filterName(FilterExpression $node): ?string + { + if ($node->hasAttribute('name')) { + $name = $node->getAttribute('name'); + + return is_string($name) ? $name : null; + } + + if ($node->hasNode('filter')) { + $filter = $node->getNode('filter'); + if ($filter instanceof ConstantExpression) { + $value = $filter->getAttribute('value'); + + return is_string($value) ? $value : null; + } + } + + return null; + } +} diff --git a/src/Twig/TwigPerformanceAnalyzer.php b/src/Twig/TwigPerformanceAnalyzer.php new file mode 100644 index 0000000..1fb7c48 --- /dev/null +++ b/src/Twig/TwigPerformanceAnalyzer.php @@ -0,0 +1,737 @@ + */ + private array $findings = []; + + /** + * Stack of active loops. Each frame: loop value-variable name + the relations + * known to be eager-loaded on the loop source. eagerLoaded === null means a + * dynamic with(...) was present → suppress N+1 for this loop. nonElement is + * true when the loop iterates a plain data structure (an array/hash literal, + * directly or via {% set %}/nesting) rather than element query results — such + * a loop variable can never trigger a relation N+1, so those checks skip it. + * + * @var list|null, nonElement: bool}> + */ + private array $loopStack = []; + + /** + * Variables assigned in the current scope via {% set x = ... %}, mapped to + * the assigned expression, so a loop over `x` can resolve its source. + * + * @var array + */ + private array $assignments = []; + + /** + * Variable names currently bound to a plain (non-element) value: assigned an + * array/hash literal via {% set %}, or the value variable of a loop whose + * source is itself plain. Used to propagate "this is not a Craft element" + * through {% set %} and nested loops (e.g. the fonts hash in + * `{% for family, fonts in fonts %}{% for font in fonts %}`). + * + * @var array + */ + private array $plainVars = []; + + /** + * @param array $enabledChecks + */ + public function __construct( + private readonly RelationFieldRegistry $relations, + private readonly array $enabledChecks, + ) {} + + /** + * @return list + */ + public function analyze(ModuleNode $module): array + { + $this->findings = []; + $this->loopStack = []; + $this->assignments = []; + $this->plainVars = []; + + $this->walk($module); + + return $this->findings; + } + + private function enabled(string $check): bool + { + return $this->enabledChecks[$check] ?? false; + } + + private function walk(Node $node): void + { + if ($node instanceof SetNode) { + $this->recordAssignment($node); + } + + if ($node instanceof ForNode) { + // Walk the loop's source expression in the OUTER context first: a + // query used as the loop's own source runs once (before iteration + // begins), so it must not be visible to checks like + // checkQueryInLoop() as "inside this loop". If that same source + // expression is itself nested inside an enclosing loop, the outer + // frame is still on the stack at this point, so it is correctly + // flagged as running per outer iteration. + $seq = $node->getNode('seq'); + $this->walk($seq); + + $valueVar = $this->enterLoop($node); + $nonElement = $this->loopStack[count($this->loopStack) - 1]['nonElement']; + + // Inside the loop body, the value variable holds one iterated item. + // If the source is plain, so is each item — propagate that so a + // nested loop over this variable is recognised as plain too. Save + // and restore any shadowed outer binding. + $hadPlain = isset($this->plainVars[$valueVar]); + if ($nonElement) { + $this->plainVars[$valueVar] = true; + } else { + unset($this->plainVars[$valueVar]); + } + + // The {% else %} branch runs at most once (only when the sequence + // is empty), so it is walked OUTSIDE this loop's frame below — + // a query there is not a per-iteration query. + $else = $node->hasNode('else') ? $node->getNode('else') : null; + + foreach ($node as $child) { + if ($child === $seq || $child === $else) { + continue; + } + $this->walk($child); + } + + array_pop($this->loopStack); + if ($hadPlain) { + $this->plainVars[$valueVar] = true; + } else { + unset($this->plainVars[$valueVar]); + } + + if ($else instanceof Node) { + $this->walk($else); + } + + return; + } + + if ($node instanceof GetAttrExpression) { + $this->checkChain($node); + $this->checkNestedRelationAll($node); + $this->checkQueryInLoop($node); + $this->checkUnboundedAll($node); + $this->walkChainSideBranches($node); + + return; + } + + if ($node instanceof FilterExpression) { + $this->checkLengthOnQuery($node); + } + + foreach ($node as $child) { + $this->walk($child); + } + } + + /** + * GetAttr nodes link into a chain via their `node` child (e.g. + * `entry.author.eagerly().one()` is four nested GetAttrs). We only want to + * evaluate the N+1 check once per chain — from the outermost node, looking + * down the whole chain — rather than once per GetAttr in it, otherwise a + * `.eagerly()` applied above the relation access would not be visible when + * the inner `entry.author` node is inspected in isolation. + * + * `walk()` only calls this for a GetAttr it reaches by general recursion, + * which is always the outermost unvisited GetAttr of its chain (inner ones + * are consumed by walkChainSideBranches() below, not by the outer foreach), + * so every chain is scanned exactly once, top-down. + */ + private function checkChain(GetAttrExpression $node): void + { + if (! $this->enabled('nPlusOne') || $this->loopStack === []) { + return; + } + + $chainMethodsAboveRelation = []; + $current = $node; + + while ($current instanceof GetAttrExpression) { + $object = $current->hasNode('node') ? $current->getNode('node') : null; + $objectName = $object instanceof Node ? TwigNodeHelper::nameOf($object) : null; + + // The chain may be rooted at ANY active loop's value variable, not + // just the innermost one: `entry.author` inside a nested loop still + // runs once per `entry` iteration. elementLoopFrame() resolves the + // name shadow-aware, so an inner loop over a plain literal masks an + // outer element loop of the same variable name. + if ($objectName !== null && ($frame = $this->elementLoopFrame($objectName)) !== null) { + // `.` found: $current is the relation access. + $this->reportIfUnguarded($current, $frame, $chainMethodsAboveRelation); + + return; + } + + if (TwigNodeHelper::isMethodCall($current)) { + $name = TwigNodeHelper::attrName($current); + if ($name !== null) { + $chainMethodsAboveRelation[$name] = true; + } + } + + $current = $object; + } + } + + /** + * @param array{var: string, eagerLoaded: array|null} $frame + * @param array $methodsAboveRelation Method names applied + * on top of the relation access within the same chain, e.g. `eagerly` + * in `entry.author.eagerly().one()`. + */ + private function reportIfUnguarded(GetAttrExpression $relationAccess, array $frame, array $methodsAboveRelation): void + { + if (isset($methodsAboveRelation['eagerly'])) { + return; + } + + $attr = TwigNodeHelper::attrName($relationAccess); + if ($attr === null || ! $this->relations->isRelation($attr)) { + return; + } + + // Suppress if eager-loaded (or dynamic with(...) → null → unknown). + $eager = $frame['eagerLoaded']; + if ($eager === null || $this->isEagerLoaded($eager, $attr)) { + return; + } + + $this->findings[] = new Finding( + 'craftcms.twigNPlusOne', + $relationAccess->getTemplateLine(), + sprintf('Relation "%s" is accessed inside a loop without eager-loading, causing an N+1 query.', $attr), + sprintf('Eager-load it on the query with .with([\'%s\']) or use %s.%s.eagerly() in the loop.', $attr, $frame['var'], $attr), + ); + } + + /** + * Pattern: `..all()` inside a loop — a nested relation + * fetched with .all() on each iteration, causing an N+1 query, unless + * `.eagerly()` is also present in the chain (it sits below the terminal + * `.all()`, e.g. `entry.rel.eagerly().all()`, so methodsInChain($node) sees it). + * + * $node is the terminal (outermost) GetAttr of its chain — see walk(). + */ + private function checkNestedRelationAll(GetAttrExpression $node): void + { + if (! $this->enabled('nestedRelationAll') || $this->loopStack === []) { + return; + } + + if (! TwigNodeHelper::isMethodCall($node) || TwigNodeHelper::attrName($node) !== 'all') { + return; + } + + $methods = TwigNodeHelper::methodsInChain($node); + if (isset($methods['eagerly'])) { + return; + } + + $object = $node->hasNode('node') ? $node->getNode('node') : null; + if (! $object instanceof GetAttrExpression) { + return; + } + + // Walk down through any method calls to the relation access itself. + $relationNode = $object; + while ($relationNode instanceof GetAttrExpression && TwigNodeHelper::isMethodCall($relationNode)) { + $relationNode = $relationNode->hasNode('node') ? $relationNode->getNode('node') : null; + } + if (! $relationNode instanceof GetAttrExpression || ! $relationNode->hasNode('node')) { + return; + } + + $objectName = TwigNodeHelper::nameOf($relationNode->getNode('node')); + $attr = TwigNodeHelper::attrName($relationNode); + if ($objectName === null || $attr === null) { + return; + } + $frame = $this->elementLoopFrame($objectName); + if ($frame === null || ! $this->relations->isRelation($attr)) { + return; + } + + // If the relation is (or may be) eager-loaded, `..all()` is + // served from the eager-loaded cache rather than re-querying, so it is + // not an N+1. null = unknown (e.g. the loop element came from outside + // this template); see resolveEagerLoaded(). + $eager = $frame['eagerLoaded']; + if ($eager === null || $this->isEagerLoaded($eager, $attr)) { + return; + } + + $this->findings[] = new Finding( + 'craftcms.twigNestedRelationAll', + $node->getTemplateLine(), + sprintf('Nested relation "%s" is fetched with .all() inside a loop, causing an N+1 query.', $attr), + sprintf('Use %s.%s.eagerly().all() or eager-load "%s" on the parent query.', $objectName, $attr, $attr), + ); + } + + /** + * Fires once per query (on the chain's outermost node) when that query is + * built and executed inside a loop. The terminal fetch method + * (all/one/count/exists/nth/ids) may sit anywhere in the chain, not just at + * the outermost position — e.g. `craft.entries.section('n').one().title` + * reads a property off the fetch, so the outermost node is `.title`, not + * `.one()`. We therefore scan the whole chain for a terminal fetch method + * rather than requiring $node itself to be one. + * + * $node is the terminal (outermost) GetAttr of its chain — see walk() — + * so this still reports exactly once per chain. + */ + private function checkQueryInLoop(GetAttrExpression $node): void + { + if (! $this->enabled('queryInLoop') || $this->loopStack === []) { + return; + } + + $methods = TwigNodeHelper::methodsInChain($node); + $terminals = array_intersect_key($methods, array_flip(['all', 'one', 'count', 'exists', 'nth', 'ids'])); + if ($terminals === []) { + return; + } + + if (! TwigNodeHelper::isQueryRooted($node)) { + return; + } + + $this->findings[] = new Finding( + 'craftcms.twigQueryInLoop', + $node->getTemplateLine(), + 'An element query is executed inside a loop, running one query per iteration.', + 'Move the query outside the loop and eager-load, or collect IDs and query once.', + ); + } + + /** + * Unbounded `.all()` on an element query outside any loop (in-loop queries + * are checkQueryInLoop's job) with no `.limit()` anywhere in the chain. + * + * $node is the terminal (outermost) GetAttr of its chain — see walk(). + */ + private function checkUnboundedAll(GetAttrExpression $node): void + { + if (! $this->enabled('unboundedAll') || $this->loopStack !== []) { + return; + } + + if (! TwigNodeHelper::isMethodCall($node) || TwigNodeHelper::attrName($node) !== 'all') { + return; + } + + if (! TwigNodeHelper::isQueryRooted($node)) { + return; + } + + $methods = TwigNodeHelper::methodsInChain($node); + if (isset($methods['limit'])) { + return; + } + + $this->findings[] = new Finding( + 'craftcms.twigUnboundedAll', + $node->getTemplateLine(), + 'Unbounded .all() on an element query may load a large result set into memory.', + 'Add .limit(n) if you do not need every element.', + ); + } + + /** + * `|length` applied directly to an element query forces it to fetch every + * row just to count them; `.count()` is the cheaper equivalent. Does not + * return early: the operand's own GetAttr chain still needs to be walked + * by the caller. + */ + private function checkLengthOnQuery(FilterExpression $node): void + { + if (! $this->enabled('lengthOnQuery')) { + return; + } + + if (TwigNodeHelper::filterName($node) !== 'length') { + return; + } + + $operand = $node->hasNode('node') ? $node->getNode('node') : null; + if (! $operand instanceof Node || ! TwigNodeHelper::isQueryRooted($operand)) { + return; + } + + // If .all()/.ids() already executed the query, |length is on an array — fine. + $methods = TwigNodeHelper::methodsInChain($operand); + if (isset($methods['all']) || isset($methods['ids'])) { + return; + } + + $this->findings[] = new Finding( + 'craftcms.twigLengthOnQuery', + $node->getTemplateLine(), + 'Using |length on an element query fetches every element just to count them.', + 'Use .count() instead of |length.', + ); + } + + /** + * The innermost active loop frame whose value variable is $name, provided + * that loop iterates elements (not a plain array/hash literal); null when + * $name is not a loop variable. The innermost match decides so an inner + * loop shadowing $name masks the outer binding: if it iterates a plain + * literal, $name holds plain values here and no element frame is returned. + * + * @return array{var: string, eagerLoaded: array|null, nonElement: bool}|null + */ + private function elementLoopFrame(string $name): ?array + { + for ($i = count($this->loopStack) - 1; $i >= 0; $i--) { + $frame = $this->loopStack[$i]; + if ($frame['var'] === $name) { + return $frame['nonElement'] ? null : $frame; + } + } + + return null; + } + + /** + * Walk the non-spine children of a GetAttr chain (the `attribute` and + * `arguments` of every node in the chain), since those may contain nested + * expressions (e.g. other loops, sub-chains) that still need visiting. The + * `node` spine itself is intentionally not re-walked here — checkChain() + * already scanned it for the N+1 check, and re-walking it would visit the + * same chain's GetAttrs a second time via the general walk() recursion. + */ + private function walkChainSideBranches(GetAttrExpression $node): void + { + $current = $node; + + while ($current instanceof GetAttrExpression) { + if ($current->hasNode('attribute')) { + $this->walk($current->getNode('attribute')); + } + if ($current->hasNode('arguments')) { + $this->walk($current->getNode('arguments')); + } + + $next = $current->hasNode('node') ? $current->getNode('node') : null; + if (! $next instanceof GetAttrExpression) { + // Reached the chain root (not a GetAttr, e.g. a NameExpression): + // walk it normally since nothing else will. + if ($next instanceof Node) { + $this->walk($next); + } + + return; + } + $current = $next; + } + } + + private function recordAssignment(SetNode $node): void + { + if (! $node->hasNode('names') || ! $node->hasNode('values')) { + return; + } + + // `names`/`values` are each a `Nodes` wrapper; the single-target case + // (the common `{% set x = expr %}`) has exactly one child at index 0. + $names = $this->firstChild($node->getNode('names')); + $values = $this->firstChild($node->getNode('values')); + + if ($names === null || $values === null) { + return; + } + + $name = TwigNodeHelper::nameOf($names); + if ($name !== null) { + $this->assignments[$name] = $values; + + if ($this->isPlainExpr($values)) { + $this->plainVars[$name] = true; + } else { + unset($this->plainVars[$name]); + } + } + } + + /** + * A plain (non-element) expression: an array/hash literal, or a bare + * reference to a variable already known to be plain. Query builders and + * relation accesses are GetAttr chains, so they are never plain. + */ + private function isPlainExpr(Node $node): bool + { + if ($node instanceof ArrayExpression) { + return true; + } + + $name = TwigNodeHelper::nameOf($node); + + return $name !== null && isset($this->plainVars[$name]); + } + + private function firstChild(Node $wrapper): ?Node + { + foreach ($wrapper as $child) { + return $child instanceof Node ? $child : null; + } + + return null; + } + + /** + * Pushes a loop frame and returns the loop's value-variable name. + */ + private function enterLoop(ForNode $node): string + { + $valueTarget = $node->getNode('value_target'); + $varName = $valueTarget->hasAttribute('name') ? (string) $valueTarget->getAttribute('name') : ''; + + $source = $node->getNode('seq'); + $resolved = $this->resolveSource($source); + + $this->loopStack[] = [ + 'var' => $varName, + 'eagerLoaded' => $this->resolveEagerLoaded($resolved), + 'nonElement' => $this->isPlainExpr($resolved), + ]; + + return $varName; + } + + /** + * If the loop source is a bare variable assigned one level back, use that + * expression; otherwise use the source expression as-is. Fallback wrappers + * (`query ?? []`, `query ?: []`) are unwrapped to the query on both the + * direct source and the resolved assignment. + */ + private function resolveSource(Node $source): Node + { + $source = $this->unwrapFallback($source); + + $name = TwigNodeHelper::nameOf($source); + if ($name !== null && isset($this->assignments[$name])) { + return $this->unwrapFallback($this->assignments[$name]); + } + + return $source; + } + + /** + * Unwrap a `query ?? default` / `query ?: default` fallback to the query + * side, so the eager-loading on the query is visible. Without this the query + * is buried in the fallback node and every relation access on the loop items + * is misreported — the exact false positive behind the ubiquitous + * `craft.…all() ?? []` navigation idiom. + * + * The AST shape differs across Twig versions: + * - Twig ≥3.16 parses `a ?? b` to a NullCoalesceBinary (`left` = the query); + * - `a ?: b` (and `a ?? b` on older Twig) is a ConditionalExpression whose + * `expr2` holds the value used when the subject is present — the query. + */ + private function unwrapFallback(Node $source): Node + { + if ($source instanceof NullCoalesceBinary && $source->hasNode('left')) { + return $source->getNode('left'); + } + + if ($source instanceof ConditionalExpression && $source->hasNode('expr2')) { + return $source->getNode('expr2'); + } + + return $source; + } + + /** + * The eager-load set for a loop source, or null ("unknown") when the source + * cannot be traced to something visible in THIS template. + * + * PHPStan analyses each template in isolation, so a partial that receives an + * already-eager-loaded element across an {% include %}/{% embed %} boundary + * (e.g. navigation/node.twig iterating `node.children`, where `nodes` was + * fetched with `.with(['children.children'])` in the parent layout) has no + * way to see that eager-loading. Assuming "nothing eager-loaded" for such an + * externally-supplied variable is exactly what produced N+1 false positives. + * + * We only trust an *empty* eager-load set when we can actually read the + * query's chain: a `craft.*` global (covers `craft.entries()…` and plugin + * queries such as `craft.navigation.nodes()…`), a builder recognised by + * isQueryRooted (`.find()`/`.relatedTo()`), a `{% set %}` variable, or an + * element of an enclosing loop whose own source was known. Otherwise the + * state is unknown → null, which the N+1 checks treat as + * possibly-eager-loaded and suppress (the same sentinel a dynamic + * `with(...)` yields). + * + * @return array|null + */ + private function resolveEagerLoaded(Node $source): ?array + { + // A plain array/hash literal (or a var known to hold one): no relations. + if ($this->isPlainExpr($source)) { + return []; + } + + $root = TwigNodeHelper::rootName($source); + + // A chain whose query we can read directly — rooted at the `craft` + // global, or a recognised builder. A missing `.with()` here genuinely + // means no eager-loading. + if ($root === 'craft' || TwigNodeHelper::isQueryRooted($source)) { + return TwigNodeHelper::eagerLoadedRelations($source); + } + + if ($root === null) { + // No identifiable root variable (unusual) → keep the conservative reading. + return TwigNodeHelper::eagerLoadedRelations($source); + } + + // Rooted at an element of an enclosing loop: if that loop's own eager + // state was unknown, so is this one (propagate across nested loops such + // as `{% for child in node.children %}` under an external `nodes`). + // Otherwise descend the enclosing loop's eager-load paths through the + // relation(s) accessed here, so a deep path like + // `with(['children.children.children'])` keeps covering each nesting + // level (`node.children` → the children collection is still eager-loaded + // for `children.children`), while relations beyond the path's depth + // remain flagged. An explicit `.with()` on this source overrides the + // inherited state. + foreach ($this->loopStack as $frame) { + if ($frame['var'] === $root) { + if ($frame['eagerLoaded'] === null) { + return null; + } + + if (isset(TwigNodeHelper::methodsInChain($source)['with'])) { + return TwigNodeHelper::eagerLoadedRelations($source); + } + + return $this->descendEagerPaths( + $frame['eagerLoaded'], + $this->relationSegments($source), + ); + } + } + + // Rooted at a variable assigned locally via {% set %}: visible here. + if (isset($this->assignments[$root])) { + return TwigNodeHelper::eagerLoadedRelations($source); + } + + // Rooted at a variable supplied from outside this template (include + // variable, embed context, or global). Its eager-load state is + // unknowable here → unknown rather than "none". + return null; + } + + /** + * Whether relation $attr is covered by the eager-load set. Handles nested + * paths: `with(['children.children'])` eager-loads `children` (the head + * segment) as well as its `children`, so accessing `children` on the loop + * items is served from cache. A path matches when $attr is exactly the path + * or its first dotted segment. + * + * @param array $eager + */ + private function isEagerLoaded(array $eager, string $attr): bool + { + foreach (array_keys($eager) as $path) { + if ($path === $attr || str_starts_with($path, $attr.'.')) { + return true; + } + } + + return false; + } + + /** + * The relation segments accessed on a chain rooted at a loop variable, in + * root→outer order: `node.children` → ['children'], `node.parent.children` + * → ['parent', 'children']. Method calls (`.all()`, `.eagerly()`) are not + * segments and are skipped. + * + * @return list + */ + private function relationSegments(Node $source): array + { + $segments = []; + $current = $source; + + while ($current instanceof GetAttrExpression) { + if (! TwigNodeHelper::isMethodCall($current)) { + $attr = TwigNodeHelper::attrName($current); + if ($attr !== null) { + $segments[] = $attr; + } + } + $current = $current->hasNode('node') ? $current->getNode('node') : null; + } + + return array_reverse($segments); + } + + /** + * Descend an eager-load path set through the given relation segments, + * returning the eager state of the collection reached. For each segment, + * keep only paths whose head matches it and strip that head; a path with no + * remaining tail contributed no deeper eager-loading. Example: descending + * {'children.children.children'} through ['children'] yields + * {'children.children'}; descending {'children'} through ['children'] + * yields {} (nothing deeper is eager-loaded, so the next level flags). + * + * @param array $eager + * @param list $segments + * @return array + */ + private function descendEagerPaths(array $eager, array $segments): array + { + $set = $eager; + + foreach ($segments as $segment) { + $next = []; + foreach (array_keys($set) as $path) { + $parts = explode('.', $path); + if ($parts[0] === $segment && count($parts) > 1) { + $next[implode('.', array_slice($parts, 1))] = true; + } + } + $set = $next; + } + + return $set; + } +} diff --git a/src/Twig/TwigTemplateCacheMetaExtension.php b/src/Twig/TwigTemplateCacheMetaExtension.php new file mode 100644 index 0000000..fbe1755 --- /dev/null +++ b/src/Twig/TwigTemplateCacheMetaExtension.php @@ -0,0 +1,52 @@ +scanner->templateFiles() as $path) { + $contents = @file_get_contents($path); + // Fold path + content into the digest so edits, additions and + // removals all shift the hash. Unreadable files contribute their + // path only, so a permission flip is still observed. + $parts[] = $path.':'.($contents === false ? '' : hash('xxh128', $contents)); + } + + return hash('xxh128', implode("\n", $parts)); + } +} diff --git a/src/Twig/TwigTemplateParser.php b/src/Twig/TwigTemplateParser.php new file mode 100644 index 0000000..4b62a7c --- /dev/null +++ b/src/Twig/TwigTemplateParser.php @@ -0,0 +1,65 @@ +twig = new Environment(new ArrayLoader, [ + 'cache' => false, + 'autoescape' => false, + 'strict_variables' => false, + 'optimizations' => 0, + ]); + + // Any tag we do not model becomes an inert node. + $this->twig->registerUndefinedTokenParserCallback( + static fn (string $name): GenericTagTokenParser => new GenericTagTokenParser($name), + ); + + // Any unknown function/filter resolves to a no-op so parsing succeeds. + $this->twig->registerUndefinedFunctionCallback( + static fn (string $name): TwigFunction => new TwigFunction($name, static fn (): string => ''), + ); + $this->twig->registerUndefinedFilterCallback( + static fn (string $name): TwigFilter => new TwigFilter($name, static fn ($v) => $v), + ); + } + + public function parseFile(string $path): ?ModuleNode + { + $code = @file_get_contents($path); + if ($code === false) { + return null; + } + + return $this->parseSource($code, $path); + } + + public function parseSource(string $code, string $name = 'template'): ?ModuleNode + { + try { + return $this->twig->parse($this->twig->tokenize(new Source($code, $name))); + } catch (Throwable) { + return null; + } + } +} diff --git a/src/Twig/TwigTemplateScanner.php b/src/Twig/TwigTemplateScanner.php new file mode 100644 index 0000000..8672e97 --- /dev/null +++ b/src/Twig/TwigTemplateScanner.php @@ -0,0 +1,126 @@ + */ + private readonly array $templatePaths; + + /** @var list */ + private readonly array $excludeDirectories; + + /** + * The action-input and performance configs are separate parameters that + * usually — but need not — point at the same directories. Both lists are + * merged and de-duplicated here so the tree is walked once and every + * consumer sees every configured directory. + * + * @param list $actionInputPaths + * @param list $performancePaths + * @param list $excludeDirectories Directory names (not paths) + * whose subtrees are skipped, e.g. `vendor`, `node_modules`. + * Prunes third-party templates a package bundles under + * `vendor/` (Craft's own CP templates, other plugins' assets) + * when a template path points at a directory containing them. + */ + public function __construct( + private readonly TwigTemplateParser $parser, + array $actionInputPaths, + array $performancePaths, + array $excludeDirectories = [], + ) { + $merged = []; + foreach ([...$actionInputPaths, ...$performancePaths] as $path) { + $merged[$path] = true; + } + + $this->templatePaths = array_keys($merged); + $this->excludeDirectories = array_values($excludeDirectories); + } + + /** + * Absolute, de-duplicated realpaths of every `.twig` file under the + * configured template directories, sorted for a stable order. + * + * @return list + */ + public function templateFiles(): array + { + $paths = []; + + foreach ($this->templatePaths as $templatePath) { + if (! is_dir($templatePath)) { + continue; + } + + $directory = new RecursiveDirectoryIterator($templatePath, RecursiveDirectoryIterator::SKIP_DOTS); + + // Prune excluded directories during descent so their subtrees are + // never entered — cheaper than filtering matched files afterwards. + $filtered = new RecursiveCallbackFilterIterator( + $directory, + function (SplFileInfo $current): bool { + if ($current->isDir()) { + return ! in_array($current->getFilename(), $this->excludeDirectories, true); + } + + return true; + }, + ); + + $iterator = new RecursiveIteratorIterator($filtered); + + /** @var SplFileInfo $file */ + foreach ($iterator as $file) { + if ($file->getExtension() !== 'twig') { + continue; + } + + $realPath = $file->getRealPath(); + if ($realPath === false) { + continue; + } + + $paths[$realPath] = true; + } + } + + $files = array_keys($paths); + sort($files); + + return $files; + } + + /** + * Every discovered template as a lazily-readable {@see ScannedTemplate}. + * + * @return Generator + */ + public function scan(): Generator + { + foreach ($this->templateFiles() as $path) { + yield new ScannedTemplate($path, $this->parser); + } + } +} diff --git a/tests/Collector/AnalysisMarkerCollectorTest.php b/tests/Collector/AnalysisMarkerCollectorTest.php new file mode 100644 index 0000000..2a76186 --- /dev/null +++ b/tests/Collector/AnalysisMarkerCollectorTest.php @@ -0,0 +1,30 @@ +getNodeType()); + } + + public function test_emits_a_marker_for_every_file(): void + { + $collector = new AnalysisMarkerCollector; + + // Scope is never touched by this collector, so a real FileNode over an + // empty statement list is enough to prove it always emits (non-null), + // which is what keeps CollectedDataNode rules reachable. + $result = $collector->processNode(new FileNode([]), $this->createStub(\PHPStan\Analyser\Scope::class)); + + self::assertNotNull($result); + self::assertTrue($result); + } +} diff --git a/tests/Helper/RelationFieldRegistryTest.php b/tests/Helper/RelationFieldRegistryTest.php new file mode 100644 index 0000000..f9de46a --- /dev/null +++ b/tests/Helper/RelationFieldRegistryTest.php @@ -0,0 +1,42 @@ +registry()->isRelation('relatedEntries')); + self::assertTrue($this->registry()->isRelation('heroImage')); + } + + public function test_non_relational_fields_are_not_detected(): void + { + self::assertFalse($this->registry()->isRelation('summary')); + self::assertFalse($this->registry()->isRelation('title')); // native, non-relational + } + + public function test_built_in_relation_accessors_are_detected(): void + { + self::assertTrue($this->registry()->isRelation('author')); + self::assertTrue($this->registry()->isRelation('children')); + self::assertTrue($this->registry()->isRelation('parent')); + } + + public function test_falls_back_to_built_ins_when_config_missing(): void + { + $registry = new RelationFieldRegistry('/does/not/exist'); + self::assertTrue($registry->isRelation('author')); + self::assertFalse($registry->isRelation('relatedEntries')); + } +} diff --git a/tests/Rule/TwigPerformanceRuleTest.php b/tests/Rule/TwigPerformanceRuleTest.php new file mode 100644 index 0000000..e7352c2 --- /dev/null +++ b/tests/Rule/TwigPerformanceRuleTest.php @@ -0,0 +1,47 @@ + true, + 'nestedRelationAll' => true, + 'queryInLoop' => true, + 'lengthOnQuery' => true, + 'unboundedAll' => false, + ]); + + $scanner = new TwigTemplateScanner( + new TwigTemplateParser, + [__DIR__.'/../fixtures/templates'], + [], + ); + + return new TwigPerformanceRule($scanner, $analyzer, $enabled); + } + + public function test_reports_n_plus_one_in_template_tree(): void + { + $errors = $this->rule()->scanTemplates(); + $identifiers = array_map(static fn ($e) => $e->getIdentifier(), $errors); + self::assertContains('craftcms.twigNPlusOne', $identifiers); + } + + public function test_no_errors_when_disabled(): void + { + self::assertSame([], $this->rule(enabled: false)->scanTemplates()); + } +} diff --git a/tests/Twig/TwigPerformanceAnalyzerChecksTest.php b/tests/Twig/TwigPerformanceAnalyzerChecksTest.php new file mode 100644 index 0000000..19312ac --- /dev/null +++ b/tests/Twig/TwigPerformanceAnalyzerChecksTest.php @@ -0,0 +1,216 @@ + true, + 'nestedRelationAll' => true, + 'queryInLoop' => true, + 'lengthOnQuery' => true, + 'unboundedAll' => true, + ]; + + /** + * @param array $checks + * @return list + */ + private function ids(string $code, array $checks = self::ALL_CHECKS): array + { + $module = (new TwigTemplateParser)->parseSource($code); + self::assertNotNull($module); + $registry = new RelationFieldRegistry(__DIR__.'/../fixtures/projectConfig'); + $findings = (new TwigPerformanceAnalyzer($registry, $checks))->analyze($module); + + return array_map(static fn (Finding $f): string => $f->identifier, $findings); + } + + public function test_nested_relation_all_in_loop(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.all() %} + {% for cat in entry.relatedEntries.all() %}{{ cat.title }}{% endfor %} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigNestedRelationAll', $this->ids($code)); + } + + public function test_nested_relation_all_suppressed_by_eagerly(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.all() %} + {% for cat in entry.relatedEntries.eagerly().all() %}{{ cat.title }}{% endfor %} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNestedRelationAll', $this->ids($code)); + } + + public function test_query_built_in_loop(): void + { + $code = <<<'TWIG' + {% for id in ids %} + {% set e = craft.entries.id(id).one() %}{{ e.title }} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigQueryInLoop', $this->ids($code)); + } + + public function test_length_on_query(): void + { + $code = '{{ craft.entries.section("news")|length }}'; + self::assertContains('craftcms.twigLengthOnQuery', $this->ids($code)); + } + + public function test_length_on_plain_array_not_flagged(): void + { + $code = '{% set xs = [1, 2, 3] %}{{ xs|length }}'; + self::assertNotContains('craftcms.twigLengthOnQuery', $this->ids($code)); + } + + public function test_unbounded_all_flagged_when_enabled(): void + { + $code = '{% set entries = craft.entries.section("news").all() %}'; + self::assertContains('craftcms.twigUnboundedAll', $this->ids($code)); + } + + public function test_unbounded_all_silent_when_disabled(): void + { + $code = '{% set entries = craft.entries.section("news").all() %}'; + self::assertNotContains('craftcms.twigUnboundedAll', $this->ids($code, ['unboundedAll' => false])); + } + + public function test_unbounded_all_not_flagged_with_limit(): void + { + $code = '{% set entries = craft.entries.limit(10).all() %}'; + self::assertNotContains('craftcms.twigUnboundedAll', $this->ids($code)); + } + + public function test_top_level_loop_source_query_not_flagged_as_query_in_loop(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.section("news").all() %}{{ entry.title }}{% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigQueryInLoop', $this->ids($code, [ + 'queryInLoop' => true, + 'unboundedAll' => false, + ])); + } + + public function test_nested_loop_source_query_flagged_as_query_in_loop(): void + { + $code = <<<'TWIG' + {% for entry in entries %} + {% for asset in craft.assets.volume("x").all() %}{{ asset.title }}{% endfor %} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigQueryInLoop', $this->ids($code, [ + 'queryInLoop' => true, + 'unboundedAll' => false, + ])); + } + + public function test_query_in_for_else_branch_not_flagged(): void + { + // The {% else %} branch runs at most once (when the sequence is empty), + // so a query there is not a per-iteration query. + $code = <<<'TWIG' + {% for entry in entries %} + {{ entry.title }} + {% else %} + {{ craft.entries.section("fallback").one().title }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigQueryInLoop', $this->ids($code)); + } + + public function test_query_in_loop_fires_on_property_off_fetch(): void + { + $code = <<<'TWIG' + {% for x in xs %}{{ craft.entries.section("n").one().title }}{% endfor %} + TWIG; + + self::assertContains('craftcms.twigQueryInLoop', $this->ids($code)); + } + + public function test_query_in_loop_fires_exactly_once_on_property_off_fetch(): void + { + $code = <<<'TWIG' + {% for x in xs %}{{ craft.entries.section("n").one().title }}{% endfor %} + TWIG; + + $ids = $this->ids($code); + $count = count(array_filter($ids, static fn (string $id): bool => $id === 'craftcms.twigQueryInLoop')); + + self::assertSame(1, $count); + } + + public function test_query_in_loop_not_fired_on_relation_chain(): void + { + $code = <<<'TWIG' + {% for entry in entries %}{{ entry.relatedEntries.all() }}{% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigQueryInLoop', $this->ids($code)); + } + + public function test_relation_named_key_on_hash_literal_loop_not_flagged(): void + { + // The loop iterates a static hash literal, so `item` is a plain hash and + // `item.heroImage` reads a map key, not a Craft relation — no N+1. + $code = <<<'TWIG' + {% set items = { a: { heroImage: 'a.jpg' }, b: { heroImage: 'b.jpg' } } %} + {% for item in items %}{{ item.heroImage }}{% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->ids($code)); + } + + public function test_plainness_propagates_through_nested_literal_loops(): void + { + // Mirrors templates/_parts/font-preloading.twig: a hash of arrays of + // hashes. The inner value must still be recognised as plain. + $code = <<<'TWIG' + {% set groups = { g1: [ { heroImage: 'a.jpg' } ], g2: [ { heroImage: 'b.jpg' } ] } %} + {% for name, group in groups %} + {% for item in group %}{{ item.heroImage }}{% endfor %} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->ids($code)); + } + + public function test_relation_on_element_query_loop_still_flagged(): void + { + // Guard against over-suppression: a genuine element loop is unaffected. + $code = <<<'TWIG' + {% for entry in craft.entries.all() %}{{ entry.heroImage }}{% endfor %} + TWIG; + + self::assertContains('craftcms.twigNPlusOne', $this->ids($code)); + } + + public function test_nested_relation_all_on_hash_literal_loop_not_flagged(): void + { + $code = <<<'TWIG' + {% set items = [ { relatedEntries: 'x' } ] %} + {% for item in items %}{{ item.relatedEntries.all() }}{% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNestedRelationAll', $this->ids($code)); + } +} diff --git a/tests/Twig/TwigPerformanceAnalyzerTest.php b/tests/Twig/TwigPerformanceAnalyzerTest.php new file mode 100644 index 0000000..1d6f707 --- /dev/null +++ b/tests/Twig/TwigPerformanceAnalyzerTest.php @@ -0,0 +1,261 @@ + $checks + * @return list + */ + private function analyze(string $code, array $checks = ['nPlusOne' => true]): array + { + $module = (new TwigTemplateParser)->parseSource($code); + self::assertNotNull($module); + + $registry = new RelationFieldRegistry(__DIR__.'/../fixtures/projectConfig'); + + return (new TwigPerformanceAnalyzer($registry, $checks))->analyze($module); + } + + /** + * @param list $findings + */ + private function identifiers(array $findings): array + { + return array_map(static fn (Finding $f): string => $f->identifier, $findings); + } + + public function test_flags_relational_access_in_loop(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.section('news').all() %} + {{ entry.author.fullName }} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_when_eager_loaded_with_with(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.section('news').with(['author']).all() %} + {{ entry.author.fullName }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_when_access_uses_eagerly(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.all() %} + {{ entry.author.eagerly().one().fullName }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_when_with_args_are_dynamic(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.with(eagerFields).all() %} + {{ entry.author.fullName }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_non_relational_access(): void + { + $code = <<<'TWIG' + {% for entry in craft.entries.all() %} + {{ entry.summary }}{{ entry.title }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_resolves_loop_source_from_set_one_level_back(): void + { + $code = <<<'TWIG' + {% set entries = craft.entries.all() %} + {% for entry in entries %} + {{ entry.author.fullName }} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_relation_off_external_variable_chain(): void + { + // A partial (e.g. navigation/node.twig) receives an element that was + // eager-loaded in a parent template and passed across an {% include %}. + // `node` is undefined in this template, so its eager-load state is + // unknowable here and must not be assumed absent. + $code = <<<'TWIG' + {% for child in node.children %} + {{ child.children | length }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_relation_off_external_bare_variable(): void + { + // `entries` is supplied from outside this template (include var/global); + // we cannot see whether the upstream query eager-loaded `author`. + $code = <<<'TWIG' + {% for entry in entries %} + {{ entry.author.fullName }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_eager_loaded_relation_when_source_has_fallback(): void + { + // The `... .all() ?? []` idiom must not hide the query: `children` IS + // eager-loaded here (footer/careers navigation pattern), so accessing it + // on the loop items is not an N+1. + $code = <<<'TWIG' + {% set nodes = craft.navigation.nodes().handle('main').with(['children']).all() ?? [] %} + {% for node in nodes %} + {{ node.children | length }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_still_flags_deeper_relation_not_eager_loaded_behind_fallback(): void + { + // Only `children` (level 2) is eager-loaded; `child.children` (level 3) + // is a genuine N+1 and must still fire even through the `?? []` fallback. + $code = <<<'TWIG' + {% set nodes = craft.navigation.nodes().handle('main').with(['children']).all() ?? [] %} + {% for node in nodes %} + {% for child in node.children %} + {{ child.children | length }} + {% endfor %} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_still_flags_nested_relation_when_source_is_visible_query(): void + { + // The outer collection comes from a query we can see, so a nested + // relation that is not eager-loaded is a genuine N+1 and must still fire. + $code = <<<'TWIG' + {% for entry in craft.entries.all() %} + {% for related in entry.relatedEntries %} + {{ related.author.fullName }} + {% endfor %} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_flags_relation_on_outer_loop_variable_inside_nested_loop(): void + { + // `entry.author` runs once per `entry` iteration even though the access + // sits in an inner loop over a different variable — still an N+1. + $code = <<<'TWIG' + {% for entry in craft.entries.all() %} + {% for size in [1, 2, 3] %} + {{ entry.author.fullName }} + {% endfor %} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_inner_literal_loop_shadowing_the_variable_masks_the_outer_loop(): void + { + // The inner loop rebinds `entry` to plain hash values, so `entry.author` + // here reads a map key of the shadowing binding — not the outer element. + $code = <<<'TWIG' + {% for entry in craft.entries.all() %} + {% for entry in [{ author: 'jane' }] %} + {{ entry.author }} + {% endfor %} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_first_segment_of_nested_eager_path(): void + { + // `with(['children.children'])` eager-loads the top-level `children` + // relation (and its `children`), so accessing `node.children` on the + // loop items is served from the eager-load cache — not an N+1. + $code = <<<'TWIG' + {% set nodes = craft.entries.with(['children.children']).all() %} + {% for node in nodes %} + {{ node.children | length }} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_does_not_flag_nested_relations_covered_by_deep_eager_path(): void + { + // The navigation menu pattern: a single deep eager-load path covers + // every level, so `children` accessed at each nesting depth is served + // from the eager-load cache. None of these are N+1s. + $code = <<<'TWIG' + {% set nodes = craft.navigation.nodes('main').with(['children.children.children']).all() %} + {% for node in nodes %} + {% set childNodes = node.children ?? [] %} + {% for subNode in childNodes %} + {% set childNodes = subNode.children ?? [] %} + {% for innerNode in childNodes %} + {{ innerNode.children | length }} + {% endfor %} + {% endfor %} + {% endfor %} + TWIG; + + self::assertNotContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } + + public function test_still_flags_relation_beyond_nested_eager_path_depth(): void + { + // `with(['children.children'])` covers two levels; the third-level + // `subNode.children` access is a genuine N+1 and must still fire. + $code = <<<'TWIG' + {% set nodes = craft.entries.with(['children.children']).all() %} + {% for node in nodes %} + {% for child in node.children %} + {% for subNode in child.children %} + {{ subNode.children | length }} + {% endfor %} + {% endfor %} + {% endfor %} + TWIG; + + self::assertContains('craftcms.twigNPlusOne', $this->identifiers($this->analyze($code))); + } +} diff --git a/tests/Twig/TwigTemplateCacheMetaExtensionTest.php b/tests/Twig/TwigTemplateCacheMetaExtensionTest.php new file mode 100644 index 0000000..5cc2831 --- /dev/null +++ b/tests/Twig/TwigTemplateCacheMetaExtensionTest.php @@ -0,0 +1,83 @@ +dir = sys_get_temp_dir().'/'.uniqid('twig_meta_', true); + mkdir($this->dir); + } + + protected function tearDown(): void + { + foreach (glob($this->dir.'/*') ?: [] as $file) { + unlink($file); + } + @rmdir($this->dir); + } + + private function extension(): TwigTemplateCacheMetaExtension + { + $scanner = new TwigTemplateScanner(new TwigTemplateParser, [$this->dir], []); + + return new TwigTemplateCacheMetaExtension($scanner); + } + + public function test_key_is_stable(): void + { + self::assertSame('craftTwigTemplates', $this->extension()->getKey()); + } + + public function test_hash_is_deterministic_for_unchanged_tree(): void + { + file_put_contents($this->dir.'/a.twig', '{{ foo }}'); + + self::assertSame($this->extension()->getHash(), $this->extension()->getHash()); + } + + public function test_hash_changes_when_template_content_changes(): void + { + $path = $this->dir.'/a.twig'; + file_put_contents($path, '{{ foo }}'); + $before = $this->extension()->getHash(); + + file_put_contents($path, '{{ bar }}'); + $after = $this->extension()->getHash(); + + self::assertNotSame($before, $after); + } + + public function test_hash_changes_when_template_is_added(): void + { + file_put_contents($this->dir.'/a.twig', '{{ foo }}'); + $before = $this->extension()->getHash(); + + file_put_contents($this->dir.'/b.twig', '{{ foo }}'); + $after = $this->extension()->getHash(); + + self::assertNotSame($before, $after); + } + + public function test_hash_changes_when_template_is_removed(): void + { + file_put_contents($this->dir.'/a.twig', '{{ foo }}'); + file_put_contents($this->dir.'/b.twig', '{{ foo }}'); + $before = $this->extension()->getHash(); + + unlink($this->dir.'/b.twig'); + $after = $this->extension()->getHash(); + + self::assertNotSame($before, $after); + } +} diff --git a/tests/Twig/TwigTemplateParserTest.php b/tests/Twig/TwigTemplateParserTest.php new file mode 100644 index 0000000..8e548c6 --- /dev/null +++ b/tests/Twig/TwigTemplateParserTest.php @@ -0,0 +1,74 @@ +parser = new TwigTemplateParser; + } + + public function test_parses_plain_template(): void + { + $module = $this->parser->parseSource('{{ entry.title }}'); + self::assertInstanceOf(ModuleNode::class, $module); + } + + public function test_parses_craft_custom_tags_without_error(): void + { + $code = <<<'TWIG' + {% cache %} + {% nav node in nodes %} + {{ node.title }} + {% endnav %} + {% switch entry.type %} + {% case "news" %}news{% endcase %} + {% endswitch %} + {% exit 404 %} + {% endcache %} + TWIG; + + self::assertInstanceOf(ModuleNode::class, $this->parser->parseSource($code)); + } + + public function test_parses_unknown_functions_and_filters(): void + { + $code = '{{ getCsrfInput() }}{{ entry.body|markdown|t }}'; + self::assertInstanceOf(ModuleNode::class, $this->parser->parseSource($code)); + } + + public function test_returns_null_on_broken_template(): void + { + // Unterminated block — unrecoverable even for a permissive parser. + self::assertNull($this->parser->parseSource('{% for x in y %}')); + } + + public function test_parses_file_from_disk(): void + { + // Create a temporary file with Twig content. + $tempPath = sys_get_temp_dir().'/'.uniqid('twig_test_', true).'.twig'; + file_put_contents($tempPath, '{{ entry.title }}'); + + try { + $module = $this->parser->parseFile($tempPath); + self::assertInstanceOf(ModuleNode::class, $module); + } finally { + unlink($tempPath); + } + } + + public function test_returns_null_for_missing_file(): void + { + $module = $this->parser->parseFile('/does/not/exist/nope.twig'); + self::assertNull($module); + } +} diff --git a/tests/Twig/TwigTemplateScannerTest.php b/tests/Twig/TwigTemplateScannerTest.php new file mode 100644 index 0000000..bb87740 --- /dev/null +++ b/tests/Twig/TwigTemplateScannerTest.php @@ -0,0 +1,89 @@ +scanner([self::FIXTURES])->templateFiles(); + + $basenames = array_map('basename', $files); + self::assertContains('clean.twig', $basenames); + self::assertContains('nplusone.twig', $basenames); + } + + public function test_prunes_excluded_directories(): void + { + $basenames = array_map('basename', $this->scanner([self::FIXTURES], [], ['vendor'])->templateFiles()); + + self::assertNotContains('bundled.twig', $basenames); + self::assertContains('clean.twig', $basenames); + } + + public function test_excluded_directories_are_scanned_when_not_configured(): void + { + $basenames = array_map('basename', $this->scanner([self::FIXTURES])->templateFiles()); + + self::assertContains('bundled.twig', $basenames); + } + + public function test_returns_stable_sorted_order(): void + { + $files = $this->scanner([self::FIXTURES])->templateFiles(); + + $sorted = $files; + sort($sorted); + self::assertSame($sorted, $files); + } + + public function test_merges_and_deduplicates_both_path_lists(): void + { + // Same directory in both lists must not yield duplicate entries. + $files = $this->scanner([self::FIXTURES], [self::FIXTURES])->templateFiles(); + + self::assertSame(array_values(array_unique($files)), $files); + } + + public function test_covers_directories_from_both_configs(): void + { + // A directory configured only for performance must still be scanned. + $files = $this->scanner([], [self::FIXTURES])->templateFiles(); + + self::assertNotSame([], $files); + } + + public function test_ignores_missing_directories(): void + { + $files = $this->scanner(['/does/not/exist'])->templateFiles(); + + self::assertSame([], $files); + } + + public function test_scan_yields_lazily_readable_templates(): void + { + $templates = iterator_to_array($this->scanner([self::FIXTURES])->scan()); + + self::assertNotEmpty($templates); + self::assertContainsOnlyInstancesOf(ScannedTemplate::class, $templates); + + $first = $templates[0]; + self::assertIsString($first->contents()); + self::assertInstanceOf(ModuleNode::class, $first->module()); + } +} diff --git a/tests/fixtures/projectConfig/fields/heroImage.yaml b/tests/fixtures/projectConfig/fields/heroImage.yaml new file mode 100644 index 0000000..0ba1bc7 --- /dev/null +++ b/tests/fixtures/projectConfig/fields/heroImage.yaml @@ -0,0 +1,2 @@ +handle: heroImage +type: craft\fields\Assets diff --git a/tests/fixtures/projectConfig/fields/relatedEntries.yaml b/tests/fixtures/projectConfig/fields/relatedEntries.yaml new file mode 100644 index 0000000..c2cf241 --- /dev/null +++ b/tests/fixtures/projectConfig/fields/relatedEntries.yaml @@ -0,0 +1,2 @@ +handle: relatedEntries +type: craft\fields\Entries diff --git a/tests/fixtures/projectConfig/fields/summary.yaml b/tests/fixtures/projectConfig/fields/summary.yaml new file mode 100644 index 0000000..48f8356 --- /dev/null +++ b/tests/fixtures/projectConfig/fields/summary.yaml @@ -0,0 +1,2 @@ +handle: summary +type: craft\fields\PlainText diff --git a/tests/fixtures/templates/clean.twig b/tests/fixtures/templates/clean.twig new file mode 100644 index 0000000..507091e --- /dev/null +++ b/tests/fixtures/templates/clean.twig @@ -0,0 +1,3 @@ +{% for entry in craft.entries.section('news').with(['author']).all() %} + {{ entry.author.fullName }} +{% endfor %} diff --git a/tests/fixtures/templates/nplusone.twig b/tests/fixtures/templates/nplusone.twig new file mode 100644 index 0000000..6dc5a72 --- /dev/null +++ b/tests/fixtures/templates/nplusone.twig @@ -0,0 +1,3 @@ +{% for entry in craft.entries.section('news').all() %} + {{ entry.author.fullName }} +{% endfor %} diff --git a/tests/fixtures/templates/vendor/bundled.twig b/tests/fixtures/templates/vendor/bundled.twig new file mode 100644 index 0000000..2618abd --- /dev/null +++ b/tests/fixtures/templates/vendor/bundled.twig @@ -0,0 +1,2 @@ +{# A third-party template that lives under vendor/ and must be excludable. #} +{% for entry in craft.entries.all() %}{{ entry.author.name }}{% endfor %}