diff --git a/.env.dist b/.env similarity index 100% rename from .env.dist rename to .env diff --git a/.gitignore b/.gitignore index 0c229e67c..3c55cd215 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ /config/table_map.yml /config/parameters.yml -/config/request_blacklist.yml +/config/request_denylist.yml /build/ -/phpunit.xml /var/* !/var/cache /var/cache/* @@ -13,10 +12,11 @@ !/var/sessions /var/sessions/* !var/sessions/.gitkeep -/node_modules/ ###> symfony/framework-bundle ### -/.env +/.env.local +/.env.local.php +/.env.*.local /public/bundles/ /var/ /vendor/ @@ -30,4 +30,21 @@ i18n_helper.js phpDocumentor.phar coverage.xml .web-server-pid + +###> squizlabs/php_codesniffer ### +/.phpcs-cache +/phpcs.xml +###< squizlabs/php_codesniffer ### + +###> symfony/phpunit-bridge ### +.phpunit .phpunit.result.cache +/phpunit.xml +###< symfony/phpunit-bridge ### + +###> symfony/webpack-encore-bundle ### +/node_modules/ +/public/build/ +npm-debug.log +yarn-error.log +###< symfony/webpack-encore-bundle ### diff --git a/composer.json b/composer.json index d90eca12d..1cde60537 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "x-tools/xtools", - "description": "A suite of tools to analyze page, user and project data of MediaWiki website", + "description": "A suite of tools to analyze page, user and project data of MediaWiki sites", "license": "GPL-3.0-or-later", "type": "project", "autoload": { @@ -18,7 +18,8 @@ "php": "7.4" }, "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true + "dealerdirect/phpcodesniffer-composer-installer": true, + "symfony/flex": true } }, "require": { @@ -27,7 +28,6 @@ "ext-intl": "*", "ext-json": "*", "ext-PDO": "*", - "symfony/symfony": "^4.4", "twig/twig": "^3.0", "doctrine/orm": "^2.5", "doctrine/doctrine-bundle": "^2.2", @@ -47,15 +47,19 @@ "doctrine/common": "^3.1", "wikimedia/ip-utils": "^1.0", "symfony/mailer": "^4.4", - "symfony/web-profiler-bundle": "^4.4" + "symfony/web-profiler-bundle": "^4.4", + "symfony/flex": "^1.19", + "symfony/dotenv": "^4.4", + "symfony/yaml": "^4.4", + "symfony/security-csrf": "^4.4", + "symfony/css-selector": "^4.4" }, "require-dev": { - "phpunit/phpunit": "^9.0", "symfony/phpunit-bridge": "^4.4", "squizlabs/php_codesniffer": "^3.3.0", "mediawiki/minus-x": "^0.3.2", - "symfony/web-server-bundle": "^4.4", - "dms/phpunit-arraysubset-asserts": "^0.4.0" + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "symfony/browser-kit": "^4.4" }, "scripts": { "test": [ @@ -66,7 +70,14 @@ "fix": [ "./vendor/bin/phpcbf .", "./vendor/bin/minus-x fix ." - ] + ], + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" + } + }, + "conflict": { + "symfony/symfony": "*" }, "extra": { "symfony-app-dir": "app", diff --git a/composer.lock b/composer.lock index 6fbec326b..1c5549543 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": "cb07d9115d1c84c7807a3aabdbd7a1ca", + "content-hash": "2047cd1264e3f97bd8755b9ec4759d25", "packages": [ { "name": "composer/package-versions-deprecated", @@ -1512,6 +1512,73 @@ }, "time": "2022-05-23T21:33:49+00:00" }, + { + "name": "egulias/email-validator", + "version": "3.2.5", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "b531a2311709443320c786feb4519cfaf94af796" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b531a2311709443320c786feb4519cfaf94af796", + "reference": "b531a2311709443320c786feb4519cfaf94af796", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.2|^2", + "php": ">=7.2", + "symfony/polyfill-intl-idn": "^1.15" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.8|^9.3.3", + "vimeo/psalm": "^4" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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/3.2.5" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2023-01-02T17:26:14+00:00" + }, { "name": "eightpoints/guzzle-bundle", "version": "v7.6.2", @@ -2386,51 +2453,67 @@ }, { "name": "monolog/monolog", - "version": "1.27.1", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", - "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "php-amqplib/php-amqplib": "~2.4", - "php-console/php-console": "^3.1.3", - "phpstan/phpstan": "^0.12.59", - "phpunit/phpunit": "~4.5", - "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", - "swiftmailer/swiftmailer": "^5.3|^6.0" + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", + "phpunit/phpunit": "^8.5.14", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "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-mongo": "Allow sending log messages to a MongoDB server", + "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 PHP Driver", + "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", - "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -2444,11 +2527,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -2456,7 +2539,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + "source": "https://github.com/Seldaek/monolog/tree/2.9.1" }, "funding": [ { @@ -2468,7 +2551,7 @@ "type": "tidelift" } ], - "time": "2022-06-09T08:53:42+00:00" + "time": "2023-02-06T13:44:46+00:00" }, { "name": "nelmio/cors-bundle", @@ -2727,58 +2810,6 @@ }, "time": "2016-08-06T14:39:51+00:00" }, - { - "name": "psr/link", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/link.git", - "reference": "eea8e8662d5cd3ae4517c9b864493f59fca95562" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/link/zipball/eea8e8662d5cd3ae4517c9b864493f59fca95562", - "reference": "eea8e8662d5cd3ae4517c9b864493f59fca95562", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Link\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interfaces for HTTP links", - "keywords": [ - "http", - "http-link", - "link", - "psr", - "psr-13", - "rest" - ], - "support": { - "source": "https://github.com/php-fig/link/tree/master" - }, - "time": "2016-10-28T16:06:13+00:00" - }, { "name": "psr/log", "version": "1.0.2", @@ -3077,54 +3108,42 @@ "time": "2023-02-22T23:07:41+00:00" }, { - "name": "symfony/contracts", - "version": "v1.1.13", + "name": "symfony/asset", + "version": "v5.4.21", "source": { "type": "git", - "url": "https://github.com/symfony/contracts.git", - "reference": "9e27f5c175ecbd6fff554d839ff4a432da797168" + "url": "https://github.com/symfony/asset.git", + "reference": "1504b6773c6b90118f9871e90a67833b5d1dca3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/contracts/zipball/9e27f5c175ecbd6fff554d839ff4a432da797168", - "reference": "9e27f5c175ecbd6fff554d839ff4a432da797168", + "url": "https://api.github.com/repos/symfony/asset/zipball/1504b6773c6b90118f9871e90a67833b5d1dca3c", + "reference": "1504b6773c6b90118f9871e90a67833b5d1dca3c", "shasum": "" }, "require": { - "php": ">=7.1.3", - "psr/cache": "^1.0|^2.0|^3.0", - "psr/container": "^1.0" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" }, - "replace": { - "symfony/cache-contracts": "self.version", - "symfony/event-dispatcher-contracts": "self.version", - "symfony/http-client-contracts": "self.version", - "symfony/service-contracts": "self.version", - "symfony/translation-contracts": "self.version" + "conflict": { + "symfony/http-foundation": "<5.3" }, "require-dev": { - "symfony/polyfill-intl-idn": "^1.10" + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^5.3|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0" }, "suggest": { - "psr/event-dispatcher": "When using the EventDispatcher contracts", - "symfony/cache-implementation": "", - "symfony/event-dispatcher-implementation": "", - "symfony/http-client-implementation": "", - "symfony/service-implementation": "", - "symfony/translation-implementation": "" + "symfony/http-foundation": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.1-dev" - } - }, "autoload": { "psr-4": { - "Symfony\\Contracts\\": "" + "Symfony\\Component\\Asset\\": "" }, "exclude-from-classmap": [ - "**/Tests/" + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3133,26 +3152,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": "A set of abstractions extracted out of the Symfony components", + "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], "support": { - "source": "https://github.com/symfony/contracts/tree/v1.1.13" + "source": "https://github.com/symfony/asset/tree/v5.4.21" }, "funding": [ { @@ -3168,38 +3179,62 @@ "type": "tidelift" } ], - "time": "2022-06-27T13:16:42+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { - "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "name": "symfony/cache", + "version": "v4.4.48", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" }, + "type": "library", "autoload": { - "files": [ - "function.php" + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3216,10 +3251,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "A generic function and convention to trigger deprecation notices", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/cache/tree/v4.4.48" }, "funding": [ { @@ -3235,48 +3274,43 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-10-17T20:21:54+00:00" }, { - "name": "symfony/monolog-bundle", - "version": "v3.8.0", + "name": "symfony/cache-contracts", + "version": "v2.5.2", "source": { "type": "git", - "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", - "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", "shasum": "" }, "require": { - "monolog/monolog": "^1.22 || ^2.0 || ^3.0", - "php": ">=7.1.3", - "symfony/config": "~4.4 || ^5.0 || ^6.0", - "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", - "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", - "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" }, - "require-dev": { - "symfony/console": "~4.4 || ^5.0 || ^6.0", - "symfony/phpunit-bridge": "^5.2 || ^6.0", - "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + "suggest": { + "symfony/cache-implementation": "" }, - "type": "symfony-bundle", + "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "psr-4": { - "Symfony\\Bundle\\MonologBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\Cache\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3284,23 +3318,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": "Symfony MonologBundle", + "description": "Generic abstractions related to caching", "homepage": "https://symfony.com", "keywords": [ - "log", - "logging" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" }, "funding": [ { @@ -3316,48 +3353,51 @@ "type": "tidelift" } ], - "time": "2022-05-10T14:24:36+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "name": "symfony/config", + "version": "v5.4.21", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "url": "https://github.com/symfony/config.git", + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" }, - "provide": { - "ext-ctype": "*" + "conflict": { + "symfony/finder": "<4.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" }, "suggest": { - "ext-ctype": "For best performance" + "symfony/yaml": "To use the yaml reference dumper" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3365,24 +3405,18 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/config/tree/v5.4.21" }, "funding": [ { @@ -3398,27 +3432,2450 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { - "name": "symfony/polyfill-intl-icu", - "version": "v1.27.0", + "name": "symfony/console", + "version": "v4.4.49", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c" + "url": "https://github.com/symfony/console.git", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/a3d9148e2c363588e05abbdd4ee4f971f0a5330c", - "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c", + "url": "https://api.github.com/repos/symfony/console/zipball/33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T17:10:16+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "5bc403d96622cf0091abd92c939eadecd4d07f94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5bc403d96622cf0091abd92c939eadecd4d07f94", + "reference": "5bc403d96622cf0091abd92c939eadecd4d07f94", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1.1", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<5.3", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^5.3|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4.26|^5.0|^6.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-16T09:33:00+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/doctrine-bridge", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-bridge.git", + "reference": "8dbbec53714eb512321380d582b45ff7e074a5d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/8dbbec53714eb512321380d582b45ff7e074a5d6", + "reference": "8dbbec53714eb512321380d582b45ff7e074a5d6", + "shasum": "" + }, + "require": { + "doctrine/event-manager": "~1.0", + "doctrine/persistence": "^1.3|^2|^3", + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "doctrine/dbal": "<2.7", + "doctrine/lexer": "<1.1", + "doctrine/orm": "<2.6.3", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/dependency-injection": "<3.4", + "symfony/form": "<4.4", + "symfony/http-kernel": "<4.3.7", + "symfony/messenger": "<4.3", + "symfony/proxy-manager-bridge": "<4.4.19", + "symfony/security-core": "<4.4", + "symfony/validator": "<4.4.2|<5.0.2,>=5.0" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.8", + "doctrine/annotations": "^1.10.4", + "doctrine/collections": "~1.0", + "doctrine/data-fixtures": "^1.1", + "doctrine/dbal": "^2.7|^3.0", + "doctrine/orm": "^2.6.3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.4.41|^5.0.11", + "symfony/http-kernel": "^4.3.7", + "symfony/messenger": "^4.4|^5.0", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/proxy-manager-bridge": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/translation": "^3.4|^4.0|^5.0", + "symfony/validator": "^4.4.2|^5.0.2", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/data-fixtures": "", + "doctrine/dbal": "", + "doctrine/orm": "", + "symfony/form": "", + "symfony/property-info": "", + "symfony/validator": "" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Doctrine\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Doctrine with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/doctrine-bridge/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-14T11:24:01+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/expression-language", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/expression-language.git", + "reference": "e4964c7636e19f6008660f450c09121c80c2a7b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/e4964c7636e19f6008660f450c09121c80c2a7b9", + "reference": "e4964c7636e19f6008660f450c09121c80c2a7b9", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/cache": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ExpressionLanguage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an engine that can compile and evaluate expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/expression-language/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e75960b1bbfd2b8c9e483e0d74811d555ca3de9f", + "reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-16T09:33:00+00:00" + }, + { + "name": "symfony/flex", + "version": "v1.19.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "51077ed0f6dc2c94cd0b670167eee3747c31b2c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/51077ed0f6dc2c94cd0b670167eee3747c31b2c1", + "reference": "51077ed0f6dc2c94cd0b670167eee3747c31b2c1", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.19.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-30T17:02:31+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d8cf2558249004a29b8e27b1f6eae52337ff471b", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.4.11|~5.0.11|^5.1.3", + "symfony/dependency-injection": "^4.4.38|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/routing": "^4.4.12|^5.1.4" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.4.21", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "doctrine/persistence": "^1.3|^2|^3", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.4.42|^5.4.9", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T15:42:31+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "3bb6ee5582366c4176d5ce596b380117c8200bbf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3bb6ee5582366c4176d5ce596b380117c8200bbf", + "reference": "3bb6ee5582366c4176d5ce596b380117c8200bbf", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" + }, + "suggest": { + "symfony/mime": "To use the file extension guesser" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-17T21:35:35+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/mailer", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "554b8c0dc2db9d74e760fd6b726f527364f03302" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/554b8c0dc2db9d74e760fd6b726f527364f03302", + "reference": "554b8c0dc2db9d74e760fd6b726f527364f03302", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3", + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^4.3", + "symfony/mime": "^4.4.21|^5.2.6", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/http-kernel": "<4.4", + "symfony/sendgrid-mailer": "<4.4" + }, + "require-dev": { + "symfony/amazon-mailer": "^4.4|^5.0", + "symfony/google-mailer": "^4.4|^5.0", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/mailchimp-mailer": "^4.4|^5.0", + "symfony/mailgun-mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/postmark-mailer": "^4.4|^5.0", + "symfony/sendgrid-mailer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-04T06:30:35+00:00" + }, + { + "name": "symfony/mime", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd", + "reference": "ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<4.4", + "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.1|^6.0", + "symfony/property-info": "^4.4|^5.1|^6.0", + "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-21T19:46:44+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v5.2.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "2c3943d7c0100983f9c0a82807555273353e3539" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/2c3943d7c0100983f9c0a82807555273353e3539", + "reference": "2c3943d7c0100983f9c0a82807555273353e3539", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1|^2", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/http-kernel": "^4.4|^5.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<4.4", + "symfony/http-foundation": "<4.4" + }, + "require-dev": { + "symfony/console": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v5.2.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-23T15:54:19+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/password-hasher", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/password-hasher.git", + "reference": "7ce4529b2b2ea7de3b6f344a1a41f58201999180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/7ce4529b2b2ea7de3b6f344a1a41f58201999180", + "reference": "7ce4529b2b2ea7de3b6f344a1a41f58201999180", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "symfony/security-core": "<5.3" + }, + "require-dev": { + "symfony/console": "^5.3|^6.0", + "symfony/security-core": "^5.3|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PasswordHasher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Robin Chalas", + "email": "robin.chalas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides password hashing utilities", + "homepage": "https://symfony.com", + "keywords": [ + "hashing", + "password" + ], + "support": { + "source": "https://github.com/symfony/password-hasher/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "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 intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" }, - "suggest": { - "ext-intl": "For best performance and support of other locales than \"en\"" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" }, "type": "library", "extra": { @@ -3435,13 +5892,10 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Icu\\": "" + "Symfony\\Polyfill\\Php81\\": "" }, "classmap": [ "Resources/stubs" - ], - "exclude-from-classmap": [ - "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3458,18 +5912,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's ICU-related data and classes", + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "icu", - "intl", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" }, "funding": [ { @@ -3488,43 +5940,298 @@ "time": "2022-11-03T14:55:06+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.27.0", + "name": "symfony/routing", + "version": "v5.4.21", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + "url": "https://github.com/symfony/routing.git", + "reference": "2ea0f3049076e8ef96eab203a809d6b2332f0361" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "url": "https://api.github.com/repos/symfony/routing/zipball/2ea0f3049076e8ef96eab203a809d6b2332f0361", + "reference": "2ea0f3049076e8ef96eab203a809d6b2332f0361", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "doctrine/annotations": "<1.12", + "symfony/config": "<5.3", + "symfony/dependency-injection": "<4.4", + "symfony/yaml": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12|^2", + "psr/log": "^1|^2|^3", + "symfony/config": "^5.3|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4|^5.0|^6.0" }, "suggest": { - "ext-intl": "For best performance" + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-16T09:33:00+00:00" + }, + { + "name": "symfony/security-core", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "aeb333053b9fca8554cdbdb00d451986d3e4386a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/aeb333053b9fca8554cdbdb00d451986d3e4386a", + "reference": "aeb333053b9fca8554cdbdb00d451986d3e4386a", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^1.1|^2|^3", + "symfony/password-hasher": "^5.3|^6.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2|^3" + }, + "conflict": { + "symfony/event-dispatcher": "<4.4", + "symfony/http-foundation": "<5.3", + "symfony/ldap": "<4.4", + "symfony/security-guard": "<4.4", + "symfony/validator": "<5.2" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "psr/container": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^5.3|^6.0", + "symfony/ldap": "^4.4|^5.0|^6.0", + "symfony/translation": "^4.4|^5.0|^6.0", + "symfony/validator": "^5.2|^6.0" + }, + "suggest": { + "psr/container-implementation": "To instantiate the Security class", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/ldap": "For using LDAP integration", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-17T10:07:35+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "45c956ef58135091f53732646a0acd28034f02c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/45c956ef58135091f53732646a0acd28034f02c0", + "reference": "45c956ef58135091f53732646a0acd28034f02c0", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^3.4|^4.0|^5.0" + }, + "conflict": { + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/http-foundation": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "2.5-dev" }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" + "Symfony\\Contracts\\Service\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -3533,30 +6240,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 writing services", "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.27.0" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -3572,47 +6275,36 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", + "name": "symfony/stopwatch", + "version": "v4.4.46", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + "url": "https://github.com/symfony/stopwatch.git", + "reference": "757660703fbd139eea0001b759c6c3bf5bc3ea52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/757660703fbd139eea0001b759c6c3bf5bc3ea52", + "reference": "757660703fbd139eea0001b759c6c3bf5bc3ea52", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1.3", + "symfony/service-contracts": "^1.0|^2" }, - "suggest": { - "ext-intl": "For best performance" + "require-dev": { + "symfony/polyfill-php72": "~1.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + "Symfony\\Component\\Stopwatch\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3621,26 +6313,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 a way to profile code", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + "source": "https://github.com/symfony/stopwatch/tree/v4.4.46" }, "funding": [ { @@ -3656,47 +6340,41 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2022-09-28T12:53:24+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "name": "symfony/translation-contracts", + "version": "v2.5.2", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe", + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "provide": { - "ext-mbstring": "*" + "php": ">=7.2.5" }, "suggest": { - "ext-mbstring": "For best performance" + "symfony/translation-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "2.5-dev" }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Contracts\\Translation\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -3713,17 +6391,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Generic abstractions related to translation", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2" }, "funding": [ { @@ -3739,42 +6418,93 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { - "name": "symfony/polyfill-php72", - "version": "v1.27.0", + "name": "symfony/twig-bridge", + "version": "v5.3.14", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + "url": "https://github.com/symfony/twig-bridge.git", + "reference": "5830022728b73b3a28877b3e2c03332a28294fe7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/5830022728b73b3a28877b3e2c03332a28294fe7", + "reference": "5830022728b73b3a28877b3e2c03332a28294fe7", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^2.13|^3.0.4" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/console": "<4.4", + "symfony/form": "<5.3", + "symfony/http-foundation": "<5.3", + "symfony/http-kernel": "<4.4", + "symfony/translation": "<5.2", + "symfony/workflow": "<5.2" + }, + "require-dev": { + "doctrine/annotations": "^1.12", + "egulias/email-validator": "^2.1.10|^3", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/form": "^5.3", + "symfony/http-foundation": "^5.3", + "symfony/http-kernel": "^4.4|^5.0", + "symfony/intl": "^4.4|^5.0", + "symfony/mime": "^5.2", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/property-info": "^4.4|^5.1", + "symfony/routing": "^4.4|^5.0", + "symfony/security-acl": "^2.8|^3.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/security-csrf": "^4.4|^5.0", + "symfony/security-http": "^4.4|^5.0", + "symfony/serializer": "^5.2", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/translation": "^5.2", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^5.2", + "symfony/yaml": "^4.4|^5.0", + "twig/cssinliner-extra": "^2.12|^3", + "twig/inky-extra": "^2.12|^3", + "twig/markdown-extra": "^2.12|^3" + }, + "suggest": { + "symfony/asset": "For using the AssetExtension", + "symfony/expression-language": "For using the ExpressionExtension", + "symfony/finder": "", + "symfony/form": "For using the FormExtension", + "symfony/http-kernel": "For using the HttpKernelExtension", + "symfony/routing": "For using the RoutingExtension", + "symfony/security-core": "For using the SecurityExtension", + "symfony/security-csrf": "For using the CsrfExtension", + "symfony/security-http": "For using the LogoutUrlExtension", + "symfony/stopwatch": "For using the StopwatchExtension", + "symfony/translation": "For using the TranslationExtension", + "symfony/var-dumper": "For using the DumpExtension", + "symfony/web-link": "For using the WebLinkExtension", + "symfony/yaml": "For using the YamlExtension" }, + "type": "symfony-bridge", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - } + "Symfony\\Bridge\\Twig\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3782,24 +6512,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 7.2+ features to lower PHP versions", + "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + "source": "https://github.com/symfony/twig-bridge/tree/v5.3.14" }, "funding": [ { @@ -3815,44 +6539,59 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2022-01-02T09:51:59+00:00" }, { - "name": "symfony/polyfill-php73", - "version": "v1.27.0", + "name": "symfony/twig-bundle", + "version": "v4.4.41", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + "url": "https://github.com/symfony/twig-bundle.git", + "reference": "164c1edc69f2c7ee337323efc78a8a8a263f45ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/164c1edc69f2c7ee337323efc78a8a8a263f45ff", + "reference": "164c1edc69f2c7ee337323efc78a8a8a263f45ff", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1.3", + "symfony/http-foundation": "^4.3|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/twig-bridge": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "conflict": { + "symfony/dependency-injection": "<4.1", + "symfony/framework-bundle": "<4.4", + "symfony/translation": "<4.2" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.2.5|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/form": "^3.4|^4.0|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/web-link": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, + "type": "symfony-bundle", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" + "Symfony\\Bundle\\TwigBundle\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3861,24 +6600,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 7.3+ features to lower PHP versions", + "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + "source": "https://github.com/symfony/twig-bundle/tree/v4.4.41" }, "funding": [ { @@ -3894,44 +6627,56 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2022-04-12T15:19:55+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "name": "symfony/var-dumper", + "version": "v5.4.21", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "6c5ac3a1be8b849d59a1a77877ee110e1b55eb74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6c5ac3a1be8b849d59a1a77877ee110e1b55eb74", + "reference": "6c5ac3a1be8b849d59a1a77877ee110e1b55eb74", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "conflict": { + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", "autoload": { "files": [ - "bootstrap.php" + "Resources/functions/dump.php" ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Component\\VarDumper\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3939,10 +6684,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -3952,16 +6693,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "debug", + "dump" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.21" }, "funding": [ { @@ -3977,44 +6716,36 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-02-23T10:00:28+00:00" }, { - "name": "symfony/polyfill-php81", - "version": "v1.27.0", + "name": "symfony/var-exporter", + "version": "v5.4.21", "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/be74908a6942fdd331554b3cec27ff41b45ccad4", + "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" }, + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" + "Symfony\\Component\\VarExporter\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -4031,16 +6762,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "description": "Allows exporting any serializable PHP data structure to plain PHP code", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + "source": "https://github.com/symfony/var-exporter/tree/v5.4.21" }, "funding": [ { @@ -4056,174 +6789,50 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-02-21T19:46:44+00:00" }, { - "name": "symfony/symfony", - "version": "v4.4.50", + "name": "symfony/web-profiler-bundle", + "version": "v4.4.47", "source": { "type": "git", - "url": "https://github.com/symfony/symfony.git", - "reference": "6bc1c2e2506327daa9a2359ec45f7098ca947728" + "url": "https://github.com/symfony/web-profiler-bundle.git", + "reference": "c173202d8ce82fde63ec0953eaffdf065018b8f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/symfony/zipball/6bc1c2e2506327daa9a2359ec45f7098ca947728", - "reference": "6bc1c2e2506327daa9a2359ec45f7098ca947728", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/c173202d8ce82fde63ec0953eaffdf065018b8f4", + "reference": "c173202d8ce82fde63ec0953eaffdf065018b8f4", "shasum": "" }, "require": { - "doctrine/event-manager": "~1.0", - "doctrine/persistence": "^1.3|^2|^3", - "ext-xml": "*", - "friendsofphp/proxy-manager-lts": "^1.0.2", "php": ">=7.1.3", - "psr/cache": "^1.0|^2.0", - "psr/container": "^1.0", - "psr/link": "^1.0", - "psr/log": "^1|^2", - "symfony/contracts": "^1.1.8", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php72": "~1.5", - "symfony/polyfill-php73": "^1.11", + "symfony/config": "^4.2|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22", + "symfony/routing": "^4.3|^5.0", + "symfony/twig-bundle": "^4.2|^5.0", "twig/twig": "^1.43|^2.13|^3.0.4" }, "conflict": { - "doctrine/dbal": "<2.7", - "egulias/email-validator": "~3.0.0", - "masterminds/html5": "<2.6", - "monolog/monolog": ">=2", - "ocramius/proxy-manager": "<2.1", - "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", - "phpdocumentor/type-resolver": "<0.3.0|1.3.*", - "phpunit/phpunit": "<5.4.3" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/cache-implementation": "1.0|2.0", - "psr/container-implementation": "1.0", - "psr/event-dispatcher-implementation": "1.0", - "psr/http-client-implementation": "1.0", - "psr/link-implementation": "1.0", - "psr/log-implementation": "1.0|2.0", - "psr/simple-cache-implementation": "1.0|2.0", - "symfony/cache-implementation": "1.0|2.0", - "symfony/event-dispatcher-implementation": "1.1", - "symfony/http-client-implementation": "1.1|2.0", - "symfony/service-implementation": "1.0|2.0", - "symfony/translation-implementation": "1.0|2.0" - }, - "replace": { - "symfony/amazon-mailer": "self.version", - "symfony/asset": "self.version", - "symfony/browser-kit": "self.version", - "symfony/cache": "self.version", - "symfony/config": "self.version", - "symfony/console": "self.version", - "symfony/css-selector": "self.version", - "symfony/debug": "self.version", - "symfony/debug-bundle": "self.version", - "symfony/dependency-injection": "self.version", - "symfony/doctrine-bridge": "self.version", - "symfony/dom-crawler": "self.version", - "symfony/dotenv": "self.version", - "symfony/error-handler": "self.version", - "symfony/event-dispatcher": "self.version", - "symfony/expression-language": "self.version", - "symfony/filesystem": "self.version", - "symfony/finder": "self.version", - "symfony/form": "self.version", - "symfony/framework-bundle": "self.version", - "symfony/google-mailer": "self.version", - "symfony/http-client": "self.version", - "symfony/http-foundation": "self.version", - "symfony/http-kernel": "self.version", - "symfony/inflector": "self.version", - "symfony/intl": "self.version", - "symfony/ldap": "self.version", - "symfony/lock": "self.version", - "symfony/mailchimp-mailer": "self.version", - "symfony/mailer": "self.version", - "symfony/mailgun-mailer": "self.version", - "symfony/messenger": "self.version", - "symfony/mime": "self.version", - "symfony/monolog-bridge": "self.version", - "symfony/options-resolver": "self.version", - "symfony/postmark-mailer": "self.version", - "symfony/process": "self.version", - "symfony/property-access": "self.version", - "symfony/property-info": "self.version", - "symfony/proxy-manager-bridge": "self.version", - "symfony/routing": "self.version", - "symfony/security": "self.version", - "symfony/security-bundle": "self.version", - "symfony/security-core": "self.version", - "symfony/security-csrf": "self.version", - "symfony/security-guard": "self.version", - "symfony/security-http": "self.version", - "symfony/sendgrid-mailer": "self.version", - "symfony/serializer": "self.version", - "symfony/stopwatch": "self.version", - "symfony/templating": "self.version", - "symfony/translation": "self.version", - "symfony/twig-bridge": "self.version", - "symfony/twig-bundle": "self.version", - "symfony/validator": "self.version", - "symfony/var-dumper": "self.version", - "symfony/var-exporter": "self.version", - "symfony/web-link": "self.version", - "symfony/web-profiler-bundle": "self.version", - "symfony/web-server-bundle": "self.version", - "symfony/workflow": "self.version", - "symfony/yaml": "self.version" + "symfony/form": "<4.3", + "symfony/messenger": "<4.2" }, "require-dev": { - "cache/integration-tests": "dev-master", - "composer/package-versions-deprecated": "^1.8", - "doctrine/annotations": "^1.10.4", - "doctrine/cache": "^1.6|^2.0", - "doctrine/collections": "~1.0", - "doctrine/data-fixtures": "^1.1", - "doctrine/dbal": "^2.7|^3.0", - "doctrine/orm": "^2.6.3", - "egulias/email-validator": "^2.1.10|^3.1", - "guzzlehttp/promises": "^1.4", - "masterminds/html5": "^2.6", - "monolog/monolog": "^1.25.1", - "nyholm/psr7": "^1.0", - "paragonie/sodium_compat": "^1.8", - "php-http/httplug": "^1.0|^2.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "predis/predis": "~1.1", - "psr/http-client": "^1.0", - "psr/simple-cache": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.2", - "symfony/security-acl": "~2.8|~3.0", - "twig/cssinliner-extra": "^2.12|^3", - "twig/inky-extra": "^2.12|^3", - "twig/markdown-extra": "^2.12|^3" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.3|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, - "type": "library", + "type": "symfony-bundle", "autoload": { "psr-4": { - "Symfony\\Bundle\\": "src/Symfony/Bundle/", - "Symfony\\Component\\": "src/Symfony/Component/", - "Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/", - "Symfony\\Bridge\\Monolog\\": "src/Symfony/Bridge/Monolog/", - "Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/", - "Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/" + "Symfony\\Bundle\\WebProfilerBundle\\": "" }, - "classmap": [ - "src/Symfony/Component/Intl/Resources/stubs" - ], "exclude-from-classmap": [ - "**/Tests/" + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -4240,14 +6849,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "The Symfony PHP framework", + "description": "Provides a development tool that gives detailed information about the execution of any request", "homepage": "https://symfony.com", - "keywords": [ - "framework" - ], "support": { - "issues": "https://github.com/symfony/symfony/issues", - "source": "https://github.com/symfony/symfony/tree/v4.4.50" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v4.4.47" }, "funding": [ { @@ -4263,7 +6868,7 @@ "type": "tidelift" } ], - "time": "2023-02-01T08:01:44+00:00" + "time": "2022-09-29T14:10:52+00:00" }, { "name": "symfony/webpack-encore-bundle", @@ -4338,6 +6943,77 @@ ], "time": "2023-01-18T19:37:55+00:00" }, + { + "name": "symfony/yaml", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-02T15:47:23+00:00" + }, { "name": "twig/twig", "version": "v3.5.1", @@ -4719,16 +7395,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -4766,7 +7442,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -4774,7 +7450,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nikic/php-parser", @@ -5263,16 +7939,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.4", + "version": "9.6.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d" + "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5", + "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5", "shasum": "" }, "require": { @@ -5305,8 +7981,8 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -5345,7 +8021,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5" }, "funding": [ { @@ -5361,7 +8037,7 @@ "type": "tidelift" } ], - "time": "2023-02-27T13:06:37+00:00" + "time": "2023-03-09T06:34:10+00:00" }, { "name": "sebastian/cli-parser", @@ -6327,6 +9003,153 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "symfony/browser-kit", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-25T12:56:14+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "105a7ac54ecacc1f52a99b9c4963935ca62aac8f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/105a7ac54ecacc1f52a99b9c4963935ca62aac8f", + "reference": "105a7ac54ecacc1f52a99b9c4963935ca62aac8f", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, { "name": "symfony/phpunit-bridge", "version": "v4.4.49", diff --git a/config/bundles.php b/config/bundles.php index 1f546daca..ee0ea86be 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -5,13 +5,13 @@ return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], - Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], - Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], EightPoints\Bundle\GuzzleBundle\EightPointsGuzzleBundle::class => ['all' => true], JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true], Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true], + Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], + Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], ]; diff --git a/config/packages/dev/jms_serializer.yaml b/config/packages/dev/jms_serializer.yaml new file mode 100644 index 000000000..f94604102 --- /dev/null +++ b/config/packages/dev/jms_serializer.yaml @@ -0,0 +1,7 @@ +jms_serializer: + visitors: + json_serialization: + options: + - JSON_PRETTY_PRINT + - JSON_UNESCAPED_SLASHES + - JSON_PRESERVE_ZERO_FRACTION diff --git a/config/packages/dev/monolog.yaml b/config/packages/dev/monolog.yaml index bcdf8602a..b1a67b5b5 100644 --- a/config/packages/dev/monolog.yaml +++ b/config/packages/dev/monolog.yaml @@ -1,5 +1,5 @@ monolog: - channels: ['rate_limit', 'blacklist', 'crawler'] + channels: ['rate_limit', 'denylist', 'crawler'] handlers: main: type: stream @@ -15,12 +15,12 @@ monolog: type: stream path: '%kernel.logs_dir%/rate_limit.log' channels: ['rate_limit'] - blacklist: + denylist: # log all messages (since debug is the lowest level) level: info type: stream - path: '%kernel.logs_dir%/blacklist.log' - channels: ['blacklist'] + path: '%kernel.logs_dir%/denylist.log' + channels: ['denylist'] crawler: level: info type: stream diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 500ffe253..847cd2cf4 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -58,20 +58,3 @@ doctrine: port: '%env(DATABASE_REPLICA_PORT_S8)%' user: '%env(DATABASE_REPLICA_USER)%' password: '%env(DATABASE_REPLICA_PASSWORD)%' - - orm: - auto_generate_proxy_classes: "%kernel.debug%" - #naming_strategy: doctrine.orm.naming_strategy.underscore - default_entity_manager: default - entity_managers: - default: - connection: default - toolsdb: - connection: toolsdb - -doctrine_migrations: - migrations_paths: - 'Application\Migrations': 'src/DoctrineMigrations' - storage: - table_storage: - table_name: migration_versions diff --git a/config/packages/doctrine_migrations.yaml b/config/packages/doctrine_migrations.yaml new file mode 100644 index 000000000..61e661240 --- /dev/null +++ b/config/packages/doctrine_migrations.yaml @@ -0,0 +1,5 @@ +doctrine_migrations: + migrations_paths: + # namespace is arbitrary but should be different from App\Migrations + # as migrations classes should NOT be autoloaded + 'DoctrineMigrations': '%kernel.project_dir%/migrations' diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index b6154e4a3..585ac2778 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -3,11 +3,8 @@ framework: #esi: ~ #translator: { fallbacks: ["%locale%"] } secret: "%env(APP_SECRET)%" - form: ~ - csrf_protection: ~ - validation: { enable_annotations: true } + csrf_protection: true #serializer: { enable_annotations: true } - default_locale: "%locale%" trusted_hosts: ~ session: # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id @@ -16,5 +13,5 @@ framework: cookie_lifetime: 604800 # 1 week fragments: ~ http_method_override: true - assets: - json_manifest_path: '%kernel.project_dir%/public/assets/manifest.json' + php_errors: + log: true diff --git a/config/packages/jms_serializer.yaml b/config/packages/jms_serializer.yaml new file mode 100644 index 000000000..d25fa0396 --- /dev/null +++ b/config/packages/jms_serializer.yaml @@ -0,0 +1,13 @@ +jms_serializer: + visitors: + xml_serialization: + format_output: '%kernel.debug%' +# metadata: +# auto_detection: false +# directories: +# any-name: +# namespace_prefix: "My\\FooBundle" +# path: "@MyFooBundle/Resources/config/serializer" +# another-name: +# namespace_prefix: "My\\BarBundle" +# path: "@MyBarBundle/Resources/config/serializer" diff --git a/config/packages/prod/jms_serializer.yaml b/config/packages/prod/jms_serializer.yaml new file mode 100644 index 000000000..89c86c893 --- /dev/null +++ b/config/packages/prod/jms_serializer.yaml @@ -0,0 +1,6 @@ +jms_serializer: + visitors: + json_serialization: + options: + - JSON_UNESCAPED_SLASHES + - JSON_PRESERVE_ZERO_FRACTION diff --git a/config/packages/prod/monolog.yaml b/config/packages/prod/monolog.yaml index a06ea99ab..b8b532dbb 100644 --- a/config/packages/prod/monolog.yaml +++ b/config/packages/prod/monolog.yaml @@ -1,5 +1,5 @@ monolog: - channels: ['rate_limit', 'blacklist', 'crawler', 'main'] + channels: ['rate_limit', 'denylist', 'crawler', 'main'] handlers: rate_limit: # log all messages (since debug is the lowest level) @@ -7,12 +7,12 @@ monolog: type: stream path: '%kernel.logs_dir%/rate_limit.log' channels: [rate_limit] - blacklist: + denylist: # log all messages (since debug is the lowest level) level: info type: stream - path: '%kernel.logs_dir%/blacklist.log' - channels: ['blacklist'] + path: '%kernel.logs_dir%/denylist.log' + channels: ['denylist'] crawler: level: info type: stream diff --git a/config/packages/prod/routing.yaml b/config/packages/prod/routing.yaml new file mode 100644 index 000000000..b3e6a0af2 --- /dev/null +++ b/config/packages/prod/routing.yaml @@ -0,0 +1,3 @@ +framework: + router: + strict_requirements: null diff --git a/config/packages/sensio_framework_extra.yaml b/config/packages/sensio_framework_extra.yaml new file mode 100644 index 000000000..1821ccc07 --- /dev/null +++ b/config/packages/sensio_framework_extra.yaml @@ -0,0 +1,3 @@ +sensio_framework_extra: + router: + annotations: false diff --git a/config/packages/test/twig.yaml b/config/packages/test/twig.yaml new file mode 100644 index 000000000..8c6e0b401 --- /dev/null +++ b/config/packages/test/twig.yaml @@ -0,0 +1,2 @@ +twig: + strict_variables: true diff --git a/config/packages/webpack_encore.yaml b/config/packages/webpack_encore.yaml new file mode 100644 index 000000000..af5b75e9a --- /dev/null +++ b/config/packages/webpack_encore.yaml @@ -0,0 +1,45 @@ +webpack_encore: + # The path where Encore is building the assets - i.e. Encore.setOutputPath() + output_path: '%kernel.project_dir%/public/assets' + # If multiple builds are defined (as shown below), you can disable the default build: + # output_path: false + + # Set attributes that will be rendered on all script and link tags + script_attributes: + defer: true + # Uncomment (also under link_attributes) if using Turbo Drive + # https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change + # 'data-turbo-track': reload + # link_attributes: + # Uncomment if using Turbo Drive + # 'data-turbo-track': reload + + # If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials') + # crossorigin: 'anonymous' + + # Preload all rendered script and link tags automatically via the HTTP/2 Link header + # preload: true + + # Throw an exception if the entrypoints.json file is missing or an entry is missing from the data + # strict_mode: false + + # If you have multiple builds: + # builds: + # frontend: '%kernel.project_dir%/public/frontend/build' + + # pass the build name as the 3rd argument to the Twig functions + # {{ encore_entry_script_tags('entry1', null, 'frontend') }} + +framework: + assets: + json_manifest_path: '%kernel.project_dir%/public/assets/manifest.json' + +#when@prod: +# webpack_encore: +# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) +# # Available in version 1.2 +# cache: true + +#when@test: +# webpack_encore: +# strict_mode: false diff --git a/config/preload.php b/config/preload.php new file mode 100644 index 000000000..a6d909d42 --- /dev/null +++ b/config/preload.php @@ -0,0 +1,11 @@ +get() # if you need to do this, you can override this setting on individual services public: false + bind: + $apiPath: '%env(API_PATH)%' + $centralAuthProject: '%env(CENTRAL_AUTH_PROJECT)%' + $defaultProject: '%env(DEFAULT_PROJECT)%' + $isWMF: '%env(bool:APP_IS_WMF)%' + $multilingualWikis: '%env(csv:APP_MULTILINGUAL_WIKIS)%' + $optedIn: '%env(csv:OPTED_IN)%' + $projectDir: '%kernel.project_dir%' + $singleWiki: '%env(bool:APP_SINGLE_WIKI)%' + $queryTimeout: '%env(APP_QUERY_TIMEOUT)%' + $replagThreshold: '%env(int:APP_REPLAG_THRESHOLD)%' # Makes classes in src/App available to be used as services. # This creates a service per class whose id is the fully-qualified class name. @@ -70,7 +74,7 @@ services: # but if a service is unused, it's removed anyway exclude: - '../src/Kernel.php' - - '../src/DoctrineMigrations/' + - '../migrations/' # controllers are imported separately to make sure services can be injected # as action arguments even if you don't extend any base controller class @@ -80,14 +84,9 @@ services: App\Repository\: resource: '../src/Repository' - arguments: - $isWMF: '%env(bool:APP_IS_WMF)%' - $queryTimeout: '%app.query_timeout%' App\Twig\: resource: '../src/Twig' - arguments: - $isWMF: '%env(bool:APP_IS_WMF)%' app.monolog.processor.web: class: App\Monolog\WebProcessorMonolog @@ -95,17 +94,22 @@ services: tags: - { name: monolog.processor, method: processRecord } + App\EventSubscriber\RateLimitSubscriber: + arguments: + $rateLimit: '%env(int:APP_RATE_LIMIT_COUNT)%' + $rateDuration: '%env(int:APP_RATE_LIMIT_TIME)%' + GuzzleHttp\Client: alias: 'eight_points_guzzle.client.xtools' # These need to not be public, but they are, for now... app.automated_edits_helper: class: App\Helper\AutomatedEditsHelper - arguments: ['@service_container'] + arguments: ['@session', '@cache.app'] public: true app.i18n_helper: class: App\Helper\I18nHelper - arguments: ['@service_container'] + arguments: ['@request_stack', '@session'] public: true app.exception_listener: diff --git a/src/DoctrineMigrations/Version20170623203059.php b/migrations/Version20170623203059.php similarity index 89% rename from src/DoctrineMigrations/Version20170623203059.php rename to migrations/Version20170623203059.php index b796029ab..a25ba940a 100644 --- a/src/DoctrineMigrations/Version20170623203059.php +++ b/migrations/Version20170623203059.php @@ -1,7 +1,8 @@ . vendor/ public/ - src/DoctrineMigrations/ + migrations/ var/ node_modules/ assets/vendor/ *.min.js bootstrap.php + bin/.phpunit/ diff --git a/src/Controller/ArticleInfoController.php b/src/Controller/ArticleInfoController.php index 342e5109c..b3dc3b522 100644 --- a/src/Controller/ArticleInfoController.php +++ b/src/Controller/ArticleInfoController.php @@ -6,21 +6,13 @@ use App\Exception\XtoolsHttpException; use App\Helper\AutomatedEditsHelper; -use App\Helper\I18nHelper; use App\Model\ArticleInfo; use App\Model\Authorship; use App\Model\Page; use App\Model\Project; use App\Repository\ArticleInfoRepository; -use App\Repository\PageRepository; -use App\Repository\ProjectRepository; -use App\Repository\UserRepository; -use GuzzleHttp\Client; use GuzzleHttp\Exception\ServerException; -use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -30,8 +22,6 @@ class ArticleInfoController extends XtoolsController { protected ArticleInfo $articleInfo; - protected ArticleInfoRepository $articleInfoRepo; - protected AutomatedEditsHelper $autoEditsHelper; /** * @inheritDoc @@ -42,35 +32,6 @@ public function getIndexRoute(): string return 'ArticleInfo'; } - /** - * @param RequestStack $requestStack - * @param ContainerInterface $container - * @param CacheItemPoolInterface $cache - * @param Client $guzzle - * @param I18nHelper $i18n - * @param ProjectRepository $projectRepo - * @param UserRepository $userRepo - * @param PageRepository $pageRepo - * @param ArticleInfoRepository $articleInfoRepo - * @param AutomatedEditsHelper $autoEditsHelper - */ - public function __construct( - RequestStack $requestStack, - ContainerInterface $container, - CacheItemPoolInterface $cache, - Client $guzzle, - I18nHelper $i18n, - ProjectRepository $projectRepo, - UserRepository $userRepo, - PageRepository $pageRepo, - ArticleInfoRepository $articleInfoRepo, - AutomatedEditsHelper $autoEditsHelper - ) { - $this->articleInfoRepo = $articleInfoRepo; - $this->autoEditsHelper = $autoEditsHelper; - parent::__construct($requestStack, $container, $cache, $guzzle, $i18n, $projectRepo, $userRepo, $pageRepo); - } - /** * The search form. * @Route("/articleinfo", name="ArticleInfo") @@ -98,17 +59,21 @@ public function indexAction(): Response /** * Setup the ArticleInfo instance and its Repository. + * @param ArticleInfoRepository $articleInfoRepo + * @param AutomatedEditsHelper $autoEditsHelper */ - private function setupArticleInfo(): void - { + private function setupArticleInfo( + ArticleInfoRepository $articleInfoRepo, + AutomatedEditsHelper $autoEditsHelper + ): void { if (isset($this->articleInfo)) { return; } $this->articleInfo = new ArticleInfo( - $this->articleInfoRepo, + $articleInfoRepo, $this->i18n, - $this->autoEditsHelper, + $autoEditsHelper, $this->page, $this->start, $this->end @@ -117,7 +82,7 @@ private function setupArticleInfo(): void /** * Generate ArticleInfo gadget script for use on-wiki. This automatically points the - * script to this installation's API. Pass ?uglify=1 to uglify the code. + * script to this installation's API. * * @Route("/articleinfo-gadget.js", name="ArticleInfoGadget") * @link https://www.mediawiki.org/wiki/XTools/ArticleInfo_gadget @@ -147,11 +112,15 @@ public function gadgetAction(): Response * "end"=false, * } * ) + * @param ArticleInfoRepository $articleInfoRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return Response * @codeCoverageIgnore */ - public function resultAction(): Response - { + public function resultAction( + ArticleInfoRepository $articleInfoRepo, + AutomatedEditsHelper $autoEditsHelper + ): Response { if (!$this->isDateRangeValid($this->page, $this->start, $this->end)) { $this->addFlashMessage('notice', 'date-range-outside-revisions'); @@ -160,7 +129,7 @@ public function resultAction(): Response ]); } - $this->setupArticleInfo(); + $this->setupArticleInfo($articleInfoRepo, $autoEditsHelper); $this->articleInfo->prepareData(); $maxRevisions = $this->getParameter('app.max_page_revisions'); @@ -220,15 +189,19 @@ private function isDateRangeValid(Page $page, $start, $end): bool * requirements={"page"=".+"} * ) * @Route("/api/page/articleinfo/{project}/{page}", requirements={"page"=".+"}) + * @param ArticleInfoRepository $articleInfoRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return Response|JsonResponse * See ArticleInfoControllerTest::testArticleInfoApi() * @codeCoverageIgnore */ - public function articleInfoApiAction(): Response - { + public function articleInfoApiAction( + ArticleInfoRepository $articleInfoRepo, + AutomatedEditsHelper $autoEditsHelper + ): Response { $this->recordApiUsage('page/articleinfo'); - $this->setupArticleInfo(); + $this->setupArticleInfo($articleInfoRepo, $autoEditsHelper); $data = []; try { @@ -280,13 +253,17 @@ private function getApiHtmlResponse(Project $project, Page $page, array $data): * name="PageApiProse", * requirements={"page"=".+"} * ) + * @param ArticleInfoRepository $articleInfoRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return JsonResponse * @codeCoverageIgnore */ - public function proseStatsApiAction(): JsonResponse - { + public function proseStatsApiAction( + ArticleInfoRepository $articleInfoRepo, + AutomatedEditsHelper $autoEditsHelper + ): JsonResponse { $this->recordApiUsage('page/prose'); - $this->setupArticleInfo(); + $this->setupArticleInfo($articleInfoRepo, $autoEditsHelper); return $this->getFormattedApiResponse($this->articleInfo->getProseStats()); } @@ -358,14 +335,18 @@ public function linksApiAction(): JsonResponse * "limit"=20, * } * ) + * @param ArticleInfoRepository $articleInfoRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return JsonResponse * @codeCoverageIgnore */ - public function topEditorsApiAction(): JsonResponse - { + public function topEditorsApiAction( + ArticleInfoRepository $articleInfoRepo, + AutomatedEditsHelper $autoEditsHelper + ): JsonResponse { $this->recordApiUsage('page/top_editors'); - $this->setupArticleInfo(); + $this->setupArticleInfo($articleInfoRepo, $autoEditsHelper); $topEditors = $this->articleInfo->getTopEditorsByEditCount( (int)$this->limit, '' != $this->request->query->get('nobots') diff --git a/src/Controller/AutomatedEditsController.php b/src/Controller/AutomatedEditsController.php index b92dc2fb6..13ffcdebe 100644 --- a/src/Controller/AutomatedEditsController.php +++ b/src/Controller/AutomatedEditsController.php @@ -4,19 +4,11 @@ namespace App\Controller; -use App\Helper\I18nHelper; use App\Model\AutoEdits; use App\Repository\AutoEditsRepository; use App\Repository\EditRepository; -use App\Repository\PageRepository; -use App\Repository\ProjectRepository; -use App\Repository\UserRepository; -use GuzzleHttp\Client; -use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -26,9 +18,6 @@ class AutomatedEditsController extends XtoolsController { protected AutoEdits $autoEdits; - protected AutoEditsRepository $autoEditsRepo; - protected EditRepository $editRepo; - protected PageRepository $pageRepo; /** @var array Data that is passed to the view. */ private array $output; @@ -42,24 +31,6 @@ public function getIndexRoute(): string return 'AutoEdits'; } - public function __construct( - RequestStack $requestStack, - ContainerInterface $container, - CacheItemPoolInterface $cache, - Client $guzzle, - I18nHelper $i18n, - ProjectRepository $projectRepo, - UserRepository $userRepo, - PageRepository $pageRepo, - AutoEditsRepository $autoEditsRepo, - EditRepository $editRepo - ) { - $this->autoEditsRepo = $autoEditsRepo; - $this->editRepo = $editRepo; - $this->pageRepo = $pageRepo; - parent::__construct($requestStack, $container, $cache, $guzzle, $i18n, $projectRepo, $userRepo, $pageRepo); - } - /** * This causes the tool to redirect back to the index page, with an error, * if the user has too high of an edit count. @@ -116,9 +87,11 @@ public function indexAction(): Response /** * Set defaults, and instantiate the AutoEdits model. This is called at the top of every view action. + * @param AutoEditsRepository $autoEditsRepo + * @param EditRepository $editRepo * @codeCoverageIgnore */ - private function setupAutoEdits(): void + private function setupAutoEdits(AutoEditsRepository $autoEditsRepo, EditRepository $editRepo): void { $tool = $this->request->query->get('tool', null); $useSandbox = (bool)$this->request->query->get('usesandbox', false); @@ -127,9 +100,9 @@ private function setupAutoEdits(): void $this->addFlashMessage('danger', 'auto-edits-logged-out'); $useSandbox = false; } - $this->autoEditsRepo->setUseSandbox($useSandbox); + $autoEditsRepo->setUseSandbox($useSandbox); - $misconfigured = $this->autoEditsRepo->getInvalidTools($this->project); + $misconfigured = $autoEditsRepo->getInvalidTools($this->project); $helpLink = "https://w.wiki/ppr"; foreach ($misconfigured as $tool) { $this->addFlashMessage('warning', 'auto-edits-misconfiguration', [$tool, $helpLink]); @@ -138,7 +111,7 @@ private function setupAutoEdits(): void // Validate tool. // FIXME: instead of redirecting to index page, show result page listing all tools for that project, // clickable to show edits by the user, etc. - if ($tool && !isset($this->autoEditsRepo->getTools($this->project)[$tool])) { + if ($tool && !isset($autoEditsRepo->getTools($this->project)[$tool])) { $this->throwXtoolsException( $this->getIndexRoute(), 'auto-edits-unknown-tool', @@ -148,8 +121,8 @@ private function setupAutoEdits(): void } $this->autoEdits = new AutoEdits( - $this->autoEditsRepo, - $this->editRepo, + $autoEditsRepo, + $editRepo, $this->pageRepo, $this->userRepo, $this->project, @@ -183,13 +156,15 @@ private function setupAutoEdits(): void * }, * defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false} * ) + * @param AutoEditsRepository $autoEditsRepo + * @param EditRepository $editRepo * @return Response * @codeCoverageIgnore */ - public function resultAction(): Response + public function resultAction(AutoEditsRepository $autoEditsRepo, EditRepository $editRepo): Response { // Will redirect back to index if the user has too high of an edit count. - $this->setupAutoEdits(); + $this->setupAutoEdits($autoEditsRepo, $editRepo); if (in_array('bot', $this->user->getUserRights($this->project))) { $this->addFlashMessage('warning', 'auto-edits-bot'); @@ -212,13 +187,14 @@ public function resultAction(): Response * }, * defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false} * ) + * @param AutoEditsRepository $autoEditsRepo + * @param EditRepository $editRepo * @return Response|RedirectResponse * @codeCoverageIgnore */ - public function nonAutomatedEditsAction(): Response + public function nonAutomatedEditsAction(AutoEditsRepository $autoEditsRepo, EditRepository $editRepo): Response { - $this->setupAutoEdits(); - + $this->setupAutoEdits($autoEditsRepo, $editRepo); return $this->getFormattedResponse('autoEdits/nonautomated_edits', $this->output); } @@ -236,12 +212,14 @@ public function nonAutomatedEditsAction(): Response * }, * defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false} * ) + * @param AutoEditsRepository $autoEditsRepo + * @param EditRepository $editRepo * @return Response * @codeCoverageIgnore */ - public function automatedEditsAction(): Response + public function automatedEditsAction(AutoEditsRepository $autoEditsRepo, EditRepository $editRepo): Response { - $this->setupAutoEdits(); + $this->setupAutoEdits($autoEditsRepo, $editRepo); return $this->getFormattedResponse('autoEdits/automated_edits', $this->output); } @@ -252,13 +230,14 @@ public function automatedEditsAction(): Response * Get a list of the automated tools and their regex/tags/etc. * @Route("/api/user/automated_tools/{project}", name="UserApiAutoEditsTools") * @Route("/api/project/automated_tools/{project}", name="ProjectApiAutoEditsTools") + * @param AutoEditsRepository $autoEditsRepo * @return JsonResponse * @codeCoverageIgnore */ - public function automatedToolsApiAction(): JsonResponse + public function automatedToolsApiAction(AutoEditsRepository $autoEditsRepo): JsonResponse { $this->recordApiUsage('user/automated_tools'); - return $this->getFormattedApiResponse($this->autoEditsRepo->getTools($this->project)); + return $this->getFormattedApiResponse($autoEditsRepo->getTools($this->project)); } /** @@ -274,14 +253,18 @@ public function automatedToolsApiAction(): JsonResponse * }, * defaults={"namespace"="all", "start"=false, "end"=false, "tools"=false} * ) + * @param AutoEditsRepository $autoEditsRepo + * @param EditRepository $editRepo * @return JsonResponse * @codeCoverageIgnore */ - public function automatedEditCountApiAction(): JsonResponse - { + public function automatedEditCountApiAction( + AutoEditsRepository $autoEditsRepo, + EditRepository $editRepo + ): JsonResponse { $this->recordApiUsage('user/automated_editcount'); - $this->setupAutoEdits(); + $this->setupAutoEdits($autoEditsRepo, $editRepo); $ret = [ 'total_editcount' => $this->autoEdits->getEditCount(), @@ -311,14 +294,18 @@ public function automatedEditCountApiAction(): JsonResponse * }, * defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false, "limit"=50} * ) + * @param AutoEditsRepository $autoEditsRepo + * @param EditRepository $editRepo * @return JsonResponse * @codeCoverageIgnore */ - public function nonAutomatedEditsApiAction(): JsonResponse - { + public function nonAutomatedEditsApiAction( + AutoEditsRepository $autoEditsRepo, + EditRepository $editRepo + ): JsonResponse { $this->recordApiUsage('user/nonautomated_edits'); - $this->setupAutoEdits(); + $this->setupAutoEdits($autoEditsRepo, $editRepo); $out = $this->addFullPageTitlesAndContinue( 'nonautomated_edits', @@ -343,14 +330,16 @@ public function nonAutomatedEditsApiAction(): JsonResponse * }, * defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false, "limit"=50} * ) + * @param AutoEditsRepository $autoEditsRepo + * @param EditRepository $editRepo * @return Response * @codeCoverageIgnore */ - public function automatedEditsApiAction(): Response + public function automatedEditsApiAction(AutoEditsRepository $autoEditsRepo, EditRepository $editRepo): Response { $this->recordApiUsage('user/automated_edits'); - $this->setupAutoEdits(); + $this->setupAutoEdits($autoEditsRepo, $editRepo); $extras = $this->autoEdits->getTool() ? ['tool' => $this->autoEdits->getTool()] diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php index acfd200dd..f9b6a7c5a 100644 --- a/src/Controller/DefaultController.php +++ b/src/Controller/DefaultController.php @@ -55,16 +55,18 @@ public function indexAction(): Response * @param Request $request * @param SessionInterface $session * @param ProjectRepository $projectRepo + * @param string $centralAuthProject * @return RedirectResponse * @throws Exception If initialization fails. */ public function loginAction( Request $request, SessionInterface $session, - ProjectRepository $projectRepo + ProjectRepository $projectRepo, + string $centralAuthProject ): RedirectResponse { try { - [ $next, $token ] = $this->getOauthClient($request, $projectRepo)->initiate(); + [ $next, $token ] = $this->getOauthClient($request, $projectRepo, $centralAuthProject)->initiate(); } catch (Exception $oauthException) { throw $oauthException; // @TODO Make this work. @@ -84,12 +86,14 @@ public function loginAction( * @param Request $request The HTTP request. * @param SessionInterface $session * @param ProjectRepository $projectRepo + * @param string $centralAuthProject * @return RedirectResponse */ public function oauthCallbackAction( Request $request, SessionInterface $session, - ProjectRepository $projectRepo + ProjectRepository $projectRepo, + string $centralAuthProject ): RedirectResponse { // Give up if the required GET params don't exist. if (!$request->get('oauth_verifier')) { @@ -97,7 +101,7 @@ public function oauthCallbackAction( } // Complete authentication. - $client = $this->getOauthClient($request, $projectRepo); + $client = $this->getOauthClient($request, $projectRepo, $centralAuthProject); $token = $session->get('oauth_request_token'); if (!is_a($token, Token::class)) { @@ -133,17 +137,19 @@ public function oauthCallbackAction( * (This shouldn't really be in this class, but oh well.) * @param Request $request * @param ProjectRepository $projectRepo + * @param string $centralAuthProject * @return Client * @codeCoverageIgnore */ - protected function getOauthClient(Request $request, ProjectRepository $projectRepo): Client - { + protected function getOauthClient( + Request $request, + ProjectRepository $projectRepo, + string $centralAuthProject + ): Client { if (isset($this->oauthClient)) { return $this->oauthClient; } - $defaultProject = $projectRepo->getProject( - $this->getParameter('central_auth_project') - ); + $defaultProject = $projectRepo->getProject($centralAuthProject); $endpoint = $defaultProject->getUrl(false) . $defaultProject->getScript() . '?title=Special:OAuth'; diff --git a/src/Controller/EditCounterController.php b/src/Controller/EditCounterController.php index 1cd0eb62a..9b37d337b 100644 --- a/src/Controller/EditCounterController.php +++ b/src/Controller/EditCounterController.php @@ -4,28 +4,18 @@ namespace App\Controller; -use App\Exception\XtoolsHttpException; -use App\Helper\I18nHelper; use App\Model\EditCounter; use App\Model\GlobalContribs; use App\Model\UserRights; use App\Repository\EditCounterRepository; use App\Repository\EditRepository; use App\Repository\GlobalContribsRepository; -use App\Repository\PageRepository; -use App\Repository\ProjectRepository; -use App\Repository\UserRepository; use App\Repository\UserRightsRepository; -use GuzzleHttp\Client; -use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; /** * Class EditCounterController @@ -47,9 +37,7 @@ class EditCounterController extends XtoolsController ]; protected EditCounter $editCounter; - protected EditCounterRepository $editCounterRepo; protected UserRights $userRights; - protected UserRightsRepository $userRightsRepo; /** @var string[] Which sections to show. */ protected array $sections; @@ -63,36 +51,6 @@ public function getIndexRoute(): string return 'EditCounter'; } - /** - * EditCounterController constructor. - * @param RequestStack $requestStack - * @param ContainerInterface $container - * @param CacheItemPoolInterface $cache - * @param Client $guzzle - * @param I18nHelper $i18n - * @param ProjectRepository $projectRepo - * @param UserRepository $userRepo - * @param EditCounterRepository $editCounterRepo - * @param UserRightsRepository $userRightsRepo - * @param PageRepository $pageRepo - */ - public function __construct( - RequestStack $requestStack, - ContainerInterface $container, - CacheItemPoolInterface $cache, - Client $guzzle, - I18nHelper $i18n, - ProjectRepository $projectRepo, - UserRepository $userRepo, - EditCounterRepository $editCounterRepo, - UserRightsRepository $userRightsRepo, - PageRepository $pageRepo - ) { - $this->editCounterRepo = $editCounterRepo; - $this->userRightsRepo = $userRightsRepo; - parent::__construct($requestStack, $container, $cache, $guzzle, $i18n, $projectRepo, $userRepo, $pageRepo); - } - /** * Causes the tool to redirect to the Simple Edit Counter if the user has too high of an edit count. * @inheritDoc @@ -124,12 +82,14 @@ public function restrictedApiActions(): array /** * Every action in this controller (other than 'index') calls this first. * If a response is returned, the calling action is expected to return it. - * @throws AccessDeniedException If attempting to access internal endpoint. - * @throws XtoolsHttpException If an API request to restricted endpoint when user has not opted in. + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @codeCoverageIgnore */ - protected function setUpEditCounter(): void - { + protected function setUpEditCounter( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): void { // Whether we're making a subrequest (the view makes a request to another action). // Subrequests to the same controller do not re-instantiate a new controller, and hence // this flag would not be set in XtoolsController::__construct(), so we must do it here as well. @@ -147,11 +107,11 @@ protected function setUpEditCounter(): void // Store which sections of the Edit Counter they requested. $this->sections = $this->getRequestedSections(); - $this->userRights = new UserRights($this->userRightsRepo, $this->project, $this->user, $this->i18n); + $this->userRights = new UserRights($userRightsRepo, $this->project, $this->user, $this->i18n); // Instantiate EditCounter. $this->editCounter = new EditCounter( - $this->editCounterRepo, + $editCounterRepo, $this->i18n, $this->userRights, $this->project, @@ -190,10 +150,10 @@ public function indexAction() * Get the requested sections either from the URL, cookie, or the defaults (all sections). * @param bool $useCookies Whether or not to check cookies for the preferred sections. * This option should not be true except on the index form. - * @return array|mixed|string[] + * @return array|string[] * @codeCoverageIgnore */ - private function getRequestedSections(bool $useCookies = false) + private function getRequestedSections(bool $useCookies = false): array { // Happens from sub-tool index pages, e.g. see self::generalStatsIndexAction(). if (isset($this->sections)) { @@ -275,12 +235,14 @@ private function redirectFromSections(): RedirectResponse * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return Response|RedirectResponse * @codeCoverageIgnore */ - public function resultAction() + public function resultAction(EditCounterRepository $editCounterRepo, UserRightsRepository $userRightsRepo) { - $this->setUpEditCounter(); + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); if (1 === count($this->sections)) { // Redirect to dedicated route. @@ -298,7 +260,7 @@ public function resultAction() ]; // Used when querying for global rights changes. - if ($this->getParameter('app.is_wmf')) { + if ($this->isWMF) { $ret['metaProject'] = $this->projectRepo->getProject('metawiki'); } @@ -314,16 +276,20 @@ public function resultAction() * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @param GlobalContribsRepository $globalContribsRepo * @param EditRepository $editRepo * @return Response * @codeCoverageIgnore */ public function generalStatsAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo, GlobalContribsRepository $globalContribsRepo, EditRepository $editRepo ): Response { - $this->setUpEditCounter(); + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); $globalContribs = new GlobalContribs( $globalContribsRepo, @@ -373,12 +339,16 @@ public function generalStatsIndexAction(): Response * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return Response * @codeCoverageIgnore */ - public function namespaceTotalsAction(): Response - { - $this->setUpEditCounter(); + public function namespaceTotalsAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): Response { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); $ret = [ 'xtTitle' => $this->user->getUsername(), @@ -414,12 +384,16 @@ public function namespaceTotalsIndexAction(): Response * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return Response * @codeCoverageIgnore */ - public function timecardAction(): Response - { - $this->setUpEditCounter(); + public function timecardAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): Response { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); $ret = [ 'xtTitle' => $this->user->getUsername(), @@ -456,12 +430,16 @@ public function timecardIndexAction(): Response * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return Response * @codeCoverageIgnore */ - public function yearCountsAction(): Response - { - $this->setUpEditCounter(); + public function yearCountsAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): Response { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); $ret = [ 'xtTitle' => $this->user->getUsername(), @@ -497,12 +475,16 @@ public function yearCountsIndexAction(): Response * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return Response * @codeCoverageIgnore */ - public function monthCountsAction(): Response - { - $this->setUpEditCounter(); + public function monthCountsAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): Response { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); $ret = [ 'xtTitle' => $this->user->getUsername(), @@ -539,12 +521,16 @@ public function monthCountsIndexAction(): Response * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return Response * @codeCoverageIgnore */ - public function rightsChangesAction(): Response - { - $this->setUpEditCounter(); + public function rightsChangesAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): Response { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); $ret = [ 'xtTitle' => $this->user->getUsername(), @@ -555,7 +541,7 @@ public function rightsChangesAction(): Response 'ec' => $this->editCounter, ]; - if ($this->getParameter('app.is_wmf')) { + if ($this->isWMF) { $ret['metaProject'] = $this->projectRepo->getProject('metawiki'); } @@ -585,12 +571,16 @@ public function rightsChangesIndexAction(): Response * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return JsonResponse * @codeCoverageIgnore */ - public function logCountsApiAction(): JsonResponse - { - $this->setUpEditCounter(); + public function logCountsApiAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): JsonResponse { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); return $this->getFormattedApiResponse([ 'log_counts' => $this->editCounter->getLogCounts(), @@ -606,12 +596,16 @@ public function logCountsApiAction(): JsonResponse * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return JsonResponse * @codeCoverageIgnore */ - public function namespaceTotalsApiAction(): JsonResponse - { - $this->setUpEditCounter(); + public function namespaceTotalsApiAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): JsonResponse { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); return $this->getFormattedApiResponse([ 'namespace_totals' => (object)$this->editCounter->namespaceTotals(), @@ -627,12 +621,16 @@ public function namespaceTotalsApiAction(): JsonResponse * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return JsonResponse * @codeCoverageIgnore */ - public function monthCountsApiAction(): JsonResponse - { - $this->setUpEditCounter(); + public function monthCountsApiAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): JsonResponse { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); $ret = $this->editCounter->monthCounts(); @@ -652,12 +650,16 @@ public function monthCountsApiAction(): JsonResponse * "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)", * } * ) + * @param EditCounterRepository $editCounterRepo + * @param UserRightsRepository $userRightsRepo * @return JsonResponse * @codeCoverageIgnore */ - public function timecardApiAction(): JsonResponse - { - $this->setUpEditCounter(); + public function timecardApiAction( + EditCounterRepository $editCounterRepo, + UserRightsRepository $userRightsRepo + ): JsonResponse { + $this->setUpEditCounter($editCounterRepo, $userRightsRepo); return $this->getFormattedApiResponse([ 'timecard' => $this->editCounter->timeCard(), diff --git a/src/Controller/GlobalContribsController.php b/src/Controller/GlobalContribsController.php index e22701365..f7b16e9f5 100644 --- a/src/Controller/GlobalContribsController.php +++ b/src/Controller/GlobalContribsController.php @@ -138,13 +138,17 @@ public function getGlobalContribs( * ), * @param GlobalContribsRepository $globalContribsRepo * @param EditRepository $editRepo + * @param string $centralAuthProject * @return Response * @codeCoverageIgnore */ - public function resultsAction(GlobalContribsRepository $globalContribsRepo, EditRepository $editRepo): Response - { + public function resultsAction( + GlobalContribsRepository $globalContribsRepo, + EditRepository $editRepo, + string $centralAuthProject + ): Response { $globalContribs = $this->getGlobalContribs($globalContribsRepo, $editRepo); - $defaultProject = $this->projectRepo->getProject($this->getParameter('central_auth_project')); + $defaultProject = $this->projectRepo->getProject($centralAuthProject); return $this->render('globalContribs/result.html.twig', [ 'xtTitle' => $this->user->getUsername(), @@ -180,17 +184,19 @@ public function resultsAction(GlobalContribsRepository $globalContribsRepo, Edit * ) * @param GlobalContribsRepository $globalContribsRepo * @param EditRepository $editRepo + * @param string $centralAuthProject * @return JsonResponse * @codeCoverageIgnore */ public function resultsApiAction( GlobalContribsRepository $globalContribsRepo, - EditRepository $editRepo + EditRepository $editRepo, + string $centralAuthProject ): JsonResponse { $this->recordApiUsage('user/globalcontribs'); $globalContribs = $this->getGlobalContribs($globalContribsRepo, $editRepo); - $defaultProject = $this->projectRepo->getProject($this->getParameter('central_auth_project')); + $defaultProject = $this->projectRepo->getProject($centralAuthProject); $this->project = $defaultProject; $results = $globalContribs->globalEdits(); diff --git a/src/Controller/MetaController.php b/src/Controller/MetaController.php index ed6eec470..b421ccc7e 100644 --- a/src/Controller/MetaController.php +++ b/src/Controller/MetaController.php @@ -195,14 +195,20 @@ private function getApiUsageStats(Connection $client): array * in base.html.twig via JavaScript so that it is done asynchronously. * @Route("/meta/usage/{tool}/{project}/{token}") * @param Request $request + * @param bool $singleWiki * @param string $tool Internal name of tool. * @param string $project Project domain such as en.wikipedia.org * @param string $token Unique token for this request, so we don't have people meddling with these statistics. * @return Response * @codeCoverageIgnore */ - public function recordUsageAction(Request $request, string $tool, string $project, string $token): Response - { + public function recordUsageAction( + Request $request, + bool $singleWiki, + string $tool, + string $project, + string $token + ): Response { // Ready the response object. $response = new Response(); $response->headers->set('Content-Type', 'application/json'); @@ -242,7 +248,7 @@ public function recordUsageAction(Request $request, string $tool, string $projec ]); // Update per-project usage, if applicable - if (!$this->container->getParameter('app.single_wiki')) { + if (!$singleWiki) { $sql = "INSERT INTO usage_projects VALUES(NULL, :tool, :project, 1) ON DUPLICATE KEY UPDATE `count` = `count` + 1"; diff --git a/src/Controller/PagesController.php b/src/Controller/PagesController.php index 73740a65d..31e41f1b9 100644 --- a/src/Controller/PagesController.php +++ b/src/Controller/PagesController.php @@ -4,20 +4,12 @@ namespace App\Controller; -use App\Helper\I18nHelper; use App\Model\Pages; use App\Model\Project; -use App\Repository\PageRepository; use App\Repository\PagesRepository; -use App\Repository\ProjectRepository; -use App\Repository\UserRepository; -use GuzzleHttp\Client; use GuzzleHttp\Exception\ClientException; -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\Routing\Annotation\Route; @@ -27,35 +19,6 @@ */ class PagesController extends XtoolsController { - protected PagesRepository $pagesRepo; - - /** - * @param RequestStack $requestStack - * @param ContainerInterface $container - * @param CacheItemPoolInterface $cache - * @param Client $guzzle - * @param I18nHelper $i18n - * @param ProjectRepository $projectRepo - * @param UserRepository $userRepo - * @param PageRepository $pageRepo - * @param PagesRepository $pagesRepo - * @codeCoverageIgnore - */ - public function __construct( - RequestStack $requestStack, - ContainerInterface $container, - CacheItemPoolInterface $cache, - Client $guzzle, - I18nHelper $i18n, - ProjectRepository $projectRepo, - UserRepository $userRepo, - PageRepository $pageRepo, - PagesRepository $pagesRepo - ) { - $this->pagesRepo = $pagesRepo; - parent::__construct($requestStack, $container, $cache, $guzzle, $i18n, $projectRepo, $userRepo, $pageRepo); - } - /** * Get the name of the tool's index route. * This is also the name of the associated model. @@ -117,12 +80,13 @@ public function indexAction(): Response /** * Every action in this controller (other than 'index') calls this first. + * @param PagesRepository $pagesRepo * @param string $redirects One of 'noredirects', 'onlyredirects' or 'all' for both. * @param string $deleted One of 'live', 'deleted' or 'all' for both. * @return Pages * @codeCoverageIgnore */ - protected function setUpPages(string $redirects, string $deleted): Pages + protected function setUpPages(PagesRepository $pagesRepo, string $redirects, string $deleted): Pages { if ($this->user->isIpRange()) { $this->params['username'] = $this->user->getUsername(); @@ -130,7 +94,7 @@ protected function setUpPages(string $redirects, string $deleted): Pages } return new Pages( - $this->pagesRepo, + $pagesRepo, $this->project, $this->user, $this->namespace, @@ -163,13 +127,17 @@ protected function setUpPages(string $redirects, string $deleted): Pages * "offset"=false, * } * ) + * @param PagesRepository $pagesRepo * @param string $redirects One of 'noredirects', 'onlyredirects' or 'all' for both. * @param string $deleted One of 'live', 'deleted' or 'all' for both. * @return RedirectResponse|Response * @codeCoverageIgnore */ - public function resultAction(string $redirects = 'noredirects', string $deleted = 'all') - { + public function resultAction( + PagesRepository $pagesRepo, + string $redirects = 'noredirects', + string $deleted = 'all' + ) { // Check for legacy values for 'redirects', and redirect // back with correct values if need be. This could be refactored // out to XtoolsController, but this is the only tool in the suite @@ -183,7 +151,7 @@ public function resultAction(string $redirects = 'noredirects', string $deleted ])); } - $pages = $this->setUpPages($redirects, $deleted); + $pages = $this->setUpPages($pagesRepo, $redirects, $deleted); $pages->prepareData(); $ret = [ @@ -331,16 +299,20 @@ private function createPagePile(Project $project, array $pageTitles): int * "end"=false, * } * ) + * @param PagesRepository $pagesRepo * @param string $redirects One of 'noredirects', 'onlyredirects' or 'all' for both. * @param string $deleted One of 'live', 'deleted' or 'all' for both. * @return JsonResponse * @codeCoverageIgnore */ - public function countPagesApiAction(string $redirects = 'noredirects', string $deleted = 'all'): JsonResponse - { + public function countPagesApiAction( + PagesRepository $pagesRepo, + string $redirects = 'noredirects', + string $deleted = 'all' + ): JsonResponse { $this->recordApiUsage('user/pages_count'); - $pages = $this->setUpPages($redirects, $deleted); + $pages = $this->setUpPages($pagesRepo, $redirects, $deleted); $counts = $pages->getCounts(); if ('all' !== $this->namespace && isset($counts[$this->namespace])) { @@ -373,16 +345,20 @@ public function countPagesApiAction(string $redirects = 'noredirects', string $d * "offset"=false, * } * ) + * @param PagesRepository $pagesRepo * @param string $redirects One of 'noredirects', 'onlyredirects' or 'all' for both. * @param string $deleted One of 'live', 'deleted' or blank for both. * @return JsonResponse * @codeCoverageIgnore */ - public function getPagesApiAction(string $redirects = 'noredirects', string $deleted = 'all'): JsonResponse - { + public function getPagesApiAction( + PagesRepository $pagesRepo, + string $redirects = 'noredirects', + string $deleted = 'all' + ): JsonResponse { $this->recordApiUsage('user/pages'); - $pages = $this->setUpPages($redirects, $deleted); + $pages = $this->setUpPages($pagesRepo, $redirects, $deleted); $pagesList = $pages->getResults(); if ('all' !== $this->namespace && isset($pagesList[$this->namespace])) { diff --git a/src/Controller/TopEditsController.php b/src/Controller/TopEditsController.php index 5284c666e..516fde672 100644 --- a/src/Controller/TopEditsController.php +++ b/src/Controller/TopEditsController.php @@ -5,17 +5,9 @@ namespace App\Controller; use App\Helper\AutomatedEditsHelper; -use App\Helper\I18nHelper; use App\Model\TopEdits; -use App\Repository\PageRepository; -use App\Repository\ProjectRepository; use App\Repository\TopEditsRepository; -use App\Repository\UserRepository; -use GuzzleHttp\Client; -use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -24,9 +16,6 @@ */ class TopEditsController extends XtoolsController { - protected AutomatedEditsHelper $autoEditsHelper; - protected TopEditsRepository $topEditsRepo; - /** * @inheritDoc * @codeCoverageIgnore @@ -36,37 +25,6 @@ public function getIndexRoute(): string return 'TopEdits'; } - /** - * TopEditsController constructor. - * @param RequestStack $requestStack - * @param ContainerInterface $container - * @param CacheItemPoolInterface $cache - * @param Client $guzzle - * @param I18nHelper $i18n - * @param ProjectRepository $projectRepo - * @param UserRepository $userRepo - * @param PageRepository $pageRepo - * @param TopEditsRepository $topEditsRepo - * @param AutomatedEditsHelper $autoEditsHelper - */ - public function __construct( - RequestStack $requestStack, - ContainerInterface $container, - CacheItemPoolInterface $cache, - Client $guzzle, - I18nHelper $i18n, - ProjectRepository $projectRepo, - UserRepository $userRepo, - PageRepository $pageRepo, - TopEditsRepository $topEditsRepo, - AutomatedEditsHelper $autoEditsHelper - ) { - $this->topEditsRepo = $topEditsRepo; - $this->autoEditsHelper = $autoEditsHelper; - $this->limit = 1000; - parent::__construct($requestStack, $container, $cache, $guzzle, $i18n, $projectRepo, $userRepo, $pageRepo); - } - /** * @inheritDoc * @codeCoverageIgnore @@ -129,14 +87,16 @@ public function indexAction(): Response /** * Every action in this controller (other than 'index') calls this first. + * @param TopEditsRepository $topEditsRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return TopEdits * @codeCoverageIgnore */ - public function setUpTopEdits(): TopEdits + public function setUpTopEdits(TopEditsRepository $topEditsRepo, AutomatedEditsHelper $autoEditsHelper): TopEdits { return new TopEdits( - $this->topEditsRepo, - $this->autoEditsHelper, + $topEditsRepo, + $autoEditsHelper, $this->project, $this->user, $this->page, @@ -160,15 +120,19 @@ public function setUpTopEdits(): TopEdits * }, * defaults={"namespace" = "all", "start"=false, "end"=false} * ) + * @param TopEditsRepository $topEditsRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return Response * @codeCoverageIgnore */ - public function namespaceTopEditsAction(): Response - { + public function namespaceTopEditsAction( + TopEditsRepository $topEditsRepo, + AutomatedEditsHelper $autoEditsHelper + ): Response { // Max number of rows per namespace to show. `null` here will use the TopEdits default. $this->limit = $this->isSubRequest ? 10 : $this->limit; - $topEdits = $this->setUpTopEdits(); + $topEdits = $this->setUpTopEdits($topEditsRepo, $autoEditsHelper); $topEdits->prepareData(); $ret = [ @@ -195,13 +159,17 @@ public function namespaceTopEditsAction(): Response * }, * defaults={"namespace"="all", "start"=false, "end"=false} * ) - * @todo Add pagination. + * @param TopEditsRepository $topEditsRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return Response * @codeCoverageIgnore + * @todo Add pagination. */ - public function singlePageTopEditsAction(): Response - { - $topEdits = $this->setUpTopEdits(); + public function singlePageTopEditsAction( + TopEditsRepository $topEditsRepo, + AutomatedEditsHelper $autoEditsHelper + ): Response { + $topEdits = $this->setUpTopEdits($topEditsRepo, $autoEditsHelper); $topEdits->prepareData(); // Send all to the template. @@ -226,14 +194,18 @@ public function singlePageTopEditsAction(): Response * }, * defaults={"namespace"="all", "start"=false, "end"=false} * ) + * @param TopEditsRepository $topEditsRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return JsonResponse * @codeCoverageIgnore */ - public function namespaceTopEditsUserApiAction(): JsonResponse - { + public function namespaceTopEditsUserApiAction( + TopEditsRepository $topEditsRepo, + AutomatedEditsHelper $autoEditsHelper + ): JsonResponse { $this->recordApiUsage('user/topedits'); - $topEdits = $this->setUpTopEdits(); + $topEdits = $this->setUpTopEdits($topEditsRepo, $autoEditsHelper); $topEdits->prepareData(); return $this->getFormattedApiResponse([ @@ -254,15 +226,19 @@ public function namespaceTopEditsUserApiAction(): JsonResponse * }, * defaults={"namespace"="all", "start"=false, "end"=false} * ) - * @todo Add pagination. + * @param TopEditsRepository $topEditsRepo + * @param AutomatedEditsHelper $autoEditsHelper * @return JsonResponse * @codeCoverageIgnore + * @todo Add pagination. */ - public function singlePageTopEditsUserApiAction(): JsonResponse - { + public function singlePageTopEditsUserApiAction( + TopEditsRepository $topEditsRepo, + AutomatedEditsHelper $autoEditsHelper + ): JsonResponse { $this->recordApiUsage('user/topedits'); - $topEdits = $this->setUpTopEdits(); + $topEdits = $this->setUpTopEdits($topEditsRepo, $autoEditsHelper); $topEdits->prepareData(false); return $this->getFormattedApiResponse([ diff --git a/src/Controller/XtoolsController.php b/src/Controller/XtoolsController.php index ee646b82b..90c9329b5 100644 --- a/src/Controller/XtoolsController.php +++ b/src/Controller/XtoolsController.php @@ -13,7 +13,9 @@ use App\Repository\ProjectRepository; use App\Repository\UserRepository; use DateTime; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; use Psr\Container\ContainerInterface; @@ -23,6 +25,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; use Symfony\Component\HttpKernel\Exception\HttpException; use Wikimedia\IPUtils; @@ -37,11 +40,22 @@ abstract class XtoolsController extends AbstractController protected CacheItemPoolInterface $cache; protected Client $guzzle; + protected FlashBagInterface $flashBag; protected I18nHelper $i18n; + protected ManagerRegistry $managerRegistry; protected ProjectRepository $projectRepo; protected UserRepository $userRepo; protected PageRepository $pageRepo; + /** @var bool Whether this is a WMF installation. */ + protected bool $isWMF; + + /** @var string The configured default project. */ + protected string $defaultProject; + + /** @var string[] Which projects are considered multilingual. */ + protected array $multilingualWikis; + /** OTHER CLASS PROPERTIES */ /** @var Request The request object. */ @@ -173,33 +187,48 @@ protected function maxLimit(): int /** * XtoolsController constructor. - * @param RequestStack $requestStack * @param ContainerInterface $container + * @param RequestStack $requestStack + * @param ManagerRegistry $managerRegistry * @param CacheItemPoolInterface $cache + * @param FlashBagInterface $flashBag * @param Client $guzzle * @param I18nHelper $i18n * @param ProjectRepository $projectRepo * @param UserRepository $userRepo * @param PageRepository $pageRepo + * @param bool $isWMF + * @param string $defaultProject + * @param array $multilingualWikis */ public function __construct( - RequestStack $requestStack, ContainerInterface $container, + RequestStack $requestStack, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, + FlashBagInterface $flashBag, Client $guzzle, I18nHelper $i18n, ProjectRepository $projectRepo, UserRepository $userRepo, - PageRepository $pageRepo + PageRepository $pageRepo, + bool $isWMF, + string $defaultProject, + array $multilingualWikis ) { - $this->request = $requestStack->getCurrentRequest(); $this->container = $container; + $this->request = $requestStack->getCurrentRequest(); + $this->managerRegistry = $managerRegistry; $this->cache = $cache; + $this->flashBag = $flashBag; $this->guzzle = $guzzle; $this->i18n = $i18n; $this->projectRepo = $projectRepo; $this->userRepo = $userRepo; $this->pageRepo = $pageRepo; + $this->isWMF = $isWMF; + $this->defaultProject = $defaultProject; + $this->multilingualWikis = $multilingualWikis; $this->params = $this->parseQueryParams(); // Parse out the name of the controller and action. @@ -214,7 +243,7 @@ public function __construct( // Whether we're making a subrequest (the view makes a request to another action). $this->isSubRequest = $this->request->get('htmlonly') - || null !== $this->get('request_stack')->getParentRequest(); + || null !== $requestStack->getParentRequest(); // Disallow AJAX (unless it's an API or subrequest). $this->checkIfAjax(); @@ -431,16 +460,14 @@ public function getProjectFromQuery(): Project } elseif (null !== $this->cookies['XtoolsProject']) { $project = $this->cookies['XtoolsProject']; } else { - $project = $this->getParameter('default_project'); + $project = $this->defaultProject; } $projectData = $this->projectRepo->getProject($project); // Revert back to defaults if we've established the given project was invalid. if (!$projectData->exists()) { - $projectData = $this->projectRepo->getProject( - $this->getParameter('default_project') - ); + $projectData = $this->projectRepo->getProject($this->defaultProject); } return $projectData; @@ -540,7 +567,7 @@ public function validateUser(string $username): User // Clear flash bag for API responses, since they get intercepted in ExceptionListener // and would otherwise be shown in subsequent requests. if ($this->isApi) { - $this->get('session')->getFlashBag()->clear(); + $this->flashBag->clear(); } throw new XtoolsHttpException( @@ -680,7 +707,6 @@ public function getParams(): array */ public function parseQueryParams(): array { - /** @var string[] $params Each parameter and value that was detected. */ $params = $this->getParams(); // Covert any legacy parameters, if present. @@ -783,11 +809,8 @@ private function convertLegacyParams(array $params): array // so we must remove leading periods and trailing .org's. $params['project'] = rtrim(ltrim($params['wiki'], '.'), '.org').'.org'; - /** @var string[] $multilingualProjects Projects for which there is no specific language association. */ - $multilingualProjects = $this->getParameter('app.multilingual_wikis'); - // Prepend language if applicable. - if (isset($params['lang']) && !in_array($params['wiki'], $multilingualProjects)) { + if (isset($params['lang']) && !in_array($params['wiki'], $this->multilingualWikis)) { $params['project'] = $params['lang'].'.'.$params['project']; } @@ -905,11 +928,11 @@ public function getFormattedApiResponse(array $data): JsonResponse ], $data, ['elapsed_time' => $elapsedTime]); // Merge in flash messages, putting them at the top. - $flashes = $this->get('session')->getFlashBag()->peekAll(); + $flashes = $this->flashBag->peekAll(); $ret = array_merge($flashes, $ret); // Flashes now can be cleared after merging into the response. - $this->get('session')->getFlashBag()->clear(); + $this->flashBag->clear(); $response->setData($ret); @@ -961,11 +984,9 @@ public function addFullPageTitlesAndContinue(string $key, array $out, array $dat */ public function recordApiUsage(string $endpoint): void { - /** @var \Doctrine\DBAL\Connection $conn */ - $conn = $this->container->get('doctrine') - ->getManager('default') - ->getConnection(); - $date = date('Y-m-d'); + /** @var Connection $conn */ + $conn = $this->managerRegistry->getConnection('default'); + $date = date('Y-m-d'); // Increment count in timeline try { diff --git a/src/EventSubscriber/DisabledToolSubscriber.php b/src/EventSubscriber/DisabledToolSubscriber.php index e8a366dac..41bbbaf24 100644 --- a/src/EventSubscriber/DisabledToolSubscriber.php +++ b/src/EventSubscriber/DisabledToolSubscriber.php @@ -5,7 +5,7 @@ namespace App\EventSubscriber; use App\Controller\XtoolsController; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -18,15 +18,15 @@ class DisabledToolSubscriber implements EventSubscriberInterface { - protected ContainerInterface $container; + protected ParameterBagInterface $parameterBag; /** * Save the container for later use. - * @param ContainerInterface $container The DI container. + * @param ParameterBagInterface $parameterBag */ - public function __construct(ContainerInterface $container) + public function __construct(ParameterBagInterface $parameterBag) { - $this->container = $container; + $this->parameterBag = $parameterBag; } /** @@ -51,7 +51,7 @@ public function onKernelController(ControllerEvent $event): void if ($controller instanceof XtoolsController && method_exists($controller, 'getIndexRoute')) { $tool = $controller[0]->getIndexRoute(); - if (!in_array($tool, ['homepage', 'meta', 'Quote']) && !$this->container->getParameter("enable.$tool")) { + if (!in_array($tool, ['homepage', 'meta', 'Quote']) && !$this->parameterBag->get("enable.$tool")) { throw new NotFoundHttpException('This tool is disabled'); } } diff --git a/src/EventSubscriber/RateLimitSubscriber.php b/src/EventSubscriber/RateLimitSubscriber.php index a73a059ab..6690317b0 100644 --- a/src/EventSubscriber/RateLimitSubscriber.php +++ b/src/EventSubscriber/RateLimitSubscriber.php @@ -8,9 +8,11 @@ use App\Helper\I18nHelper; use DateInterval; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; @@ -34,9 +36,13 @@ class RateLimitSubscriber implements EventSubscriberInterface ]; protected CacheItemPoolInterface $cache; - protected ContainerInterface $container; protected I18nHelper $i18n; + protected LoggerInterface $crawlerLogger; + protected LoggerInterface $denylistLogger; + protected LoggerInterface $rateLimitLogger; + protected ParameterBagInterface $parameterBag; protected Request $request; + protected SessionInterface $session; /** @var int Number of requests allowed in time period */ protected int $rateLimit; @@ -54,16 +60,36 @@ class RateLimitSubscriber implements EventSubscriberInterface protected string $uri; /** - * Save the container for later use. - * @param ContainerInterface $container The DI container. * @param I18nHelper $i18n * @param CacheItemPoolInterface $cache + * @param ParameterBagInterface $parameterBag + * @param SessionInterface $session + * @param LoggerInterface $crawlerLogger + * @param LoggerInterface $denylistLogger + * @param LoggerInterface $rateLimitLogger + * @param int $rateLimit + * @param int $rateDuration */ - public function __construct(ContainerInterface $container, I18nHelper $i18n, CacheItemPoolInterface $cache) - { - $this->container = $container; + public function __construct( + I18nHelper $i18n, + CacheItemPoolInterface $cache, + ParameterBagInterface $parameterBag, + SessionInterface $session, + LoggerInterface $crawlerLogger, + LoggerInterface $denylistLogger, + LoggerInterface $rateLimitLogger, + int $rateLimit, + int $rateDuration + ) { $this->i18n = $i18n; $this->cache = $cache; + $this->parameterBag = $parameterBag; + $this->session = $session; + $this->crawlerLogger = $crawlerLogger; + $this->denylistLogger = $denylistLogger; + $this->rateLimitLogger = $rateLimitLogger; + $this->rateLimit = $rateLimit; + $this->rateDuration = $rateDuration; } /** @@ -96,8 +122,6 @@ public function onKernelController(ControllerEvent $event): void return; } - $this->rateLimit = (int)$this->container->getParameter('app.rate_limit_count'); - $this->rateDuration = (int)$this->container->getParameter('app.rate_limit_time'); $this->request = $event->getRequest(); $this->userAgent = (string)$this->request->headers->get('User-Agent'); $this->referer = (string)$this->request->headers->get('referer'); @@ -110,7 +134,7 @@ public function onKernelController(ControllerEvent $event): void return; } - $loggedIn = (bool)$this->container->get('session')->get('logged_in_user'); + $loggedIn = (bool)$this->session->get('logged_in_user'); $isApi = 'ApiAction' === substr($action, -9); // No rate limits on lightweight pages, logged in users, subrequests or API requests. @@ -134,7 +158,7 @@ private function xffRateLimit(): void return; } - $cacheKey = "ratelimit.session.".md5($xff); + $cacheKey = "ratelimit.session.".sha1($xff); $cacheItem = $this->cache->getItem($cacheKey); // If increment value already in cache, or start with 1. @@ -174,7 +198,7 @@ private function logCrawlers(): void // We're trying to check if everything BUT the uselang has remained unchanged. $cacheUri = str_replace('uselang='.$useLang, '', $this->uri); - $cacheKey = 'ratelimit.crawler.'.md5($this->userAgent.$cacheUri); + $cacheKey = 'ratelimit.crawler.'.sha1($this->userAgent.$cacheUri); $cacheItem = $this->cache->getItem($cacheKey); // If increment value already in cache, or start with 1. @@ -182,8 +206,7 @@ private function logCrawlers(): void // Check if limit has been exceeded, and if so, add a log entry. if ($count > 3) { - $logger = $this->container->get('monolog.logger.crawler'); - $logger->info('Possible crawler detected'); + $this->crawlerLogger->info('Possible crawler detected'); } // Reset the clock on every request. @@ -197,12 +220,12 @@ private function logCrawlers(): void */ private function checkDenylist(): void { - // First check user agent and URI blacklists - if (!$this->container->hasParameter('request_blacklist')) { + // First check user agent and URI denylists. + if (!$this->parameterBag->has('request_denylist')) { return; } - $denylist = (array)$this->container->getParameter('request_blacklist'); + $denylist = (array)$this->parameterBag->get('request_denylist'); foreach ($denylist as $name => $item) { $matches = []; @@ -242,7 +265,7 @@ private function checkDenylist(): void private function denyAccess(string $logComment, bool $denylist = false): void { // Log the denied request - $logger = $this->container->get($denylist ? 'monolog.logger.blacklist' : 'monolog.logger.rate_limit'); + $logger = $denylist ? $this->denylistLogger : $this->rateLimitLogger; $logger->info($logComment); if ($denylist) { diff --git a/src/Helper/AutomatedEditsHelper.php b/src/Helper/AutomatedEditsHelper.php index 228a7b233..d17028a23 100644 --- a/src/Helper/AutomatedEditsHelper.php +++ b/src/Helper/AutomatedEditsHelper.php @@ -8,33 +8,31 @@ use DateInterval; use MediaWiki\OAuthClient\Client; use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Session\SessionInterface; /** * Helper class for fetching semi-automated definitions. */ class AutomatedEditsHelper { + protected CacheItemPoolInterface $cache; + protected SessionInterface $session; + /** @var array The list of tools that are considered reverting. */ - protected $revertTools = []; + protected array $revertTools = []; /** @var array The list of tool names and their regexes/tags. */ - protected $tools = []; - - /** @var ContainerInterface */ - private $container; - - /** @var CacheItemPoolInterface */ - protected $cache; + protected array $tools = []; /** * AutomatedEditsHelper constructor. - * @param ContainerInterface $container + * @param SessionInterface $session + * @param CacheItemPoolInterface $cache */ - public function __construct(ContainerInterface $container) + public function __construct(SessionInterface $session, CacheItemPoolInterface $cache) { - $this->container = $container; - $this->cache = $container->get('cache.app'); + $this->session = $session; + $this->cache = $cache; } /** @@ -81,16 +79,15 @@ public function getConfig(bool $useSandbox = false): array return $this->cache->getItem($cacheKey)->get(); } - $session = $this->container->get('session'); $uri = 'https://meta.wikimedia.org/w/index.php?action=raw&ctype=application/json&title=' . 'MediaWiki:XTools-AutoEdits.json' . ($useSandbox ? '/sandbox' : ''); - if ($useSandbox && $session->get('logged_in_user')) { + if ($useSandbox && $this->session->get('logged_in_user')) { // Request via OAuth to get around server-side caching. /** @var Client $client */ - $client = $this->container->get('session')->get('oauth_client'); + $client = $this->session->get('oauth_client'); $resp = $client->makeOAuthCall( - $this->container->get('session')->get('oauth_access_token'), + $this->session->get('oauth_access_token'), $uri ); } else { @@ -112,7 +109,7 @@ public function getConfig(bool $useSandbox = false): array /** * Get list of automated tools and their associated info for the given project. - * This defaults to the 'default_project' if entries for the given project are not found. + * This defaults to the DEFAULT_PROJECT if entries for the given project are not found. * @param Project $project * @param bool $useSandbox Whether to use the /sandbox version for testing (also bypasses caching). * @return array Each tool with the tool name as the key and 'link', 'regex' and/or 'tag' as the subarray keys. diff --git a/src/Helper/I18nHelper.php b/src/Helper/I18nHelper.php index c80d69010..cb82fdde5 100644 --- a/src/Helper/I18nHelper.php +++ b/src/Helper/I18nHelper.php @@ -21,6 +21,7 @@ class I18nHelper { private Intuition $intuition; + private string $projectDir; protected ContainerInterface $container; protected IntlDateFormatter $dateFormatter; protected NumberFormatter $numFormatter; @@ -30,25 +31,25 @@ class I18nHelper /** * Constructor for the I18nHelper. - * @param ContainerInterface $container * @param RequestStack $requestStack * @param SessionInterface $session + * @param string $projectDir */ public function __construct( - ContainerInterface $container, RequestStack $requestStack, - SessionInterface $session + SessionInterface $session, + string $projectDir ) { - $this->container = $container; $this->requestStack = $requestStack; $this->session = $session; + $this->projectDir = $projectDir; } /** * Get an Intuition object, set to the current language based on the query string or session * of the current request. * @return Intuition - * @throws \Exception If the 'i18n/en.json' file doesn't exist (as it's the default). + * @throws Exception If the 'i18n/en.json' file doesn't exist (as it's the default). */ public function getIntuition(): Intuition { @@ -58,7 +59,7 @@ public function getIntuition(): Intuition } // Find the path, and complain if English doesn't exist. - $path = $this->container->getParameter('kernel.root_dir') . '/../i18n'; + $path = $this->projectDir . '/i18n'; if (!file_exists("$path/en.json")) { throw new Exception("Language directory doesn't exist: $path"); } @@ -110,7 +111,7 @@ public function getLangName(): string */ public function getAllLangs(): array { - $messageFiles = glob($this->container->getParameter('kernel.root_dir').'/../i18n/*.json'); + $messageFiles = glob($this->projectDir.'/i18n/*.json'); $languages = array_values(array_unique(array_map( function ($filename) { @@ -149,7 +150,7 @@ public function isRTL(?string $lang = null): bool */ public function getFallbacks(?string $useLang = null): array { - $i18nPath = $this->container->getParameter('kernel.root_dir').'/../i18n/'; + $i18nPath = $this->projectDir.'/i18n/'; $useLang = $useLang ?? $this->getLang(); $fallbacks = array_merge( @@ -172,7 +173,6 @@ public function getFallbacks(?string $useLang = null): array */ public function msg(?string $message, array $vars = []): ?string { - $vars = is_array($vars) ? $vars : []; return $this->getIntuition()->msg($message, ['domain' => 'xtools', 'variables' => $vars]); } @@ -186,7 +186,7 @@ public function msgExists(?string $message, array $vars = []): bool { return $this->getIntuition()->msgExists($message, array_merge( ['domain' => 'xtools'], - ['variables' => is_array($vars) ? $vars : []] + ['variables' => $vars] )); } @@ -324,6 +324,6 @@ private function getIntuitionLang(): string */ private function getRequest(): ?Request { - return $this->container->get('request_stack')->getCurrentRequest(); + return $this->requestStack->getCurrentRequest(); } } diff --git a/src/Model/ArticleInfo.php b/src/Model/ArticleInfo.php index f2273dd00..2be4e72c5 100644 --- a/src/Model/ArticleInfo.php +++ b/src/Model/ArticleInfo.php @@ -134,8 +134,8 @@ public function getDateParams(): array } /** - * Get the number of revisions that are actually getting processed. This goes by the app.max_page_revisions - * parameter, or the actual number of revisions, whichever is smaller. + * Get the number of revisions that are actually getting processed. This goes by the APP_MAX_PAGE_REVISIONS + * env variable, or the actual number of revisions, whichever is smaller. * @return int */ public function getNumRevisionsProcessed(): int diff --git a/src/Repository/AdminStatsRepository.php b/src/Repository/AdminStatsRepository.php index 9958a36c7..23f36a40b 100644 --- a/src/Repository/AdminStatsRepository.php +++ b/src/Repository/AdminStatsRepository.php @@ -20,7 +20,7 @@ class AdminStatsRepository extends Repository */ public function getUserGroupIcons(): array { - return $this->container->getParameter('user_group_icons'); + return $this->parameterBag->get('user_group_icons'); } /** @@ -115,7 +115,7 @@ private function getLogSqlParts(Project $project, string $type, array $requested */ public function getConfig(Project $project): array { - $config = $this->container->getParameter('admin_stats'); + $config = $this->parameterBag->get('admin_stats'); $extensions = $project->getInstalledExtensions(); foreach ($config as $type => $values) { @@ -142,7 +142,7 @@ public function getConfig(Project $project): array */ public function getRelevantUserGroup(string $type): string { - return $this->container->getParameter('admin_stats')[$type]['user_group']; + return $this->parameterBag->get('admin_stats')[$type]['user_group']; } /** @@ -158,7 +158,7 @@ public function getUserGroups(Project $project, string $type): array return $this->cache->getItem($cacheKey)->get(); } - $permissions = $this->container->getParameter('admin_stats')[$type]['permissions']; + $permissions = $this->parameterBag->get('admin_stats')[$type]['permissions']; $res = $this->executeApiRequest($project, [ 'meta' => 'siteinfo', @@ -170,11 +170,11 @@ public function getUserGroups(Project $project, string $type): array $userGroups = [ 'local' => array_unique(array_merge( $this->getUserGroupByLocality($res, $permissions), - $this->container->getParameter('admin_stats')[$type]['extra_user_groups'] + $this->parameterBag->get('admin_stats')[$type]['extra_user_groups'] )), 'global' => array_unique(array_merge( $this->getUserGroupByLocality($res, $permissions, true), - $this->container->getParameter('admin_stats')[$type]['extra_user_groups'] + $this->parameterBag->get('admin_stats')[$type]['extra_user_groups'] )), ]; diff --git a/src/Repository/ArticleInfoRepository.php b/src/Repository/ArticleInfoRepository.php index 1581b7e13..4ad50e410 100644 --- a/src/Repository/ArticleInfoRepository.php +++ b/src/Repository/ArticleInfoRepository.php @@ -7,10 +7,11 @@ use App\Model\Edit; use App\Model\Page; use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * ArticleInfoRepository is responsible for retrieving data about a single @@ -22,23 +23,26 @@ class ArticleInfoRepository extends Repository protected EditRepository $editRepo; protected UserRepository $userRepo; - /** @var int Maximum number of revisions to process, as configured via app.max_page_revisions */ + /** @var int Maximum number of revisions to process, as configured via APP_MAX_PAGE_REVISIONS */ protected int $maxPageRevisions; /** - * @param ContainerInterface $container + * @param ManagerRegistry $managerRegistry * @param CacheItemPoolInterface $cache * @param Client $guzzle * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag * @param bool $isWMF * @param int $queryTimeout * @param EditRepository $editRepo + * @param UserRepository $userRepo */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, EditRepository $editRepo, @@ -46,7 +50,7 @@ public function __construct( ) { $this->editRepo = $editRepo; $this->userRepo = $userRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** @@ -56,7 +60,7 @@ public function __construct( public function getMaxPageRevisions(): int { if (!isset($this->maxPageRevisions)) { - $this->maxPageRevisions = (int)$this->container->getParameter('app.max_page_revisions'); + $this->maxPageRevisions = (int)$this->parameterBag->get('app.max_page_revisions'); } return $this->maxPageRevisions; } diff --git a/src/Repository/AuthorshipRepository.php b/src/Repository/AuthorshipRepository.php index 53d033db3..c871177d9 100644 --- a/src/Repository/AuthorshipRepository.php +++ b/src/Repository/AuthorshipRepository.php @@ -6,7 +6,6 @@ use App\Model\Page; use App\Model\Project; -use GuzzleHttp; /** * AuthorshipRepository is responsible for retrieving authorship data about a single page. @@ -43,10 +42,7 @@ public function getData(Page $page, ?int $revId, bool $returnRevId = false): ?ar 'read_timeout' => 60, ]; - /** @var GuzzleHttp\Client $client */ - $client = $this->container->get('eight_points_guzzle.client.xtools'); - - $res = $client->request('GET', $url, $opts); + $res = $this->guzzle->request('GET', $url, $opts); // Cache and return. return $this->setCache($cacheKey, json_decode($res->getBody()->getContents(), true)); diff --git a/src/Repository/AutoEditsRepository.php b/src/Repository/AutoEditsRepository.php index dcd90445a..36866faf4 100644 --- a/src/Repository/AutoEditsRepository.php +++ b/src/Repository/AutoEditsRepository.php @@ -4,9 +4,16 @@ namespace App\Repository; +use App\Helper\AutomatedEditsHelper; use App\Model\Project; use App\Model\User; +use Doctrine\Persistence\ManagerRegistry; +use GuzzleHttp\Client; use PDO; +use Psr\Cache\CacheItemPoolInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Wikimedia\IPUtils; /** @@ -16,6 +23,8 @@ */ class AutoEditsRepository extends UserRepository { + protected AutomatedEditsHelper $autoEditsHelper; + /** @var array List of automated tools, used for fetching the tool list and filtering it. */ private array $aeTools; @@ -25,6 +34,44 @@ class AutoEditsRepository extends UserRepository /** @var array Process cache for tags/IDs. */ private array $tags; + /** + * @param ManagerRegistry $managerRegistry + * @param CacheItemPoolInterface $cache + * @param Client $guzzle + * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag + * @param bool $isWMF + * @param int $queryTimeout + * @param ProjectRepository $projectRepo + * @param AutomatedEditsHelper $autoEditsHelper + * @param SessionInterface $session + */ + public function __construct( + ManagerRegistry $managerRegistry, + CacheItemPoolInterface $cache, + Client $guzzle, + LoggerInterface $logger, + ParameterBagInterface $parameterBag, + bool $isWMF, + int $queryTimeout, + ProjectRepository $projectRepo, + AutomatedEditsHelper $autoEditsHelper, + SessionInterface $session + ) { + $this->autoEditsHelper = $autoEditsHelper; + parent::__construct( + $managerRegistry, + $cache, + $guzzle, + $logger, + $parameterBag, + $isWMF, + $queryTimeout, + $projectRepo, + $session + ); + } + /** * @param bool $useSandbox * @return AutoEditsRepository @@ -44,9 +91,7 @@ public function setUseSandbox(bool $useSandbox): AutoEditsRepository public function getTools(Project $project, $namespace = 'all'): array { if (!isset($this->aeTools)) { - $this->aeTools = $this->container - ->get('app.automated_edits_helper') - ->getTools($project, $this->useSandbox); + $this->aeTools = $this->autoEditsHelper->getTools($project, $this->useSandbox); } if ('all' !== $namespace) { diff --git a/src/Repository/BlameRepository.php b/src/Repository/BlameRepository.php index 70524c268..d3f09a882 100644 --- a/src/Repository/BlameRepository.php +++ b/src/Repository/BlameRepository.php @@ -6,10 +6,11 @@ use App\Model\Edit; use App\Model\Page; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * BlameRepository is responsible for retrieving authorship data about a single page. @@ -20,19 +21,31 @@ class BlameRepository extends AuthorshipRepository protected EditRepository $editRepo; protected UserRepository $userRepo; + /** + * @param ManagerRegistry $managerRegistry + * @param CacheItemPoolInterface $cache + * @param Client $guzzle + * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag + * @param bool $isWMF + * @param int $queryTimeout + * @param EditRepository $editRepo + * @param UserRepository $userRepo + */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, EditRepository $editRepo, UserRepository $userRepo ) { - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); $this->editRepo = $editRepo; $this->userRepo = $userRepo; + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** diff --git a/src/Repository/CategoryEditsRepository.php b/src/Repository/CategoryEditsRepository.php index 79624b96c..9112e146f 100644 --- a/src/Repository/CategoryEditsRepository.php +++ b/src/Repository/CategoryEditsRepository.php @@ -11,10 +11,11 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\ParameterType; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Wikimedia\IPUtils; /** @@ -30,10 +31,11 @@ class CategoryEditsRepository extends Repository protected UserRepository $userRepo; /** - * @param ContainerInterface $container + * @param ManagerRegistry $managerRegistry * @param CacheItemPoolInterface $cache * @param Client $guzzle * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag * @param bool $isWMF * @param int $queryTimeout * @param AutomatedEditsHelper $autoEditsHelper @@ -42,10 +44,11 @@ class CategoryEditsRepository extends Repository * @param UserRepository $userRepo */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, AutomatedEditsHelper $autoEditsHelper, @@ -53,11 +56,11 @@ public function __construct( PageRepository $pageRepo, UserRepository $userRepo ) { - $this->autoEditsHelper= $autoEditsHelper; + $this->autoEditsHelper = $autoEditsHelper; $this->editRepo = $editRepo; $this->pageRepo = $pageRepo; $this->userRepo = $userRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** diff --git a/src/Repository/EditCounterRepository.php b/src/Repository/EditCounterRepository.php index d0a6deb06..5143d9f0d 100644 --- a/src/Repository/EditCounterRepository.php +++ b/src/Repository/EditCounterRepository.php @@ -6,10 +6,11 @@ use App\Model\Project; use App\Model\User; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Wikimedia\IPUtils; /** @@ -21,34 +22,21 @@ class EditCounterRepository extends Repository { protected AutoEditsRepository $autoEditsRepo; protected ProjectRepository $projectRepo; - protected UserRightsRepository $userRightsRepo; - /** - * @param ContainerInterface $container - * @param CacheItemPoolInterface $cache - * @param Client $guzzle - * @param LoggerInterface $logger - * @param ProjectRepository $projectRepo - * @param UserRightsRepository $userRightsRepo - * @param AutoEditsRepository $autoEditsRepo - * @param bool $isWMF - * @param int $queryTimeout - */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, - ProjectRepository $projectRepo, - UserRightsRepository $userRightsRepo, - AutoEditsRepository $autoEditsRepo, + ParameterBagInterface $parameterBag, bool $isWMF, - int $queryTimeout + int $queryTimeout, + ProjectRepository $projectRepo, + AutoEditsRepository $autoEditsRepo ) { $this->projectRepo = $projectRepo; - $this->userRightsRepo = $userRightsRepo; $this->autoEditsRepo = $autoEditsRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** @@ -275,7 +263,7 @@ public function getFileCounts(Project $project, User $user): array */ protected function getFileCountsCommons(User $user): array { - $commonsProject = $this->projectRepo->getProject('commonswiki', $this->container); + $commonsProject = $this->projectRepo->getProject('commonswiki'); $loggingTableCommons = $commonsProject->getTableName('logging'); $sql = "(SELECT 'files_moved_commons' AS `key`, COUNT(log_id) AS `val` FROM $loggingTableCommons diff --git a/src/Repository/EditRepository.php b/src/Repository/EditRepository.php index 3c29f4031..9c9584279 100644 --- a/src/Repository/EditRepository.php +++ b/src/Repository/EditRepository.php @@ -8,10 +8,11 @@ use App\Model\Edit; use App\Model\Page; use App\Model\Project; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * An EditRepository fetches data about a single revision. @@ -22,21 +23,12 @@ class EditRepository extends Repository protected AutomatedEditsHelper $autoEditsHelper; protected PageRepository $pageRepo; - /** - * @param ContainerInterface $container - * @param CacheItemPoolInterface $cache - * @param Client $guzzle - * @param LoggerInterface $logger - * @param bool $isWMF - * @param int $queryTimeout - * @param AutomatedEditsHelper $autoEditsHelper - * @param PageRepository $pageRepo - */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, AutomatedEditsHelper $autoEditsHelper, @@ -44,7 +36,7 @@ public function __construct( ) { $this->autoEditsHelper = $autoEditsHelper; $this->pageRepo = $pageRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** diff --git a/src/Repository/GlobalContribsRepository.php b/src/Repository/GlobalContribsRepository.php index f0f30b72c..3efdcce3d 100644 --- a/src/Repository/GlobalContribsRepository.php +++ b/src/Repository/GlobalContribsRepository.php @@ -6,11 +6,12 @@ use App\Model\Project; use App\Model\User; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use PDO; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Wikimedia\IPUtils; /** @@ -25,20 +26,20 @@ class GlobalContribsRepository extends Repository protected Project $caProject; public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, - ProjectRepository $projectRepo + ProjectRepository $projectRepo, + string $centralAuthProject ) { - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); - $this->caProject = new Project( - $this->container->getParameter('central_auth_project') - ); + $this->caProject = new Project($centralAuthProject); $this->projectRepo = $projectRepo; $this->caProject->setRepository($this->projectRepo); + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** diff --git a/src/Repository/LargestPagesRepository.php b/src/Repository/LargestPagesRepository.php index dab0fc806..366b1bb11 100644 --- a/src/Repository/LargestPagesRepository.php +++ b/src/Repository/LargestPagesRepository.php @@ -6,10 +6,11 @@ use App\Model\Page; use App\Model\Project; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * A LargestPagesRepository is responsible for retrieving information from the database for the LargestPages tool. @@ -20,25 +21,27 @@ class LargestPagesRepository extends Repository protected PageRepository $pageRepo; /** - * @param ContainerInterface $container + * @param ManagerRegistry $managerRegistry * @param CacheItemPoolInterface $cache * @param Client $guzzle * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag * @param bool $isWMF * @param int $queryTimeout * @param PageRepository $pageRepo */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, PageRepository $pageRepo ) { $this->pageRepo = $pageRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** @var int Max rows to display. */ diff --git a/src/Repository/PageAssessmentsRepository.php b/src/Repository/PageAssessmentsRepository.php index 3269ccd83..e78eb84d2 100644 --- a/src/Repository/PageAssessmentsRepository.php +++ b/src/Repository/PageAssessmentsRepository.php @@ -25,7 +25,7 @@ class PageAssessmentsRepository extends Repository public function getConfig(Project $project): ?array { if (!isset($this->assessments)) { - $this->assessments = $this->container->getParameter('assessments'); + $this->assessments = $this->parameterBag->get('assessments'); } return $this->assessments[$project->getDomain()] ?? null; } @@ -43,8 +43,8 @@ public function getAssessments(Page $page, bool $first = false): array return $this->cache->getItem($cacheKey)->get(); } - $paTable = $this->getTableName($page->getProject()->getDatabaseName(), 'page_assessments'); - $papTable = $this->getTableName($page->getProject()->getDatabaseName(), 'page_assessments_projects'); + $paTable = $page->getProject()->getTableName('page_assessments'); + $papTable = $page->getProject()->getTableName('page_assessments_projects'); $pageId = $page->getId(); $sql = "SELECT pap_project_title AS wikiproject, pa_class AS class, pa_importance AS importance diff --git a/src/Repository/PageRepository.php b/src/Repository/PageRepository.php index 5cc1de288..1c4007ca7 100644 --- a/src/Repository/PageRepository.php +++ b/src/Repository/PageRepository.php @@ -9,7 +9,6 @@ use App\Model\User; use DateTime; use Doctrine\DBAL\Driver\ResultStatement; -use GuzzleHttp; /** * A PageRepository fetches data about Pages, either singularly or for multiple. @@ -376,9 +375,6 @@ public function getPageviews(Page $page, $start, $end): array { $title = rawurlencode(str_replace(' ', '_', $page->getTitle())); - /** @var GuzzleHttp\Client $client */ - $client = $this->container->get('eight_points_guzzle.client.xtools'); - if ($start instanceof DateTime) { $start = $start->format('Ymd'); } else { @@ -395,7 +391,7 @@ public function getPageviews(Page $page, $start, $end): array $url = 'https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/' . "$project/all-access/user/$title/daily/$start/$end"; - $res = $client->request('GET', $url); + $res = $this->guzzle->request('GET', $url); return json_decode($res->getBody()->getContents(), true); } @@ -407,13 +403,11 @@ public function getPageviews(Page $page, $start, $end): array */ public function getHTMLContent(Page $page, ?int $revId = null): string { - /** @var GuzzleHttp\Client $client */ - $client = $this->container->get('eight_points_guzzle.client.xtools'); $url = $page->getUrl(); if (null !== $revId) { $url .= "?oldid=$revId"; } - return $client->request('GET', $url) + return $this->guzzle->request('GET', $url) ->getBody() ->getContents(); } @@ -448,14 +442,12 @@ public function getRevisionIdAtDate(Page $page, DateTime $date): int */ public function displayTitles(Project $project, array $pageTitles): array { - $client = $this->container->get('eight_points_guzzle.client.xtools'); - $displayTitles = []; $numPages = count($pageTitles); for ($n = 0; $n < $numPages; $n += 50) { $titleSlice = array_slice($pageTitles, $n, 50); - $res = $client->request('GET', $project->getApiUrl(), ['query' => [ + $res = $this->guzzle->request('GET', $project->getApiUrl(), ['query' => [ 'action' => 'query', 'prop' => 'info|pageprops', 'inprop' => 'displaytitle', diff --git a/src/Repository/ProjectRepository.php b/src/Repository/ProjectRepository.php index 91b2a1a46..ae8a36d0b 100644 --- a/src/Repository/ProjectRepository.php +++ b/src/Repository/ProjectRepository.php @@ -7,11 +7,12 @@ use App\Model\PageAssessments; use App\Model\Project; use Doctrine\DBAL\Connection; +use Doctrine\Persistence\ManagerRegistry; use Exception; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * This class provides data to the Project class. @@ -33,17 +34,52 @@ class ProjectRepository extends Repository /** @var string The cache key for the 'all project' metadata. */ protected string $cacheKeyAllProjects = 'allprojects'; + /** @var string The configured default project. */ + protected string $defaultProject; + + /** @var bool Whether XTools is configured to run on a single wiki or not. */ + protected bool $singleWiki; + + /** @var array Projects that have opted into showing restricted stats to everyone. */ + protected array $optedIn; + + /** @var string The project's API path. */ + protected string $apiPath; + + /** + * @param ManagerRegistry $managerRegistry + * @param CacheItemPoolInterface $cache + * @param Client $guzzle + * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag + * @param bool $isWMF + * @param int $queryTimeout + * @param PageAssessmentsRepository $assessmentsRepo + * @param string $defaultProject + * @param bool $singleWiki + * @param array $optedIn + * @param string $apiPath + */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, - PageAssessmentsRepository $assessmentsRepo + PageAssessmentsRepository $assessmentsRepo, + string $defaultProject, + bool $singleWiki, + array $optedIn, + string $apiPath ) { $this->assessmentsRepo = $assessmentsRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); + $this->defaultProject = $defaultProject; + $this->singleWiki = $singleWiki; + $this->optedIn = $optedIn; + $this->apiPath = $apiPath; + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** @@ -57,12 +93,12 @@ public function getProject(string $projectIdent): Project $project->setRepository($this); $project->setPageAssessments(new PageAssessments($this->assessmentsRepo, $project)); - if ($this->container->getParameter('app.single_wiki')) { + if ($this->singleWiki) { $this->setSingleBasicInfo([ - 'url' => $this->container->getParameter('wiki_url'), + 'url' => $this->parameterBag->get('wiki_url'), 'dbName' => '', // Just so this will pass in CI. // TODO: this will need to be restored for third party support; KEYWORD: isWMF - // 'dbName' => $container->getParameter('database_replica_name'), + // 'dbName' => $this->parameterBag->('database_replica_name'), ]); } @@ -75,8 +111,7 @@ public function getProject(string $projectIdent): Project */ public function getDefaultProject(): Project { - $defaultProjectName = $this->container->getParameter('default_project'); - return $this->getProject($defaultProjectName); + return $this->getProject($this->defaultProject); } /** @@ -128,9 +163,9 @@ public function getAll(): array return $this->cache->getItem($this->cacheKeyAllProjects)->get(); } - if ($this->container->hasParameter("database_meta_table")) { - $table = $this->container->getParameter('database_meta_name') . '.' . - $this->container->getParameter('database_meta_table'); + if ($this->parameterBag->has("database_meta_table")) { + $table = $this->parameterBag->get('database_meta_name') . '.' . + $this->parameterBag->get('database_meta_table'); } else { $table = "meta_p.wiki"; } @@ -324,12 +359,7 @@ private function setNamespaces(array $res): void */ public function optedIn(): array { - $optedIn = $this->container->getParameter('opted_in'); - // In case there's just one given. - if (!is_array($optedIn)) { - $optedIn = [ $optedIn ]; - } - return $optedIn; + return $this->optedIn; } /** @@ -338,7 +368,7 @@ public function optedIn(): array */ public function getApiPath(): string { - return $this->container->getParameter('api_path'); + return $this->apiPath; } /** diff --git a/src/Repository/Repository.php b/src/Repository/Repository.php index 481a7ba2d..270307b7f 100644 --- a/src/Repository/Repository.php +++ b/src/Repository/Repository.php @@ -7,14 +7,14 @@ use App\Model\Project; use DateInterval; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; @@ -25,43 +25,49 @@ abstract class Repository { protected CacheItemPoolInterface $cache; - protected ContainerInterface $container; protected Client $guzzle; protected LoggerInterface $logger; + protected ManagerRegistry $managerRegistry; + protected ParameterBagInterface $parameterBag; /** @var Connection The database connection to the meta database. */ - private $metaConnection; + private Connection $metaConnection; /** @var Connection The database connection to other tools' databases. */ - private $toolsConnection; + private Connection $toolsConnection; /** @var bool Whether this is configured as a WMF installation. */ - protected $isWMF; + protected bool $isWMF; /** @var int */ - protected $queryTimeout; + protected int $queryTimeout; /** @var string Prefix URL for where the dblists live. Will be followed by i.e. 's1.dblist' */ public const DBLISTS_URL = 'https://noc.wikimedia.org/conf/dblists/'; /** * Create a new Repository. - * @param ContainerInterface $container - * @param CacheItemPoolInterface $cache + * @param ManagerRegistry $managerRegistry * @param Client $guzzle + * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag + * @param bool $isWMF + * @param int $queryTimeout */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout ) { - $this->container = $container; + $this->managerRegistry = $managerRegistry; $this->cache = $cache; $this->guzzle = $guzzle; $this->logger = $logger; + $this->parameterBag = $parameterBag; $this->isWMF = $isWMF; $this->queryTimeout = $queryTimeout; } @@ -77,7 +83,7 @@ public function __construct( */ protected function getMetaConnection(): Connection { - if (!$this->metaConnection instanceof Connection) { + if (!isset($this->metaConnection)) { $this->metaConnection = $this->getProjectsConnection('meta'); } return $this->metaConnection; @@ -103,8 +109,7 @@ protected function getProjectsConnection($project): Connection $slice = $this->getDbList()[$project->getDatabaseName()]; } - return $this->container->get('doctrine') - ->getConnection('toolforge_'.$slice); + return $this->managerRegistry->getConnection('toolforge_'.$slice); } /** @@ -114,11 +119,8 @@ protected function getProjectsConnection($project): Connection */ protected function getToolsConnection(): Connection { - if (!$this->toolsConnection instanceof Connection) { - $this->toolsConnection = $this->container - ->get('doctrine') - ->getManager('toolsdb') - ->getConnection(); + if (!isset($this->toolsConnection)) { + $this->toolsConnection = $this->managerRegistry->getConnection('toolsdb'); } return $this->toolsConnection; } @@ -208,10 +210,10 @@ public function getTableName(string $databaseName, string $tableName, ?string $t if ($this->isWMF && null !== $tableExtension) { $mapped = true; $tableName .=('' === $tableExtension ? '' : '_'.$tableExtension); - } elseif ($this->container->hasParameter("app.table.$tableName")) { + } elseif ($this->parameterBag->has("app.table.$tableName")) { // Use the table specified in the table mapping configuration, if present. $mapped = true; - $tableName = $this->container->getParameter("app.table.$tableName"); + $tableName = $this->parameterBag->get("app.table.$tableName"); } // For 'revision' and 'logging' tables (actually views) on Labs, use the indexed versions @@ -267,7 +269,7 @@ public function getCacheKey($args, ?string $key = null): string } // Remove reserved characters. - return preg_replace('/[{}()\/\@\:"]/', '', $cacheKey); + return preg_replace('/[{}()\/@:"]/', '', $cacheKey); } /** @@ -330,16 +332,16 @@ public function getDateConditions( if (is_int($start)) { // Convert to YYYYMMDDHHMMSS. $start = date('Ymd', $start).'000000'; - $datesConditions .= " AND {$tableAlias}{$field} >= '$start'"; + $datesConditions .= " AND $tableAlias{$field} >= '$start'"; } // When we're given an $offset, it basically replaces $end, except it's also a full timestamp. if (is_int($offset)) { $offset = date('YmdHis', $offset); - $datesConditions .= " AND {$tableAlias}{$field} <= '$offset'"; + $datesConditions .= " AND $tableAlias{$field} <= '$offset'"; } elseif (is_int($end)) { $end = date('Ymd', $end) . '235959'; - $datesConditions .= " AND {$tableAlias}{$field} <= '$end'"; + $datesConditions .= " AND $tableAlias{$field} <= '$end'"; } return $datesConditions; @@ -351,10 +353,9 @@ public function getDateConditions( * @param string $sql * @param array $params Parameters to bound to the prepared query. * @param int|null $timeout Maximum statement time in seconds. null will use the - * default specified by the app.query_timeout config parameter. + * default specified by the APP_QUERY_TIMEOUT env variable. * @return ResultStatement * @throws DriverException - * @throws DBALException * @codeCoverageIgnore */ public function executeProjectsQuery( @@ -377,7 +378,7 @@ public function executeProjectsQuery( * Execute a query using the projects connection, handling certain Exceptions. * @param QueryBuilder $qb * @param int|null $timeout Maximum statement time in seconds. null will use the - * default specified by the app.query_timeout config parameter. + * default specified by the APP_QUERY_TIMEOUT env variable. * @return ResultStatement * @throws HttpException * @throws DriverException @@ -386,7 +387,7 @@ public function executeProjectsQuery( public function executeQueryBuilder(QueryBuilder $qb, ?int $timeout = null): ResultStatement { try { - $timeout = $timeout ?? $this->container->getParameter('app.query_timeout'); + $timeout = $timeout ?? $this->queryTimeout; $sql = "SET STATEMENT max_statement_time = $timeout FOR\n".$qb->getSQL(); return $qb->getConnection()->executeQuery($sql, $qb->getParameters(), $qb->getParameterTypes()); } catch (DriverException $e) { diff --git a/src/Repository/TopEditsRepository.php b/src/Repository/TopEditsRepository.php index 0b3402cca..447d71b6c 100644 --- a/src/Repository/TopEditsRepository.php +++ b/src/Repository/TopEditsRepository.php @@ -8,11 +8,13 @@ use App\Model\Page; use App\Model\Project; use App\Model\User; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use PDO; use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Wikimedia\IPUtils; /** @@ -26,20 +28,45 @@ class TopEditsRepository extends UserRepository protected EditRepository $editRepo; protected UserRepository $userRepo; + /** + * @param ManagerRegistry $managerRegistry + * @param CacheItemPoolInterface $cache + * @param Client $guzzle + * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag + * @param bool $isWMF + * @param int $queryTimeout + * @param ProjectRepository $projectRepo + * @param EditRepository $editRepo + * @param UserRepository $userRepo + * @param SessionInterface $session + */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, + ProjectRepository $projectRepo, EditRepository $editRepo, UserRepository $userRepo, - ProjectRepository $projectRepo + SessionInterface $session ) { $this->editRepo = $editRepo; $this->userRepo = $userRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout, $projectRepo); + parent::__construct( + $managerRegistry, + $cache, + $guzzle, + $logger, + $parameterBag, + $isWMF, + $queryTimeout, + $projectRepo, + $session + ); } /** diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index 6e3c26ce2..a36e653bb 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -7,11 +7,12 @@ use App\Model\Project; use App\Model\User; use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Wikimedia\IPUtils; /** @@ -21,27 +22,33 @@ class UserRepository extends Repository { protected ProjectRepository $projectRepo; + protected SessionInterface $session; /** - * @param ContainerInterface $container + * @param ManagerRegistry $managerRegistry * @param CacheItemPoolInterface $cache * @param Client $guzzle * @param LoggerInterface $logger + * @param ParameterBagInterface $parameterBag * @param bool $isWMF * @param int $queryTimeout * @param ProjectRepository $projectRepo + * @param SessionInterface $session */ public function __construct( - ContainerInterface $container, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, Client $guzzle, LoggerInterface $logger, + ParameterBagInterface $parameterBag, bool $isWMF, int $queryTimeout, - ProjectRepository $projectRepo + ProjectRepository $projectRepo, + SessionInterface $session ) { $this->projectRepo = $projectRepo; - parent::__construct($container, $cache, $guzzle, $logger, $isWMF, $queryTimeout); + $this->session = $session; + parent::__construct($managerRegistry, $cache, $guzzle, $logger, $parameterBag, $isWMF, $queryTimeout); } /** @@ -187,9 +194,7 @@ public function countEdits(Project $project, User $user, $namespace = 'all', $st */ public function getXtoolsUserInfo() { - /** @var Session $session */ - $session = $this->container->get('session'); - return $session->get('logged_in_user'); + return $this->session->get('logged_in_user'); } /** @@ -198,7 +203,7 @@ public function getXtoolsUserInfo() */ public function maxEdits(): int { - return (int)$this->container->getParameter('app.max_user_edits'); + return (int)$this->parameterBag->get('app.max_user_edits'); } /** diff --git a/src/Repository/UserRightsRepository.php b/src/Repository/UserRightsRepository.php index be98018a3..a8bd4610c 100644 --- a/src/Repository/UserRightsRepository.php +++ b/src/Repository/UserRightsRepository.php @@ -25,7 +25,7 @@ public function getRightsChanges(Project $project, User $user): array { $changes = $this->queryRightsChanges($project, $user); - if ((bool)$this->container->hasParameter('app.is_wmf')) { + if ($this->isWMF) { $changes = array_merge( $changes, $this->queryRightsChanges($project, $user, 'meta') diff --git a/src/Twig/AppExtension.php b/src/Twig/AppExtension.php index 0080d2340..d9d4b08f0 100644 --- a/src/Twig/AppExtension.php +++ b/src/Twig/AppExtension.php @@ -10,7 +10,7 @@ use App\Model\User; use App\Repository\ProjectRepository; use DateTime; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -25,41 +25,52 @@ */ class AppExtension extends AbstractExtension { - protected ContainerInterface $container; protected I18nHelper $i18n; + protected ParameterBagInterface $parameterBag; protected ProjectRepository $projectRepo; protected RequestStack $requestStack; protected SessionInterface $session; protected UrlGeneratorInterface $urlGenerator; + protected bool $isWMF; + protected int $replagThreshold; + protected bool $singleWiki; + /** @var float Duration of the current HTTP request in seconds. */ protected float $requestTime; - protected bool $isWMF; /** * Constructor, with the I18nHelper through dependency injection. - * @param ContainerInterface $container * @param RequestStack $requestStack * @param SessionInterface $session * @param I18nHelper $i18n * @param UrlGeneratorInterface $generator + * @param ProjectRepository $projectRepo + * @param ParameterBagInterface $parameterBag + * @param bool $isWMF + * @param bool $singleWiki + * @param int $replagThreshold */ public function __construct( - ContainerInterface $container, RequestStack $requestStack, SessionInterface $session, I18nHelper $i18n, UrlGeneratorInterface $generator, ProjectRepository $projectRepo, - bool $isWMF + ParameterBagInterface $parameterBag, + bool $isWMF, + bool $singleWiki, + int $replagThreshold ) { - $this->container = $container; $this->requestStack = $requestStack; $this->session = $session; $this->i18n = $i18n; $this->urlGenerator = $generator; $this->projectRepo = $projectRepo; + $this->parameterBag = $parameterBag; $this->isWMF = $isWMF; + $this->singleWiki = $singleWiki; + $this->replagThreshold = $replagThreshold; } /*********************************** FUNCTIONS ***********************************/ @@ -247,8 +258,8 @@ public function gitDate(): string public function toolEnabled(string $tool = 'index'): bool { $param = false; - if ($this->container->hasParameter("enable.$tool")) { - $param = boolval($this->container->getParameter("enable.$tool")); + if ($this->parameterBag->has("enable.$tool")) { + $param = (bool)$this->parameterBag->get("enable.$tool"); } return $param; } @@ -259,11 +270,7 @@ public function toolEnabled(string $tool = 'index'): bool */ public function tools(): array { - $retVal = []; - if ($this->container->hasParameter('tools')) { - $retVal = $this->container->getParameter('tools'); - } - return $retVal; + return $this->parameterBag->get('tools'); } /** @@ -396,11 +403,7 @@ public function chartColor(int $num): string */ public function isSingleWiki(): bool { - $param = true; - if ($this->container->hasParameter('app.single_wiki')) { - $param = (bool)$this->container->getParameter('app.single_wiki'); - } - return $param; + return $this->singleWiki; } /** @@ -409,11 +412,7 @@ public function isSingleWiki(): bool */ public function getReplagThreshold(): int { - $param = 30; - if ($this->container->hasParameter('app.replag_threshold')) { - $param = $this->container->getParameter('app.replag_threshold'); - } - return $param; + return $this->replagThreshold; } /** @@ -449,10 +448,10 @@ public function quote(): string { // Don't show if Quote is turned off, but always show for WMF // (so quote is in footer but not in nav). - if (!$this->isWMF && !$this->container->getParameter('enable.Quote')) { + if (!$this->isWMF && !$this->parameterBag->get('enable.Quote')) { return ''; } - $quotes = $this->container->getParameter('quotes'); + $quotes = $this->parameterBag->get('quotes'); $id = array_rand($quotes); return $quotes[$id]; } @@ -463,7 +462,7 @@ public function quote(): string */ public function loggedInUser() { - return $this->container->get('session')->get('logged_in_user'); + return $this->session->get('logged_in_user'); } /** diff --git a/symfony.lock b/symfony.lock new file mode 100644 index 000000000..bb39be9af --- /dev/null +++ b/symfony.lock @@ -0,0 +1,260 @@ +{ + "doctrine/annotations": { + "version": "1.14", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.10", + "ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05" + } + }, + "doctrine/doctrine-bundle": { + "version": "2.7", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.4", + "ref": "013b823e7fee65890b23e40f31e6667a1ac519ac" + }, + "files": [ + "config/packages/doctrine.yaml", + "src/Entity/.gitignore", + "src/Repository/.gitignore" + ] + }, + "doctrine/doctrine-migrations-bundle": { + "version": "2.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.2", + "ref": "baaa439e3e3179e69e3da84b671f0a3e4a2f56ad" + }, + "files": [ + "config/packages/doctrine_migrations.yaml", + "migrations/.gitignore" + ] + }, + "eightpoints/guzzle-bundle": { + "version": "7.6", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "7.0", + "ref": "7babb21a3928e44e485391907e3abc346804e0d2" + }, + "files": [ + "config/packages/eight_points_guzzle.yaml" + ] + }, + "jms/serializer-bundle": { + "version": "3.10", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "3.0", + "ref": "384cec52df45f3bfd46a09930d6960a58872b268" + }, + "files": [ + "config/packages/dev/jms_serializer.yaml", + "config/packages/jms_serializer.yaml", + "config/packages/prod/jms_serializer.yaml" + ] + }, + "nelmio/cors-bundle": { + "version": "1.5", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.5", + "ref": "6bea22e6c564fba3a1391615cada1437d0bde39c" + }, + "files": [ + "config/packages/nelmio_cors.yaml" + ] + }, + "phpunit/phpunit": { + "version": "9.6", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "9.3", + "ref": "a6249a6c4392e9169b87abf93225f7f9f59025e6" + }, + "files": [ + ".env.test", + "phpunit.xml.dist", + "tests/bootstrap.php" + ] + }, + "sensio/framework-extra-bundle": { + "version": "5.6", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.2", + "ref": "fb7e19da7f013d0d422fa9bce16f5c510e27609b" + }, + "files": [ + "config/packages/sensio_framework_extra.yaml" + ] + }, + "squizlabs/php_codesniffer": { + "version": "3.7", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "3.6", + "ref": "1019e5c08d4821cb9b77f4891f8e9c31ff20ac6f" + }, + "files": [ + "phpcs.xml.dist" + ] + }, + "symfony/console": { + "version": "4.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "4.4", + "ref": "fd5340d07d4c90504843b53da41525cf42e31f5c" + }, + "files": [ + "bin/console", + "config/bootstrap.php" + ] + }, + "symfony/flex": { + "version": "1.19", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" + }, + "files": [ + ".env" + ] + }, + "symfony/framework-bundle": { + "version": "4.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "4.4", + "ref": "24eb45d1355810154890460e6a05c0ca27318fe7" + }, + "files": [ + "config/bootstrap.php", + "config/packages/cache.yaml", + "config/packages/framework.yaml", + "config/packages/test/framework.yaml", + "config/preload.php", + "config/routes/dev/framework.yaml", + "config/services.yaml", + "public/index.php", + "src/Controller/.gitignore", + "src/Kernel.php" + ] + }, + "symfony/mailer": { + "version": "4.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "4.3", + "ref": "2bf89438209656b85b9a49238c4467bff1b1f939" + }, + "files": [ + "config/packages/mailer.yaml" + ] + }, + "symfony/monolog-bundle": { + "version": "3.8", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.7", + "ref": "213676c4ec929f046dfde5ea8e97625b81bc0578" + }, + "files": [ + "config/packages/monolog.yaml" + ] + }, + "symfony/phpunit-bridge": { + "version": "4.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "4.3", + "ref": "170ab6f9abd4e1dab87462847116659ae138c34e" + }, + "files": [ + ".env.test", + "bin/phpunit", + "phpunit.xml.dist", + "tests/bootstrap.php" + ] + }, + "symfony/routing": { + "version": "5.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.1", + "ref": "8c5b5f86ec3e4547cec9a3ae30c3b40ae51cab1f" + }, + "files": [ + "config/packages/prod/routing.yaml", + "config/packages/routing.yaml", + "config/routes.yaml" + ] + }, + "symfony/twig-bundle": { + "version": "4.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "4.4", + "ref": "73baff3f7b3cea12a73812a7cfd2c0924a9e250f" + }, + "files": [ + "config/packages/test/twig.yaml", + "config/packages/twig.yaml", + "templates/base.html.twig" + ] + }, + "symfony/web-profiler-bundle": { + "version": "4.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.3", + "ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6" + }, + "files": [ + "config/packages/dev/web_profiler.yaml", + "config/packages/test/web_profiler.yaml", + "config/routes/dev/web_profiler.yaml" + ] + }, + "symfony/webpack-encore-bundle": { + "version": "1.16", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.10", + "ref": "f8fc53f1942f76679e9ee3c25fd44865355707b5" + }, + "files": [ + "assets/app.js", + "assets/bootstrap.js", + "assets/controllers.json", + "assets/controllers/hello_controller.js", + "assets/styles/app.css", + "config/packages/webpack_encore.yaml", + "package.json", + "webpack.config.js" + ] + } +} diff --git a/templates/rfxAnalysis/index.html.twig b/templates/rfxAnalysis/index.html.twig deleted file mode 100644 index 2da1d6501..000000000 --- a/templates/rfxAnalysis/index.html.twig +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "base.html.twig" %} -{% import 'macros/forms.html.twig' as forms %} - -{% block body %} -
-
-
- {{ msg('project') }} - -
- {{ forms.user_input(true, false, null, true) }} -
- {{ forms.submit_btn() }} -
-{% endblock %} diff --git a/templates/rfxAnalysis/result.html.twig b/templates/rfxAnalysis/result.html.twig deleted file mode 100644 index 121304491..000000000 --- a/templates/rfxAnalysis/result.html.twig +++ /dev/null @@ -1,103 +0,0 @@ -{% extends 'base.html.twig' %} -{% import 'macros/layout.html.twig' as layout %} -{% import 'macros/wiki.html.twig' as wiki %} - -{% block body %} -
-
-
- - - {{ msg('back') }} - - {{ wiki.pageLink(page) }} - - • - {{ project.domain }} - -
-
-
- {{ wiki.userLinks(user, project, xtPage) }} - - {% set content %} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ msg('user') }}{{ wiki.userLink(user, project) }}
{{ msg('type') }}{{ type|upper }}
{{ msg('support') }} - {{ support|length }} - ({{ support|length|percent_format(total) }}) -
{{ msg('oppose') }} - {{ oppose|length }} - ({{ oppose|length|percent_format(total) }}) -
{{ msg('neutral') }} - {{ neutral|length }} - ({{ neutral|length|percent_format(total) }}) -
{{ msg('end') }}{{ enddate }}
{{ msg('rfx-duplicates') }} - {{ duplicates|length|num_format }} -
-
- {% endset %} - {{ layout.content_block('summary', content) }} - - {% set content %} -
    - {% for username in support %} -
  1. - {{ wiki.userLink(username, project) }} - {% if username in duplicates %} - ({{ msg("duplicate-vote")|lower }}) - {% endif %} -
  2. - {% endfor %} -
- {% endset %} - {{ layout.content_block('support', content) }} - - {% set content %} -
    - {% for username in oppose %} -
  1. {{ wiki.userLink(username, project) }}
  2. - {% endfor %} -
- {% endset %} - {{ layout.content_block('oppose', content) }} - - {% set content %} -
    - {% for username in neutral %} -
  1. {{ wiki.userLink(username, project) }}
  2. - {% endfor %} -
- {% endset %} - {{ layout.content_block('neutral', content) }} -
-
-{% endblock %} diff --git a/templates/rfxVoteCalculator/index.html.twig b/templates/rfxVoteCalculator/index.html.twig deleted file mode 100644 index 68a2e7a2c..000000000 --- a/templates/rfxVoteCalculator/index.html.twig +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'base.html.twig' %} -{% import 'macros/forms.html.twig' as forms %} - -{% block body %} -
-
- {{ forms.wiki_input(project) }} - {{ forms.user_input(true, false, project, true) }} -
- {{ forms.submit_btn() }} -
-{% endblock %} diff --git a/templates/rfxVoteCalculator/result.html.twig b/templates/rfxVoteCalculator/result.html.twig deleted file mode 100644 index 3d309f1f5..000000000 --- a/templates/rfxVoteCalculator/result.html.twig +++ /dev/null @@ -1,89 +0,0 @@ -{% extends 'base.html.twig' %} -{% import 'macros/layout.html.twig' as layout %} -{% import 'macros/wiki.html.twig' as wiki %} -{% import 'macros/pieChart.html.twig' as pie %} - -{% block body %} -
- {{ layout.userHeading(user, project, xtPage) }} - -
- {{ wiki.userLinks(user, project, xtPage) }} - - {% set content %} -
-
- {% endset %} - {{ layout.content_block('summary', content) }} - - {% for type in data|keys %} - {% set content %} - {# TODO: Pie chart here #} -
- - - - - - - - - - {% for voteType in data[type]|keys %} - {% set count = totals[type][voteType] is defined ? totals[type][voteType]|num_format : 0 %} - - - - - {% endfor %} -
{{ msg('considered-usernames') }}
{{ msg('rfx-total-votes') }} - {{ totals[type].total|num_format }} -
{{ msg(voteType) }} - {{ count }} ({{ count|percent_format(totals[type].total) }}) -
-
- - {% for vote in data[type]|keys %} -

{{ vote|title }}

- - - {% for key in ['index', 'date', 'rfx-tally', 'user'] %} - - {% endfor %} - - {% for pagename in data[type][vote]|keys %} - {% set parsedData = data[type][vote][pagename] %} - - - - {# FIXME: assume support/oppose/neutral sections #} - {% set tally = parsedData.Support + parsedData.Oppose + parsedData.Neutral %} - - - - {% endfor %} -
- - {% if key == 'index' %} - # - {% else %} - {{ msg(key)|ucfirst }} - {% endif %} - - -
{{ loop.index }} - {{ parsedData.Support }} / - {{ parsedData.Oppose }} / - {{ parsedData.Neutral }} - - {{ wiki.pageLinkRaw(pagename, project, parsedData.name) }} -
- {% endfor %} - {% endset %} - {{ layout.content_block(type, content, '', type, true) }} - {% endfor %} -
-
-{% endblock %} \ No newline at end of file diff --git a/tests/Controller/OverridableXtoolsController.php b/tests/Controller/OverridableXtoolsController.php index 9f0a8edd5..665c29000 100644 --- a/tests/Controller/OverridableXtoolsController.php +++ b/tests/Controller/OverridableXtoolsController.php @@ -9,10 +9,12 @@ use App\Repository\PageRepository; use App\Repository\ProjectRepository; use App\Repository\UserRepository; +use Doctrine\Persistence\ManagerRegistry; use GuzzleHttp\Client; use Psr\Cache\CacheItemPoolInterface; use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; /** * This class can be used in unit tests where you need to override methods @@ -25,28 +27,52 @@ class OverridableXtoolsController extends XtoolsController protected array $overrides = []; /** - * @param RequestStack $requestStack * @param ContainerInterface $container + * @param RequestStack $requestStack + * @param ManagerRegistry $managerRegistry * @param CacheItemPoolInterface $cache + * @param FlashBagInterface $flashBag * @param Client $guzzle * @param I18nHelper $i18n * @param ProjectRepository $projectRepo * @param UserRepository $userRepo * @param PageRepository $pageRepo + * @param bool $isWMF + * @param string $defaultProject + * @param array $multilingualWikis * @param string[] $overrides Keys are method names, values are what they should return. */ public function __construct( - RequestStack $requestStack, ContainerInterface $container, + RequestStack $requestStack, + ManagerRegistry $managerRegistry, CacheItemPoolInterface $cache, + FlashBagInterface $flashBag, Client $guzzle, I18nHelper $i18n, ProjectRepository $projectRepo, UserRepository $userRepo, PageRepository $pageRepo, + bool $isWMF, + string $defaultProject, + array $multilingualWikis, array $overrides = [] ) { - parent::__construct($requestStack, $container, $cache, $guzzle, $i18n, $projectRepo, $userRepo, $pageRepo); + parent::__construct( + $container, + $requestStack, + $managerRegistry, + $cache, + $flashBag, + $guzzle, + $i18n, + $projectRepo, + $userRepo, + $pageRepo, + $isWMF, + $defaultProject, + $multilingualWikis + ); $this->overrides = $overrides; } diff --git a/tests/Controller/XtoolsControllerTest.php b/tests/Controller/XtoolsControllerTest.php index 88e8ca547..2eb07eefb 100644 --- a/tests/Controller/XtoolsControllerTest.php +++ b/tests/Controller/XtoolsControllerTest.php @@ -44,14 +44,19 @@ private function getControllerWithRequest(array $requestParams = [], array $meth $requestStack->push(new Request($requestParams)); return new OverridableXtoolsController( - $requestStack, self::$container, + $requestStack, + self::$container->get('doctrine'), self::$container->get('cache.app'), + self::$container->get('session')->getFlashBag(), self::$container->get('eight_points_guzzle.client.xtools'), $this->i18n, self::$container->get('App\Repository\ProjectRepository'), self::$container->get('App\Repository\UserRepository'), self::$container->get('App\Repository\PageRepository'), + self::$container->getParameter('app.is_wmf'), + self::$container->getParameter('default_project'), + self::$container->getParameter('app.multilingual_wikis'), $methodOverrides ); } diff --git a/tests/Helper/AutomatedEditsTest.php b/tests/Helper/AutomatedEditsTest.php index 3e0197a1c..c25040bf1 100644 --- a/tests/Helper/AutomatedEditsTest.php +++ b/tests/Helper/AutomatedEditsTest.php @@ -29,7 +29,10 @@ public function setUp(): void { $client = static::createClient(); $container = $client->getContainer(); - $this->aeh = new AutomatedEditsHelper($container); + $this->aeh = new AutomatedEditsHelper( + $container->get('session'), + $container->get('cache.app') + ); } /** diff --git a/tests/Helper/I18nHelperTest.php b/tests/Helper/I18nHelperTest.php index 22ca61303..eef096a45 100644 --- a/tests/Helper/I18nHelperTest.php +++ b/tests/Helper/I18nHelperTest.php @@ -8,8 +8,6 @@ use App\Tests\TestAdapter; use DateTime; use Krinkle\Intuition\Intuition; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Session; /** * @covers \App\Helper\I18nHelper @@ -20,10 +18,7 @@ class I18nHelperTest extends TestAdapter public function setUp(): void { - $container = static::createClient()->getContainer(); - $stack = new RequestStack(); - $session = new Session(); - $this->i18n = new I18nHelper($container, $stack, $session); + $this->i18n = static::createClient()->getContainer()->get('app.i18n_helper'); } public function testGetters(): void diff --git a/tests/Model/ArticleInfoTest.php b/tests/Model/ArticleInfoTest.php index b5bdee2ae..c39a2ac1e 100644 --- a/tests/Model/ArticleInfoTest.php +++ b/tests/Model/ArticleInfoTest.php @@ -5,7 +5,6 @@ namespace App\Tests\Model; use App\Helper\AutomatedEditsHelper; -use App\Helper\I18nHelper; use App\Model\ArticleInfo; use App\Model\Edit; use App\Model\Page; @@ -18,8 +17,6 @@ use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use GuzzleHttp; use ReflectionClass; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Session; /** * Tests for ArticleInfo. @@ -49,7 +46,7 @@ public function setUp(): void static::createClient(); /** @var AutomatedEditsHelper $autoEditsHelper */ $autoEditsHelper = static::$container->get('app.automated_edits_helper'); - $i18nHelper = new I18nHelper(static::$container, new RequestStack(), new Session()); + $i18nHelper = static::$container->get('app.i18n_helper'); $this->project = $this->getMockEnwikiProject(); $this->pageRepo = $this->createMock(PageRepository::class); $this->page = new Page($this->pageRepo, $this->project, 'Test page'); diff --git a/tests/Model/EditCounterTest.php b/tests/Model/EditCounterTest.php index fbe3f364a..6a98ade24 100644 --- a/tests/Model/EditCounterTest.php +++ b/tests/Model/EditCounterTest.php @@ -15,8 +15,6 @@ use App\Tests\TestAdapter; use DateTime; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Session; /** * Tests for the EditCounter. @@ -39,7 +37,7 @@ class EditCounterTest extends TestAdapter */ public function setUp(): void { - $this->i18n = new I18nHelper(static::createClient()->getContainer(), new RequestStack(), new Session()); + $this->i18n = static::createClient()->getContainer()->get('app.i18n_helper'); $this->editCounterRepo = $this->createMock(EditCounterRepository::class); $this->projectRepo = $this->getProjectRepo(); diff --git a/tests/Model/EditSummaryTest.php b/tests/Model/EditSummaryTest.php index 4bc2d5eb9..ef203b6f9 100644 --- a/tests/Model/EditSummaryTest.php +++ b/tests/Model/EditSummaryTest.php @@ -4,7 +4,6 @@ namespace App\Tests\Model; -use App\Helper\I18nHelper; use App\Model\EditSummary; use App\Model\Project; use App\Model\User; @@ -12,8 +11,6 @@ use App\Repository\UserRepository; use App\Tests\TestAdapter; use ReflectionClass; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Session; /** * Tests for EditSummary. @@ -41,7 +38,7 @@ public function setUp(): void $editSummaryRepo, $this->project, $this->user, - new I18nHelper(static::createClient()->getContainer(), new RequestStack(), new Session()), + static::createClient()->getContainer()->get('app.i18n_helper'), 'all', false, false, diff --git a/tests/Model/PageTest.php b/tests/Model/PageTest.php index 15dcda3aa..0818c3bb8 100644 --- a/tests/Model/PageTest.php +++ b/tests/Model/PageTest.php @@ -366,12 +366,13 @@ public function testLinksAndRedirects(): void private function getRealPageRepository(): PageRepository { - $container = static::createClient()->getContainer(); + static::createClient(); return new PageRepository( - $container, - $container->get('cache.app'), - $container->get('eight_points_guzzle.client.xtools'), + self::$container->get('doctrine'), + self::$container->get('cache.app'), + self::$container->get('eight_points_guzzle.client.xtools'), $this->createMock(LoggerInterface::class), + self::$container->get('parameter_bag'), true, 30 ); diff --git a/tests/Model/TopEditsTest.php b/tests/Model/TopEditsTest.php index 500d91019..f98b32c44 100644 --- a/tests/Model/TopEditsTest.php +++ b/tests/Model/TopEditsTest.php @@ -46,7 +46,8 @@ public function setUp(): void $this->project->setRepository($this->projectRepo); $this->userRepo = $this->createMock(UserRepository::class); $this->user = new User($this->userRepo, 'Test user'); - $this->autoEditsHelper = new AutomatedEditsHelper(static::createClient()->getContainer()); + $container = static::createClient()->getContainer(); + $this->autoEditsHelper = new AutomatedEditsHelper($container->get('session'), $container->get('cache.app')); $this->teRepo = $this->createMock(TopEditsRepository::class); $this->editRepo = $this->createMock(EditRepository::class); $this->editRepo->method('getAutoEditsHelper') diff --git a/tests/Model/UserRightsTest.php b/tests/Model/UserRightsTest.php index 5905b0325..c70831251 100644 --- a/tests/Model/UserRightsTest.php +++ b/tests/Model/UserRightsTest.php @@ -12,8 +12,6 @@ use App\Repository\UserRightsRepository; use App\Tests\TestAdapter; use PHPUnit\Framework\MockObject\MockObject; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Session; /** * @covers \App\Model\UserRights @@ -28,7 +26,7 @@ class UserRightsTest extends TestAdapter public function setUp(): void { - $this->i18n = new I18nHelper(static::createClient()->getContainer(), new RequestStack(), new Session()); + $this->i18n = static::createClient()->getContainer()->get('app.i18n_helper'); $project = new Project('test.example.org'); $project->setRepository($this->getProjectRepo()); $this->userRepo = $this->createMock(UserRepository::class); diff --git a/tests/Twig/AppExtensionTest.php b/tests/Twig/AppExtensionTest.php index f84947c1f..f3cf9b7b9 100644 --- a/tests/Twig/AppExtensionTest.php +++ b/tests/Twig/AppExtensionTest.php @@ -4,7 +4,6 @@ namespace App\Tests\Twig; -use App\Helper\I18nHelper; use App\Model\Project; use App\Model\User; use App\Repository\ProjectRepository; @@ -32,19 +31,21 @@ class AppExtensionTest extends TestAdapter */ public function setUp(): void { - $container = static::createClient()->getContainer(); + static::createClient(); $stack = new RequestStack(); $session = new Session(); - $i18nHelper = new I18nHelper($container, $stack, $session); + $i18nHelper = static::$container->get('app.i18n_helper'); $urlGenerator = $this->createMock(UrlGenerator::class); $this->appExtension = new AppExtension( - $container, $stack, $session, $i18nHelper, $urlGenerator, $this->createMock(ProjectRepository::class), - false + static::$container->get('parameter_bag'), + static::$container->getParameter('app.is_wmf'), + static::$container->getParameter('app.single_wiki'), + 30 ); } diff --git a/tests/Twig/TopNavExtensionTest.php b/tests/Twig/TopNavExtensionTest.php index 9fc65ae0d..27b4a7597 100644 --- a/tests/Twig/TopNavExtensionTest.php +++ b/tests/Twig/TopNavExtensionTest.php @@ -4,12 +4,9 @@ namespace App\Tests\Twig; -use App\Helper\I18nHelper; use App\Repository\ProjectRepository; use App\Tests\TestAdapter; use App\Twig\TopNavExtension; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Routing\Generator\UrlGenerator; /** @@ -25,19 +22,17 @@ class TopNavExtensionTest extends TestAdapter */ public function setUp(): void { - $container = static::createClient()->getContainer(); - $stack = new RequestStack(); - $session = new Session(); - $i18nHelper = new I18nHelper($container, $stack, $session); - $urlGenerator = $this->createMock(UrlGenerator::class); + static::createClient(); $this->topNavExtension = new TopNavExtension( - $container, - $stack, - $session, - $i18nHelper, - $urlGenerator, + static::$container->get('request_stack'), + static::$container->get('session'), + static::$container->get('app.i18n_helper'), + $this->createMock(UrlGenerator::class), $this->createMock(ProjectRepository::class), - false + static::$container->get('parameter_bag'), + static::$container->getParameter('app.is_wmf'), + static::$container->getParameter('app.single_wiki'), + static::$container->getParameter('app.replag_threshold') ); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 65286ab1f..3f8ebe528 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,14 +1,16 @@ load(dirname(__DIR__) . $loadFile);