From 3cc74862cd09552eb1b232e234b76fff42b2da52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Get=C3=BAlio=20Meirelles?= Date: Tue, 4 Apr 2023 13:51:10 -0300 Subject: [PATCH 01/75] chore: add php 8 support --- composer.json | 10 +- composer.lock | 2507 +++++++++++++++++++++++++-------------------- docker/Dockerfile | 2 +- 3 files changed, 1393 insertions(+), 1126 deletions(-) diff --git a/composer.json b/composer.json index 6e68715f..9a7b21a5 100644 --- a/composer.json +++ b/composer.json @@ -10,10 +10,10 @@ "ext-rdkafka": ">=4.0", "ext-json": "*", "guzzlehttp/guzzle": "^6.5.0 || ^7.0", - "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0", - "illuminate/console": "^5.5 || ^6.0 || ^7.0 || ^8.0", - "illuminate/config": "^5.5 || ^6.0 || ^7.0 || ^8.0", - "php": ">=7.4", + "illuminate/support": "^9.0 || ^10.0", + "illuminate/console": "^9.0 || ^10.0", + "illuminate/config": "^9.0 || ^10.0", + "php": "^8.0", "wikimedia/avro": "^1.9.0" }, "require-dev": { @@ -21,7 +21,7 @@ "phpunit/phpunit": "^9.5.27", "mockery/mockery": "^1.5.1", "kwn/php-rdkafka-stubs": "^2.2.1", - "orchestra/testbench": "^6.25.1", + "orchestra/testbench": "^7.0|^8.0", "dms/phpunit-arraysubset-asserts": "^0.2.1", "phpro/grumphp": "^1.13.0", "vimeo/psalm": "^4.30.0", diff --git a/composer.lock b/composer.lock index 2d508fb6..37d642f5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,30 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "af22a3400640796726b61a692ed5b532", + "content-hash": "70981de1c0e9abf6f6ea296fca4d0cd6", "packages": [ { "name": "brick/math", - "version": "0.9.3", + "version": "0.10.2", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "url": "https://api.github.com/repos/brick/math/zipball/459f2781e1a08d52ee56b0b1444086e038561e3f", + "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f", "shasum": "" }, "require": { "ext-json": "*", - "php": "^7.1 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.9.2" + "phpunit/phpunit": "^9.0", + "vimeo/psalm": "4.25.0" }, "type": "library", "autoload": { @@ -52,19 +52,15 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.3" + "source": "https://github.com/brick/math/tree/0.10.2" }, "funding": [ { "url": "https://github.com/BenMorel", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/brick/math", - "type": "tidelift" } ], - "time": "2021-08-15T20:50:18+00:00" + "time": "2022-08-10T22:54:19+00:00" }, { "name": "dflydev/dot-access-data", @@ -141,6 +137,49 @@ }, "time": "2022-10-27T11:44:00+00:00" }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" + }, { "name": "doctrine/inflector", "version": "2.0.6", @@ -234,31 +273,33 @@ }, { "name": "doctrine/lexer", - "version": "1.2.3", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9.0", + "doctrine/coding-standard": "^9 || ^10", "phpstan/phpstan": "^1.3", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.11" + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.0" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + "Doctrine\\Common\\Lexer\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -290,7 +331,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.3" + "source": "https://github.com/doctrine/lexer/tree/2.1.0" }, "funding": [ { @@ -306,7 +347,7 @@ "type": "tidelift" } ], - "time": "2022-02-28T11:07:21+00:00" + "time": "2022-12-14T08:49:07+00:00" }, { "name": "dragonmantank/cron-expression", @@ -371,27 +412,26 @@ }, { "name": "egulias/email-validator", - "version": "2.1.25", + "version": "3.2.5", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "0dbf5d78455d4d6a41d186da50adc1122ec066f4" + "reference": "b531a2311709443320c786feb4519cfaf94af796" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/0dbf5d78455d4d6a41d186da50adc1122ec066f4", - "reference": "0dbf5d78455d4d6a41d186da50adc1122ec066f4", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b531a2311709443320c786feb4519cfaf94af796", + "reference": "b531a2311709443320c786feb4519cfaf94af796", "shasum": "" }, "require": { - "doctrine/lexer": "^1.0.1", - "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.10" + "doctrine/lexer": "^1.2|^2", + "php": ">=7.2", + "symfony/polyfill-intl-idn": "^1.15" }, "require-dev": { - "dominicsayers/isemail": "^3.0.7", - "phpunit/phpunit": "^4.8.36|^7.5.15", - "satooshi/php-coveralls": "^1.0.1" + "phpunit/phpunit": "^8.5.8|^9.3.3", + "vimeo/psalm": "^4" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -399,7 +439,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -427,7 +467,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/2.1.25" + "source": "https://github.com/egulias/EmailValidator/tree/3.2.5" }, "funding": [ { @@ -435,28 +475,99 @@ "type": "github" } ], - "time": "2020-12-29T14:50:06+00:00" + "time": "2023-01-02T17:26:14+00:00" + }, + { + "name": "fruitcake/php-cors", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/58571acbaa5f9f462c9c77e911700ac66f446d4e", + "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "symfony/http-foundation": "^4.4|^5.4|^6" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barryvdh", + "email": "barryvdh@gmail.com" + } + ], + "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", + "homepage": "https://github.com/fruitcake/php-cors", + "keywords": [ + "cors", + "laravel", + "symfony" + ], + "support": { + "issues": "https://github.com/fruitcake/php-cors/issues", + "source": "https://github.com/fruitcake/php-cors/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2022-02-20T15:07:15+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8" + "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/a878d45c1914464426dc94da61c9e1d36ae262a8", - "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", + "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9" + "phpoption/phpoption": "^1.9.1" }, "require-dev": { - "phpunit/phpunit": "^8.5.28 || ^9.5.21" + "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" }, "type": "library", "autoload": { @@ -485,7 +596,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.0" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1" }, "funding": [ { @@ -497,7 +608,7 @@ "type": "tidelift" } ], - "time": "2022-07-30T15:56:11+00:00" + "time": "2023-02-25T20:23:15+00:00" }, { "name": "guzzlehttp/guzzle", @@ -713,16 +824,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.4.3", + "version": "2.4.4", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "67c26b443f348a51926030c83481b85718457d3d" + "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d", - "reference": "67c26b443f348a51926030c83481b85718457d3d", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", + "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", "shasum": "" }, "require": { @@ -812,7 +923,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.4.3" + "source": "https://github.com/guzzle/psr7/tree/2.4.4" }, "funding": [ { @@ -828,60 +939,152 @@ "type": "tidelift" } ], - "time": "2022-10-26T14:07:24+00:00" + "time": "2023-03-09T13:19:02+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "b945d74a55a25a949158444f09ec0d3c120d69e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/b945d74a55a25a949158444f09ec0d3c120d69e2", + "reference": "b945d74a55a25a949158444f09ec0d3c120d69e2", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-php80": "^1.17" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.19 || ^9.5.8", + "uri-template/tests": "1.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\UriTemplate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + } + ], + "description": "A polyfill class for uri_template of PHP", + "keywords": [ + "guzzlehttp", + "uri-template" + ], + "support": { + "issues": "https://github.com/guzzle/uri-template/issues", + "source": "https://github.com/guzzle/uri-template/tree/v1.0.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/uri-template", + "type": "tidelift" + } + ], + "time": "2021-10-07T12:57:01+00:00" }, { "name": "laravel/framework", - "version": "v8.83.27", + "version": "v9.52.5", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "e1afe088b4ca613fb96dc57e6d8dbcb8cc2c6b49" + "reference": "e14d28c0f9403630d13f308bb43f3d3cb73d6d67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/e1afe088b4ca613fb96dc57e6d8dbcb8cc2c6b49", - "reference": "e1afe088b4ca613fb96dc57e6d8dbcb8cc2c6b49", + "url": "https://api.github.com/repos/laravel/framework/zipball/e14d28c0f9403630d13f308bb43f3d3cb73d6d67", + "reference": "e14d28c0f9403630d13f308bb43f3d3cb73d6d67", "shasum": "" }, "require": { - "doctrine/inflector": "^1.4|^2.0", - "dragonmantank/cron-expression": "^3.0.2", - "egulias/email-validator": "^2.1.10", - "ext-json": "*", + "brick/math": "^0.9.3|^0.10.2|^0.11", + "doctrine/inflector": "^2.0.5", + "dragonmantank/cron-expression": "^3.3.2", + "egulias/email-validator": "^3.2.1|^4.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", "ext-mbstring": "*", "ext-openssl": "*", - "laravel/serializable-closure": "^1.0", - "league/commonmark": "^1.3|^2.0.2", - "league/flysystem": "^1.1", + "ext-session": "*", + "ext-tokenizer": "*", + "fruitcake/php-cors": "^1.2", + "guzzlehttp/uri-template": "^1.0", + "laravel/serializable-closure": "^1.2.2", + "league/commonmark": "^2.2.1", + "league/flysystem": "^3.8.0", "monolog/monolog": "^2.0", - "nesbot/carbon": "^2.53.1", - "opis/closure": "^3.6", - "php": "^7.3|^8.0", - "psr/container": "^1.0", - "psr/log": "^1.0|^2.0", - "psr/simple-cache": "^1.0", - "ramsey/uuid": "^4.2.2", - "swiftmailer/swiftmailer": "^6.3", - "symfony/console": "^5.4", - "symfony/error-handler": "^5.4", - "symfony/finder": "^5.4", - "symfony/http-foundation": "^5.4", - "symfony/http-kernel": "^5.4", - "symfony/mime": "^5.4", - "symfony/process": "^5.4", - "symfony/routing": "^5.4", - "symfony/var-dumper": "^5.4", - "tijsverkoyen/css-to-inline-styles": "^2.2.2", + "nesbot/carbon": "^2.62.1", + "nunomaduro/termwind": "^1.13", + "php": "^8.0.2", + "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7", + "symfony/console": "^6.0.9", + "symfony/error-handler": "^6.0", + "symfony/finder": "^6.0", + "symfony/http-foundation": "^6.0", + "symfony/http-kernel": "^6.0", + "symfony/mailer": "^6.0", + "symfony/mime": "^6.0", + "symfony/process": "^6.0", + "symfony/routing": "^6.0", + "symfony/uid": "^6.0", + "symfony/var-dumper": "^6.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.5", "vlucas/phpdotenv": "^5.4.1", - "voku/portable-ascii": "^1.6.1" + "voku/portable-ascii": "^2.0" }, "conflict": { "tightenco/collect": "<5.5.33" }, "provide": { - "psr/container-implementation": "1.0", - "psr/simple-cache-implementation": "1.0" + "psr/container-implementation": "1.1|2.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0" }, "replace": { "illuminate/auth": "self.version", @@ -889,6 +1092,7 @@ "illuminate/bus": "self.version", "illuminate/cache": "self.version", "illuminate/collections": "self.version", + "illuminate/conditionable": "self.version", "illuminate/config": "self.version", "illuminate/console": "self.version", "illuminate/container": "self.version", @@ -917,53 +1121,68 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "^3.198.1", + "ably/ably-php": "^1.0", + "aws/aws-sdk-php": "^3.235.5", "doctrine/dbal": "^2.13.3|^3.1.4", - "filp/whoops": "^2.14.3", - "guzzlehttp/guzzle": "^6.5.5|^7.0.1", - "league/flysystem-cached-adapter": "^1.0", - "mockery/mockery": "^1.4.4", - "orchestra/testbench-core": "^6.27", + "ext-gmp": "*", + "fakerphp/faker": "^1.21", + "guzzlehttp/guzzle": "^7.5", + "league/flysystem-aws-s3-v3": "^3.0", + "league/flysystem-ftp": "^3.0", + "league/flysystem-path-prefixing": "^3.3", + "league/flysystem-read-only": "^3.3", + "league/flysystem-sftp-v3": "^3.0", + "mockery/mockery": "^1.5.1", + "orchestra/testbench-core": "^7.16", "pda/pheanstalk": "^4.0", - "phpunit/phpunit": "^8.5.19|^9.5.8", - "predis/predis": "^1.1.9", - "symfony/cache": "^5.4" + "phpstan/phpdoc-parser": "^1.15", + "phpstan/phpstan": "^1.4.7", + "phpunit/phpunit": "^9.5.8", + "predis/predis": "^1.1.9|^2.0.2", + "symfony/cache": "^6.0", + "symfony/http-client": "^6.0" }, "suggest": { "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.198.1).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.235.5).", "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.4).", - "ext-bcmath": "Required to use the multiple_of validation rule.", + "ext-apcu": "Required to use the APC cache driver.", + "ext-fileinfo": "Required to use the Filesystem class.", "ext-ftp": "Required to use the Flysystem FTP driver.", "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", "ext-memcached": "Required to use the memcache cache driver.", - "ext-pcntl": "Required to use all features of the queue worker.", + "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.", + "ext-pdo": "Required to use all database features.", "ext-posix": "Required to use all features of the queue worker.", "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", "filp/whoops": "Required for friendly error pages in development (^2.14.3).", - "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.5.5|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the HTTP Client and the ping methods on schedules (^7.5).", "laravel/tinker": "Required to use the tinker console command (^2.0).", - "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", - "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", - "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", - "mockery/mockery": "Required to use mocking (^1.4.4).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.0).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.0).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.3).", + "league/flysystem-read-only": "Required to use read-only disks (^3.3)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.0).", + "mockery/mockery": "Required to use mocking (^1.5.1).", "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", - "phpunit/phpunit": "Required to use assertions and run tests (^8.5.19|^9.5.8).", - "predis/predis": "Required to use the predis connector (^1.1.9).", + "phpunit/phpunit": "Required to use assertions and run tests (^9.5.8).", + "predis/predis": "Required to use the predis connector (^1.1.9|^2.0.2).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0|^7.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.4).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.4).", - "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", - "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^6.0).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^6.0).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^6.0).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^6.0).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^6.0).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "autoload": { @@ -977,7 +1196,8 @@ "Illuminate\\": "src/Illuminate/", "Illuminate\\Support\\": [ "src/Illuminate/Macroable/", - "src/Illuminate/Collections/" + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/" ] } }, @@ -1001,20 +1221,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-12-08T15:28:55+00:00" + "time": "2023-03-28T18:03:54+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.2.2", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae" + "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/47afb7fae28ed29057fdca37e16a84f90cc62fae", - "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", + "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", "shasum": "" }, "require": { @@ -1061,20 +1281,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2022-09-08T13:45:54+00:00" + "time": "2023-01-30T18:31:20+00:00" }, { "name": "league/commonmark", - "version": "2.3.8", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "c493585c130544c4e91d2e0e131e6d35cb0cbc47" + "reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c493585c130544c4e91d2e0e131e6d35cb0cbc47", - "reference": "c493585c130544c4e91d2e0e131e6d35cb0cbc47", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d44a24690f16b8c1808bf13b1bd54ae4c63ea048", + "reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048", "shasum": "" }, "require": { @@ -1110,7 +1330,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" } }, "autoload": { @@ -1167,7 +1387,7 @@ "type": "tidelift" } ], - "time": "2022-12-10T16:02:17+00:00" + "time": "2023-03-24T15:16:10+00:00" }, { "name": "league/config", @@ -1253,54 +1473,49 @@ }, { "name": "league/flysystem", - "version": "1.1.10", + "version": "3.12.3", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" + "reference": "81e87e74dd5213795c7846d65089712d2dda90ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", - "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/81e87e74dd5213795c7846d65089712d2dda90ce", + "reference": "81e87e74dd5213795c7846d65089712d2dda90ce", "shasum": "" }, "require": { - "ext-fileinfo": "*", - "league/mime-type-detection": "^1.3", - "php": "^7.2.5 || ^8.0" + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" }, "conflict": { - "league/flysystem-sftp": "<1.0.6" + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" }, "require-dev": { - "phpspec/prophecy": "^1.11.1", - "phpunit/phpunit": "^8.5.8" - }, - "suggest": { - "ext-ftp": "Allows you to use FTP server storage", - "ext-openssl": "Allows you to use FTPS server storage", - "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", - "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", - "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", - "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", - "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", - "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", - "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", - "league/flysystem-webdav": "Allows you to use WebDAV storage", - "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", - "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", - "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + "async-aws/s3": "^1.5", + "async-aws/simple-s3": "^1.1", + "aws/aws-sdk-php": "^3.220.0", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "microsoft/azure-storage-blob": "^1.1", + "phpseclib/phpseclib": "^3.0.14", + "phpstan/phpstan": "^0.12.26", + "phpunit/phpunit": "^9.5.11", + "sabre/dav": "^4.3.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, "autoload": { "psr-4": { - "League\\Flysystem\\": "src/" + "League\\Flysystem\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1310,40 +1525,42 @@ "authors": [ { "name": "Frank de Jonge", - "email": "info@frenky.net" + "email": "info@frankdejonge.nl" } ], - "description": "Filesystem abstraction: Many filesystems, one API.", + "description": "File storage abstraction for PHP", "keywords": [ - "Cloud Files", "WebDAV", - "abstraction", "aws", "cloud", - "copy.com", - "dropbox", - "file systems", + "file", "files", "filesystem", "filesystems", "ftp", - "rackspace", - "remote", "s3", "sftp", "storage" ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" + "source": "https://github.com/thephpleague/flysystem/tree/3.12.3" }, "funding": [ { - "url": "https://offset.earth/frankdejonge", - "type": "other" + "url": "https://ecologi.com/frankdejonge", + "type": "custom" + }, + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" } ], - "time": "2022-10-04T09:16:37+00:00" + "time": "2023-02-18T15:32:41+00:00" }, { "name": "league/mime-type-detection", @@ -1403,16 +1620,16 @@ }, { "name": "monolog/monolog", - "version": "2.8.0", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50" + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", "shasum": "" }, "require": { @@ -1427,7 +1644,7 @@ "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7 || ^8", "ext-json": "*", - "graylog2/gelf-php": "^1.4.2", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", "guzzlehttp/guzzle": "^7.4", "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", @@ -1489,7 +1706,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.8.0" + "source": "https://github.com/Seldaek/monolog/tree/2.9.1" }, "funding": [ { @@ -1501,20 +1718,20 @@ "type": "tidelift" } ], - "time": "2022-07-24T11:55:47+00:00" + "time": "2023-02-06T13:44:46+00:00" }, { "name": "nesbot/carbon", - "version": "2.64.0", + "version": "2.66.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "889546413c97de2d05063b8cb7b193c2531ea211" + "reference": "496712849902241f04902033b0441b269effe001" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/889546413c97de2d05063b8cb7b193c2531ea211", - "reference": "889546413c97de2d05063b8cb7b193c2531ea211", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/496712849902241f04902033b0441b269effe001", + "reference": "496712849902241f04902033b0441b269effe001", "shasum": "" }, "require": { @@ -1603,7 +1820,7 @@ "type": "tidelift" } ], - "time": "2022-11-26T17:36:00+00:00" + "time": "2023-01-29T18:53:47+00:00" }, { "name": "nette/schema", @@ -1669,28 +1886,30 @@ }, { "name": "nette/utils", - "version": "v3.2.8", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "02a54c4c872b99e4ec05c4aec54b5a06eb0f6368" + "reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/02a54c4c872b99e4ec05c4aec54b5a06eb0f6368", - "reference": "02a54c4c872b99e4ec05c4aec54b5a06eb0f6368", + "url": "https://api.github.com/repos/nette/utils/zipball/cacdbf5a91a657ede665c541eda28941d4b09c1e", + "reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e", "shasum": "" }, "require": { - "php": ">=7.2 <8.3" + "php": ">=8.0 <8.3" }, "conflict": { - "nette/di": "<3.0.6" + "nette/finder": "<3", + "nette/schema": "<1.2.2" }, "require-dev": { - "nette/tester": "~2.0", + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.4", "phpstan/phpstan": "^1.0", - "tracy/tracy": "^2.3" + "tracy/tracy": "^2.9" }, "suggest": { "ext-gd": "to use Image", @@ -1704,7 +1923,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1748,43 +1967,55 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v3.2.8" + "source": "https://github.com/nette/utils/tree/v4.0.0" }, - "time": "2022-09-12T23:36:20+00:00" + "time": "2023-02-02T10:41:53+00:00" }, { - "name": "opis/closure", - "version": "3.6.3", + "name": "nunomaduro/termwind", + "version": "v1.15.1", "source": { "type": "git", - "url": "https://github.com/opis/closure.git", - "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad" + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/3d81e4309d2a927abbe66df935f4bb60082805ad", - "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/8ab0b32c8caa4a2e09700ea32925441385e4a5dc", + "reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc", "shasum": "" }, "require": { - "php": "^5.4 || ^7.0 || ^8.0" + "ext-mbstring": "*", + "php": "^8.0", + "symfony/console": "^5.3.0|^6.0.0" }, "require-dev": { - "jeremeamia/superclosure": "^2.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "ergebnis/phpstan-rules": "^1.0.", + "illuminate/console": "^8.0|^9.0", + "illuminate/support": "^8.0|^9.0", + "laravel/pint": "^1.0.0", + "pestphp/pest": "^1.21.0", + "pestphp/pest-plugin-mock": "^1.0", + "phpstan/phpstan": "^1.4.6", + "phpstan/phpstan-strict-rules": "^1.1.0", + "symfony/var-dumper": "^5.2.7|^6.0.0", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "3.6.x-dev" + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] } }, "autoload": { "files": [ - "functions.php" + "src/Functions.php" ], "psr-4": { - "Opis\\Closure\\": "src/" + "Termwind\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1793,50 +2024,59 @@ ], "authors": [ { - "name": "Marius Sarca", - "email": "marius.sarca@gmail.com" - }, - { - "name": "Sorin Sarca", - "email": "sarca_sorin@hotmail.com" + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" } ], - "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", - "homepage": "https://opis.io/closure", + "description": "Its like Tailwind CSS, but for the console.", "keywords": [ - "anonymous functions", - "closure", - "function", - "serializable", - "serialization", - "serialize" + "cli", + "console", + "css", + "package", + "php", + "style" ], "support": { - "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.6.3" + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v1.15.1" }, - "time": "2022-01-27T09:35:39+00:00" + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2023-02-08T01:06:31+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab" + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", - "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8", - "phpunit/phpunit": "^8.5.28 || ^9.5.21" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" }, "type": "library", "extra": { @@ -1878,7 +2118,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.0" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" }, "funding": [ { @@ -1890,26 +2130,31 @@ "type": "tidelift" } ], - "time": "2022-07-30T15:51:26+00:00" + "time": "2023-02-25T19:38:58+00:00" }, { "name": "psr/container", - "version": "1.1.2", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { "php": ">=7.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -1936,9 +2181,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { "name": "psr/event-dispatcher", @@ -2099,25 +2344,25 @@ }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "1.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -2146,36 +2391,36 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/php-fig/http-message/tree/1.1" }, - "time": "2016-08-06T14:39:51+00:00" + "time": "2023-04-04T09:50:52+00:00" }, { "name": "psr/log", - "version": "1.1.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2196,31 +2441,31 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/log/tree/3.0.0" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2021-07-14T16:46:02+00:00" }, { "name": "psr/simple-cache", - "version": "1.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -2235,7 +2480,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for simple caching", @@ -2247,9 +2492,9 @@ "simple-cache" ], "support": { - "source": "https://github.com/php-fig/simple-cache/tree/master" + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" }, - "time": "2017-10-23T01:57:42+00:00" + "time": "2021-10-29T13:26:27+00:00" }, { "name": "ralouphie/getallheaders", @@ -2297,42 +2542,53 @@ }, { "name": "ramsey/collection", - "version": "1.2.2", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a" + "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a", - "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a", + "url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4", + "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4", "shasum": "" }, "require": { - "php": "^7.3 || ^8", + "php": "^7.4 || ^8.0", "symfony/polyfill-php81": "^1.23" }, "require-dev": { - "captainhook/captainhook": "^5.3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "ergebnis/composer-normalize": "^2.6", - "fakerphp/faker": "^1.5", - "hamcrest/hamcrest-php": "^2", - "jangregor/phpstan-prophecy": "^0.8", - "mockery/mockery": "^1.3", + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.28.3", + "fakerphp/faker": "^1.21", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^1.0", + "mockery/mockery": "^1.5", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpcsstandards/phpcsutils": "^1.0.0-rc1", "phpspec/prophecy-phpunit": "^2.0", - "phpstan/extension-installer": "^1", - "phpstan/phpstan": "^0.12.32", - "phpstan/phpstan-mockery": "^0.12.5", - "phpstan/phpstan-phpunit": "^0.12.11", - "phpunit/phpunit": "^8.5 || ^9", - "psy/psysh": "^0.10.4", - "slevomat/coding-standard": "^6.3", - "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^4.4" + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5", + "psalm/plugin-mockery": "^1.1", + "psalm/plugin-phpunit": "^0.18.4", + "ramsey/coding-standard": "^2.0.3", + "ramsey/conventional-commits": "^1.3", + "vimeo/psalm": "^5.4" }, "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, "autoload": { "psr-4": { "Ramsey\\Collection\\": "src/" @@ -2360,7 +2616,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.2.2" + "source": "https://github.com/ramsey/collection/tree/1.3.0" }, "funding": [ { @@ -2372,29 +2628,27 @@ "type": "tidelift" } ], - "time": "2021-10-10T03:01:02+00:00" + "time": "2022-12-27T19:12:24+00:00" }, { "name": "ramsey/uuid", - "version": "4.2.3", + "version": "4.7.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" + "reference": "433b2014e3979047db08a17a205f410ba3869cf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", - "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/433b2014e3979047db08a17a205f410ba3869cf2", + "reference": "433b2014e3979047db08a17a205f410ba3869cf2", "shasum": "" }, "require": { - "brick/math": "^0.8 || ^0.9", + "brick/math": "^0.8.8 || ^0.9 || ^0.10", "ext-json": "*", - "php": "^7.2 || ^8.0", - "ramsey/collection": "^1.0", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-php80": "^1.14" + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" }, "replace": { "rhumsaa/uuid": "self.version" @@ -2406,24 +2660,23 @@ "doctrine/annotations": "^1.8", "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", - "moontoast/math": "^1.1", "paragonie/random-lib": "^2", "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", "php-parallel-lint/php-parallel-lint": "^1.1", "phpbench/phpbench": "^1.0", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-mockery": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", "phpunit/phpunit": "^8.5 || ^9", - "slevomat/coding-standard": "^7.0", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", "squizlabs/php_codesniffer": "^3.5", "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", - "ext-ctype": "Enables faster processing of character classification using ctype functions.", "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", @@ -2431,9 +2684,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "4.x-dev" - }, "captainhook": { "force-install": true } @@ -2458,7 +2708,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.2.3" + "source": "https://github.com/ramsey/uuid/tree/4.7.3" }, "funding": [ { @@ -2470,126 +2720,46 @@ "type": "tidelift" } ], - "time": "2021-09-25T23:10:38+00:00" - }, - { - "name": "swiftmailer/swiftmailer", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", - "shasum": "" - }, - "require": { - "egulias/email-validator": "^2.0|^3.1", - "php": ">=7.0.0", - "symfony/polyfill-iconv": "^1.0", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.4" - }, - "suggest": { - "ext-intl": "Needed to support internationalized email addresses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.2-dev" - } - }, - "autoload": { - "files": [ - "lib/swift_required.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Chris Corbyn" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Swiftmailer, free feature-rich PHP mailer", - "homepage": "https://swiftmailer.symfony.com", - "keywords": [ - "email", - "mail", - "mailer" - ], - "support": { - "issues": "https://github.com/swiftmailer/swiftmailer/issues", - "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer", - "type": "tidelift" - } - ], - "abandoned": "symfony/mailer", - "time": "2021-10-18T15:26:12+00:00" + "time": "2023-01-12T18:13:24+00:00" }, { "name": "symfony/console", - "version": "v5.4.16", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8e9b9c8dfb33af6057c94e1b44846bee700dc5ef" + "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8e9b9c8dfb33af6057c94e1b44846bee700dc5ef", - "reference": "8e9b9c8dfb33af6057c94e1b44846bee700dc5ef", + "url": "https://api.github.com/repos/symfony/console/zipball/c3ebc83d031b71c39da318ca8b7a07ecc67507ed", + "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.0.2", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/string": "^5.4|^6.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/lock": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" }, "suggest": { "psr/log": "For using the console logger", @@ -2629,7 +2799,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.16" + "source": "https://github.com/symfony/console/tree/v6.0.19" }, "funding": [ { @@ -2645,25 +2815,24 @@ "type": "tidelift" } ], - "time": "2022-11-25T14:09:27+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.11", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "c1681789f059ab756001052164726ae88512ae3d" + "reference": "f1d00bddb83a4cb2138564b2150001cb6ce272b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/c1681789f059ab756001052164726ae88512ae3d", - "reference": "c1681789f059ab756001052164726ae88512ae3d", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f1d00bddb83a4cb2138564b2150001cb6ce272b1", + "reference": "f1d00bddb83a4cb2138564b2150001cb6ce272b1", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2" }, "type": "library", "autoload": { @@ -2695,7 +2864,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.11" + "source": "https://github.com/symfony/css-selector/tree/v6.0.19" }, "funding": [ { @@ -2711,29 +2880,29 @@ "type": "tidelift" } ], - "time": "2022-06-27T16:58:25+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", @@ -2762,7 +2931,7 @@ "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" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2" }, "funding": [ { @@ -2778,31 +2947,31 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-01-02T09:55:41+00:00" }, { "name": "symfony/error-handler", - "version": "v5.4.15", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "539cf1428b8442303c6e876ad7bf5a7babd91091" + "reference": "c7df52182f43a68522756ac31a532dd5b1e6db67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/539cf1428b8442303c6e876ad7bf5a7babd91091", - "reference": "539cf1428b8442303c6e876ad7bf5a7babd91091", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/c7df52182f43a68522756ac31a532dd5b1e6db67", + "reference": "c7df52182f43a68522756ac31a532dd5b1e6db67", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^4.4|^5.0|^6.0" + "symfony/var-dumper": "^5.4|^6.0" }, "require-dev": { "symfony/deprecation-contracts": "^2.1|^3", - "symfony/http-kernel": "^4.4|^5.0|^6.0", - "symfony/serializer": "^4.4|^5.0|^6.0" + "symfony/http-kernel": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0" }, "bin": [ "Resources/bin/patch-type-declarations" @@ -2833,7 +3002,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.15" + "source": "https://github.com/symfony/error-handler/tree/v6.0.19" }, "funding": [ { @@ -2849,44 +3018,42 @@ "type": "tidelift" } ], - "time": "2022-10-27T06:32:25+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.9", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" + "reference": "2eaf8e63bc5b8cefabd4a800157f0d0c094f677a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", - "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2eaf8e63bc5b8cefabd4a800157f0d0c094f677a", + "reference": "2eaf8e63bc5b8cefabd4a800157f0d0c094f677a", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/event-dispatcher-contracts": "^2|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2", + "symfony/event-dispatcher-contracts": "^2|^3" }, "conflict": { - "symfony/dependency-injection": "<4.4" + "symfony/dependency-injection": "<5.4" }, "provide": { "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0" + "symfony/event-dispatcher-implementation": "2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^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/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/stopwatch": "^4.4|^5.0|^6.0" + "symfony/stopwatch": "^5.4|^6.0" }, "suggest": { "symfony/dependency-injection": "", @@ -2918,7 +3085,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.0.19" }, "funding": [ { @@ -2934,24 +3101,24 @@ "type": "tidelift" } ], - "time": "2022-05-05T16:45:39+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.2", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + "reference": "7bc61cc2db649b4637d331240c5346dcc7708051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7bc61cc2db649b4637d331240c5346dcc7708051", + "reference": "7bc61cc2db649b4637d331240c5346dcc7708051", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "psr/event-dispatcher": "^1" }, "suggest": { @@ -2960,7 +3127,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", @@ -2997,7 +3164,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.2" }, "funding": [ { @@ -3013,26 +3180,24 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-01-02T09:55:41+00:00" }, { "name": "symfony/finder", - "version": "v5.4.11", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c" + "reference": "5cc9cac6586fc0c28cd173780ca696e419fefa11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c", - "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c", + "url": "https://api.github.com/repos/symfony/finder/zipball/5cc9cac6586fc0c28cd173780ca696e419fefa11", + "reference": "5cc9cac6586fc0c28cd173780ca696e419fefa11", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2" }, "type": "library", "autoload": { @@ -3060,7 +3225,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.11" + "source": "https://github.com/symfony/finder/tree/v6.0.19" }, "funding": [ { @@ -3076,35 +3241,34 @@ "type": "tidelift" } ], - "time": "2022-07-29T07:37:50+00:00" + "time": "2023-01-20T17:44:14+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.16", + "version": "v6.0.20", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5032c5849aef24741e1970cb03511b0dd131d838" + "reference": "e16b2676a4b3b1fa12378a20b29c364feda2a8d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5032c5849aef24741e1970cb03511b0dd131d838", - "reference": "5032c5849aef24741e1970cb03511b0dd131d838", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e16b2676a4b3b1fa12378a20b29c364feda2a8d6", + "reference": "e16b2676a4b3b1fa12378a20b29c364feda2a8d6", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { "predis/predis": "~1.0", - "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/cache": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^5.4|^6.0", "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", - "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/mime": "^5.4|^6.0", "symfony/rate-limiter": "^5.2|^6.0" }, "suggest": { @@ -3136,7 +3300,7 @@ "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.16" + "source": "https://github.com/symfony/http-foundation/tree/v6.0.20" }, "funding": [ { @@ -3152,67 +3316,64 @@ "type": "tidelift" } ], - "time": "2022-11-07T08:06:40+00:00" + "time": "2023-01-30T15:41:07+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.16", + "version": "v6.0.20", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "b432c57c5de73634b1859093c1f58e3cd84455a1" + "reference": "6dc70833fd0ef5e861e17c7854c12d7d86679349" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b432c57c5de73634b1859093c1f58e3cd84455a1", - "reference": "b432c57c5de73634b1859093c1f58e3cd84455a1", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6dc70833fd0ef5e861e17c7854c12d7d86679349", + "reference": "6dc70833fd0ef5e861e17c7854c12d7d86679349", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/log": "^1|^2", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^5.0|^6.0", - "symfony/http-foundation": "^5.3.7|^6.0", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2", + "psr/log": "^1|^2|^3", + "symfony/error-handler": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { "symfony/browser-kit": "<5.4", - "symfony/cache": "<5.0", - "symfony/config": "<5.0", - "symfony/console": "<4.4", - "symfony/dependency-injection": "<5.3", - "symfony/doctrine-bridge": "<5.0", - "symfony/form": "<5.0", - "symfony/http-client": "<5.0", - "symfony/mailer": "<5.0", - "symfony/messenger": "<5.0", - "symfony/translation": "<5.0", - "symfony/twig-bridge": "<5.0", - "symfony/validator": "<5.0", + "symfony/cache": "<5.4", + "symfony/config": "<5.4", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/doctrine-bridge": "<5.4", + "symfony/form": "<5.4", + "symfony/http-client": "<5.4", + "symfony/mailer": "<5.4", + "symfony/messenger": "<5.4", + "symfony/translation": "<5.4", + "symfony/twig-bridge": "<5.4", + "symfony/validator": "<5.4", "twig/twig": "<2.13" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "symfony/browser-kit": "^5.4|^6.0", - "symfony/config": "^5.0|^6.0", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/css-selector": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^5.3|^6.0", - "symfony/dom-crawler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/config": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/css-selector": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/dom-crawler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", "symfony/http-client-contracts": "^1.1|^2|^3", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/routing": "^4.4|^5.0|^6.0", - "symfony/stopwatch": "^4.4|^5.0|^6.0", - "symfony/translation": "^4.4|^5.0|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/routing": "^5.4|^6.0", + "symfony/stopwatch": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", "symfony/translation-contracts": "^1.1|^2|^3", "twig/twig": "^2.13|^3.0.4" }, @@ -3248,7 +3409,7 @@ "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/v5.4.16" + "source": "https://github.com/symfony/http-kernel/tree/v6.0.20" }, "funding": [ { @@ -3264,48 +3425,42 @@ "type": "tidelift" } ], - "time": "2022-11-28T18:08:58+00:00" + "time": "2023-02-01T08:22:55+00:00" }, { - "name": "symfony/mime", - "version": "v5.4.16", + "name": "symfony/mailer", + "version": "v6.0.19", "source": { "type": "git", - "url": "https://github.com/symfony/mime.git", - "reference": "46eeedb08f0832b1b61a84c612d945fc85ee4734" + "url": "https://github.com/symfony/mailer.git", + "reference": "cd60799210c488f545ddde2444dc1aa548322872" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/46eeedb08f0832b1b61a84c612d945fc85ee4734", - "reference": "46eeedb08f0832b1b61a84c612d945fc85ee4734", + "url": "https://api.github.com/repos/symfony/mailer/zipball/cd60799210c488f545ddde2444dc1aa548322872", + "reference": "cd60799210c488f545ddde2444dc1aa548322872", "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" + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.0.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/mime": "^5.4|^6.0", + "symfony/service-contracts": "^1.1|^2|^3" }, "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" + "symfony/http-kernel": "<5.4" }, "require-dev": { - "egulias/email-validator": "^2.1.10|^3.1", - "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" + "symfony/http-client-contracts": "^1.1|^2|^3", + "symfony/messenger": "^5.4|^6.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Mime\\": "" + "Symfony\\Component\\Mailer\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3325,14 +3480,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Allows manipulating MIME messages", + "description": "Helps sending emails", "homepage": "https://symfony.com", - "keywords": [ - "mime", - "mime-type" - ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.16" + "source": "https://github.com/symfony/mailer/tree/v6.0.19" }, "funding": [ { @@ -3348,48 +3499,50 @@ "type": "tidelift" } ], - "time": "2022-11-26T16:45:22+00:00" + "time": "2023-01-11T11:50:03+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "name": "symfony/mime", + "version": "v6.0.19", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "url": "https://github.com/symfony/mime.git", + "reference": "d7052547a0070cbeadd474e172b527a00d657301" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/mime/zipball/d7052547a0070cbeadd474e172b527a00d657301", + "reference": "d7052547a0070cbeadd474e172b527a00d657301", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.0.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" }, - "provide": { - "ext-ctype": "*" + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<5.4", + "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" }, - "suggest": { - "ext-ctype": "For best performance" + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/property-info": "^5.4|^6.0", + "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" }, "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\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3397,24 +3550,22 @@ ], "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": "Allows manipulating MIME messages", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" + "mime", + "mime-type" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/mime/tree/v6.0.19" }, "funding": [ { @@ -3430,30 +3581,30 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-11T11:50:03+00:00" }, { - "name": "symfony/polyfill-iconv", + "name": "symfony/polyfill-ctype", "version": "v1.27.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "927013f3aac555983a5059aada98e1907d842695" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/927013f3aac555983a5059aada98e1907d842695", - "reference": "927013f3aac555983a5059aada98e1907d842695", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { - "ext-iconv": "*" + "ext-ctype": "*" }, "suggest": { - "ext-iconv": "For best performance" + "ext-ctype": "For best performance" }, "type": "library", "extra": { @@ -3470,7 +3621,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Iconv\\": "" + "Symfony\\Polyfill\\Ctype\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -3479,25 +3630,24 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Iconv extension", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "iconv", + "ctype", "polyfill", - "portable", - "shim" + "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" }, "funding": [ { @@ -3927,17 +4077,17 @@ "time": "2022-11-03T14:55:06+00:00" }, { - "name": "symfony/polyfill-php73", + "name": "symfony/polyfill-php80", "version": "v1.27.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "shasum": "" }, "require": { @@ -3958,7 +4108,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" + "Symfony\\Polyfill\\Php80\\": "" }, "classmap": [ "Resources/stubs" @@ -3969,6 +4119,10 @@ "MIT" ], "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -3978,7 +4132,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -3987,7 +4141,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" }, "funding": [ { @@ -4006,17 +4160,17 @@ "time": "2022-11-03T14:55:06+00:00" }, { - "name": "symfony/polyfill-php80", + "name": "symfony/polyfill-php81", "version": "v1.27.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", "shasum": "" }, "require": { @@ -4037,7 +4191,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Polyfill\\Php81\\": "" }, "classmap": [ "Resources/stubs" @@ -4048,10 +4202,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -4061,7 +4211,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -4070,7 +4220,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" }, "funding": [ { @@ -4089,22 +4239,28 @@ "time": "2022-11-03T14:55:06+00:00" }, { - "name": "symfony/polyfill-php81", + "name": "symfony/polyfill-uuid", "version": "v1.27.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "f3cf1a645c2734236ed1e2e671e273eeb3586166" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/f3cf1a645c2734236ed1e2e671e273eeb3586166", + "reference": "f3cf1a645c2734236ed1e2e671e273eeb3586166", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, "type": "library", "extra": { "branch-alias": { @@ -4120,11 +4276,8 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] + "Symfony\\Polyfill\\Uuid\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4132,24 +4285,24 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "description": "Symfony polyfill for uuid functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", "polyfill", "portable", - "shim" + "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.27.0" }, "funding": [ { @@ -4169,21 +4322,20 @@ }, { "name": "symfony/process", - "version": "v5.4.11", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1" + "reference": "2114fd60f26a296cc403a7939ab91478475a33d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1", - "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1", + "url": "https://api.github.com/repos/symfony/process/zipball/2114fd60f26a296cc403a7939ab91478475a33d4", + "reference": "2114fd60f26a296cc403a7939ab91478475a33d4", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2" }, "type": "library", "autoload": { @@ -4211,7 +4363,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.11" + "source": "https://github.com/symfony/process/tree/v6.0.19" }, "funding": [ { @@ -4227,41 +4379,39 @@ "type": "tidelift" } ], - "time": "2022-06-27T16:58:25+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/routing", - "version": "v5.4.15", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "5c9b129efe9abce9470e384bf65d8a7e262eee69" + "reference": "e56ca9b41c1ec447193474cd86ad7c0b547755ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/5c9b129efe9abce9470e384bf65d8a7e262eee69", - "reference": "5c9b129efe9abce9470e384bf65d8a7e262eee69", + "url": "https://api.github.com/repos/symfony/routing/zipball/e56ca9b41c1ec447193474cd86ad7c0b547755ac", + "reference": "e56ca9b41c1ec447193474cd86ad7c0b547755ac", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2" }, "conflict": { "doctrine/annotations": "<1.12", - "symfony/config": "<5.3", - "symfony/dependency-injection": "<4.4", - "symfony/yaml": "<4.4" + "symfony/config": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/yaml": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.12", + "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" + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" }, "suggest": { "symfony/config": "For using the all-in-one router or any loader", @@ -4301,7 +4451,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.15" + "source": "https://github.com/symfony/routing/tree/v6.0.19" }, "funding": [ { @@ -4317,26 +4467,25 @@ "type": "tidelift" } ], - "time": "2022-10-13T14:10:41+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.2", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d78d39c1599bd1188b8e26bb341da52c3c6d8a66", + "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.0.2", + "psr/container": "^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -4347,7 +4496,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", @@ -4384,7 +4533,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/service-contracts/tree/v3.0.2" }, "funding": [ { @@ -4400,38 +4549,37 @@ "type": "tidelift" } ], - "time": "2022-05-30T19:17:29+00:00" + "time": "2022-05-30T19:17:58+00:00" }, { "name": "symfony/string", - "version": "v5.4.15", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed" + "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", - "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", + "url": "https://api.github.com/repos/symfony/string/zipball/d9e72497367c23e08bf94176d2be45b00a9d232a", + "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.0" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation-contracts": "^2.0|^3.0", + "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -4470,7 +4618,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.15" + "source": "https://github.com/symfony/string/tree/v6.0.19" }, "funding": [ { @@ -4486,52 +4634,50 @@ "type": "tidelift" } ], - "time": "2022-10-05T15:16:54+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/translation", - "version": "v5.4.14", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "f0ed07675863aa6e3939df8b1bc879450b585cab" + "reference": "9c24b3fdbbe9fb2ef3a6afd8bbaadfd72dad681f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/f0ed07675863aa6e3939df8b1bc879450b585cab", - "reference": "f0ed07675863aa6e3939df8b1bc879450b585cab", + "url": "https://api.github.com/repos/symfony/translation/zipball/9c24b3fdbbe9fb2ef3a6afd8bbaadfd72dad681f", + "reference": "9c24b3fdbbe9fb2ef3a6afd8bbaadfd72dad681f", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.0.2", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/translation-contracts": "^2.3" + "symfony/translation-contracts": "^2.3|^3.0" }, "conflict": { - "symfony/config": "<4.4", - "symfony/console": "<5.3", - "symfony/dependency-injection": "<5.0", - "symfony/http-kernel": "<5.0", - "symfony/twig-bundle": "<5.0", - "symfony/yaml": "<4.4" + "symfony/config": "<5.4", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/twig-bundle": "<5.4", + "symfony/yaml": "<5.4" }, "provide": { - "symfony/translation-implementation": "2.3" + "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^4.4|^5.0|^6.0", + "symfony/config": "^5.4|^6.0", "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", "symfony/http-client-contracts": "^1.1|^2.0|^3.0", - "symfony/http-kernel": "^5.0|^6.0", - "symfony/intl": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/intl": "^5.4|^6.0", "symfony/polyfill-intl-icu": "^1.21", "symfony/service-contracts": "^1.1.2|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" + "symfony/yaml": "^5.4|^6.0" }, "suggest": { "psr/log-implementation": "To use logging capability in translator", @@ -4556,18 +4702,96 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v6.0.19" + }, + "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-01T08:36:10+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "acbfbb274e730e5a0236f619b6168d9dedb3e282" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/acbfbb274e730e5a0236f619b6168d9dedb3e282", + "reference": "acbfbb274e730e5a0236f619b6168d9dedb3e282", + "shasum": "" + }, + "require": { + "php": ">=8.0.2" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "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": "Provides tools to internationalize your application", + "description": "Generic abstractions related to translation", "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "source": "https://github.com/symfony/translation/tree/v5.4.14" + "source": "https://github.com/symfony/translation-contracts/tree/v3.0.2" }, "funding": [ { @@ -4583,48 +4807,47 @@ "type": "tidelift" } ], - "time": "2022-10-07T08:01:20+00:00" + "time": "2022-06-27T17:10:44+00:00" }, { - "name": "symfony/translation-contracts", - "version": "v2.5.2", + "name": "symfony/uid", + "version": "v6.0.19", "source": { "type": "git", - "url": "https://github.com/symfony/translation-contracts.git", - "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe" + "url": "https://github.com/symfony/uid.git", + "reference": "6499e28b0ac9f2aa3151e11845bdb5cd21e6bb9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe", - "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe", + "url": "https://api.github.com/repos/symfony/uid/zipball/6499e28b0ac9f2aa3151e11845bdb5cd21e6bb9d", + "reference": "6499e28b0ac9f2aa3151e11845bdb5cd21e6bb9d", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=8.0.2", + "symfony/polyfill-uuid": "^1.15" }, - "suggest": { - "symfony/translation-implementation": "" + "require-dev": { + "symfony/console": "^5.4|^6.0" }, "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\\Translation\\": "" - } + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -4634,18 +4857,15 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to translation", + "description": "Provides an object-oriented API to generate and represent UIDs", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "UID", + "ulid", + "uuid" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/uid/tree/v6.0.19" }, "funding": [ { @@ -4661,36 +4881,35 @@ "type": "tidelift" } ], - "time": "2022-06-27T16:58:25+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.14", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "6894d06145fefebd9a4c7272baa026a1c394a430" + "reference": "eb980457fa6899840fe1687e8627a03a7d8a3d52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6894d06145fefebd9a4c7272baa026a1c394a430", - "reference": "6894d06145fefebd9a4c7272baa026a1c394a430", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/eb980457fa6899840fe1687e8627a03a7d8a3d52", + "reference": "eb980457fa6899840fe1687e8627a03a7d8a3d52", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "phpunit/phpunit": "<5.4.3", - "symfony/console": "<4.4" + "symfony/console": "<5.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", + "symfony/console": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/uid": "^5.4|^6.0", "twig/twig": "^2.13|^3.0.4" }, "suggest": { @@ -4734,7 +4953,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.14" + "source": "https://github.com/symfony/var-dumper/tree/v6.0.19" }, "funding": [ { @@ -4750,20 +4969,20 @@ "type": "tidelift" } ], - "time": "2022-10-07T08:01:20+00:00" + "time": "2023-01-20T17:44:14+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.5", + "version": "2.2.6", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "4348a3a06651827a27d989ad1d13efec6bb49b19" + "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/4348a3a06651827a27d989ad1d13efec6bb49b19", - "reference": "4348a3a06651827a27d989ad1d13efec6bb49b19", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/c42125b83a4fa63b187fdf29f9c93cb7733da30c", + "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c", "shasum": "" }, "require": { @@ -4801,9 +5020,9 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.5" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.6" }, - "time": "2022-09-12T13:28:28+00:00" + "time": "2023-01-03T09:29:04+00:00" }, { "name": "vlucas/phpdotenv", @@ -4891,16 +5110,16 @@ }, { "name": "voku/portable-ascii", - "version": "1.6.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "87337c91b9dfacee02452244ee14ab3c43bc485a" + "reference": "b56450eed252f6801410d810c8e1727224ae0743" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/87337c91b9dfacee02452244ee14ab3c43bc485a", - "reference": "87337c91b9dfacee02452244ee14ab3c43bc485a", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", + "reference": "b56450eed252f6801410d810c8e1727224ae0743", "shasum": "" }, "require": { @@ -4937,7 +5156,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/1.6.1" + "source": "https://github.com/voku/portable-ascii/tree/2.0.1" }, "funding": [ { @@ -4961,7 +5180,7 @@ "type": "tidelift" } ], - "time": "2022-01-24T18:55:24+00:00" + "time": "2022-03-08T17:03:00+00:00" }, { "name": "webmozart/assert", @@ -5264,16 +5483,16 @@ }, { "name": "amphp/parallel", - "version": "v1.4.1", + "version": "v1.4.3", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "fbc128383c1ffb3823866f71b88d8c4722a25ce9" + "reference": "3aac213ba7858566fd83d38ccb85b91b2d652cb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/fbc128383c1ffb3823866f71b88d8c4722a25ce9", - "reference": "fbc128383c1ffb3823866f71b88d8c4722a25ce9", + "url": "https://api.github.com/repos/amphp/parallel/zipball/3aac213ba7858566fd83d38ccb85b91b2d652cb0", + "reference": "3aac213ba7858566fd83d38ccb85b91b2d652cb0", "shasum": "" }, "require": { @@ -5326,7 +5545,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v1.4.1" + "source": "https://github.com/amphp/parallel/tree/v1.4.3" }, "funding": [ { @@ -5334,7 +5553,7 @@ "type": "github" } ], - "time": "2021-10-25T19:16:02+00:00" + "time": "2023-03-23T08:04:23+00:00" }, { "name": "amphp/parallel-functions", @@ -5396,29 +5615,30 @@ }, { "name": "amphp/parser", - "version": "v1.0.0", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/amphp/parser.git", - "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1" + "reference": "ff1de4144726c5dad5fab97f66692ebe8de3e151" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parser/zipball/f83e68f03d5b8e8e0365b8792985a7f341c57ae1", - "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1", + "url": "https://api.github.com/repos/amphp/parser/zipball/ff1de4144726c5dad5fab97f66692ebe8de3e151", + "reference": "ff1de4144726c5dad5fab97f66692ebe8de3e151", "shasum": "" }, "require": { - "php": ">=7" + "php": ">=7.4" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.3", - "phpunit/phpunit": "^6" + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" }, "type": "library", "autoload": { "psr-4": { - "Amp\\Parser\\": "lib" + "Amp\\Parser\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -5426,13 +5646,13 @@ "MIT" ], "authors": [ - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" } ], "description": "A generator parser to make streaming parsers simple.", @@ -5445,9 +5665,15 @@ ], "support": { "issues": "https://github.com/amphp/parser/issues", - "source": "https://github.com/amphp/parser/tree/is-valid" + "source": "https://github.com/amphp/parser/tree/v1.1.0" }, - "time": "2017-06-06T05:29:10+00:00" + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2022-12-30T18:08:47+00:00" }, { "name": "amphp/process", @@ -6158,75 +6384,32 @@ }, "time": "2022-09-01T20:12:10+00:00" }, - { - "name": "doctrine/deprecations", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "shasum": "" - }, - "require": { - "php": "^7.1|^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" - }, - "time": "2022-05-02T15:47:09+00:00" - }, { "name": "doctrine/instantiator", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9", + "doctrine/coding-standard": "^9 || ^11", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^0.16 || ^1", "phpstan/phpstan": "^1.4", "phpstan/phpstan-phpunit": "^1", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.22" + "vimeo/psalm": "^4.30 || ^5.4" }, "type": "library", "autoload": { @@ -6253,7 +6436,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" }, "funding": [ { @@ -6269,7 +6452,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T08:28:38+00:00" + "time": "2022-12-30T00:15:36+00:00" }, { "name": "fakerphp/faker", @@ -6725,16 +6908,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": { @@ -6772,7 +6955,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": [ { @@ -6780,7 +6963,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "netresearch/jsonmapper", @@ -6835,16 +7018,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.2", + "version": "v4.15.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc" + "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", "shasum": "" }, "require": { @@ -6885,9 +7068,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" }, - "time": "2022-11-12T15:38:23+00:00" + "time": "2023-03-05T19:49:14+00:00" }, { "name": "ondram/ci-detector", @@ -7022,30 +7205,34 @@ }, { "name": "orchestra/testbench", - "version": "v6.25.1", + "version": "v7.24.1", "source": { "type": "git", "url": "https://github.com/orchestral/testbench.git", - "reference": "0516123d26d64117bc04f7e9cb982eae2624e750" + "reference": "6c38cf3d6a3523a25974d8457ca94439eaf12ab0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/0516123d26d64117bc04f7e9cb982eae2624e750", - "reference": "0516123d26d64117bc04f7e9cb982eae2624e750", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/6c38cf3d6a3523a25974d8457ca94439eaf12ab0", + "reference": "6c38cf3d6a3523a25974d8457ca94439eaf12ab0", "shasum": "" }, "require": { - "laravel/framework": "^8.75", - "mockery/mockery": "^1.4.4", - "orchestra/testbench-core": "^6.29.1", - "php": "^7.3 || ^8.0", - "phpunit/phpunit": "^8.5.21 || ^9.5.10", - "spatie/laravel-ray": "^1.26.2" + "fakerphp/faker": "^1.21", + "laravel/framework": "^9.52.4", + "mockery/mockery": "^1.5.1", + "orchestra/testbench-core": "^7.24.1", + "php": "^8.0", + "phpunit/phpunit": "^9.5.10", + "spatie/laravel-ray": "^1.32.4", + "symfony/process": "^6.0.9", + "symfony/yaml": "^6.0.9", + "vlucas/phpdotenv": "^5.4.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.0-dev" + "dev-master": "7.0-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -7071,55 +7258,51 @@ ], "support": { "issues": "https://github.com/orchestral/testbench/issues", - "source": "https://github.com/orchestral/testbench/tree/v6.25.1" + "source": "https://github.com/orchestral/testbench/tree/v7.24.1" }, - "funding": [ - { - "url": "https://paypal.me/crynobone", - "type": "custom" - }, - { - "url": "https://liberapay.com/crynobone", - "type": "liberapay" - } - ], - "time": "2022-10-11T14:01:10+00:00" + "time": "2023-04-03T01:22:44+00:00" }, { "name": "orchestra/testbench-core", - "version": "v6.29.1", + "version": "v7.24.1", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "29a7586915885f89b8d2203efe20f76afe9cf956" + "reference": "4d9277728235a7fe3724397b8195dda3d39e1bdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/29a7586915885f89b8d2203efe20f76afe9cf956", - "reference": "29a7586915885f89b8d2203efe20f76afe9cf956", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/4d9277728235a7fe3724397b8195dda3d39e1bdf", + "reference": "4d9277728235a7fe3724397b8195dda3d39e1bdf", "shasum": "" }, "require": { - "fakerphp/faker": "^1.9.1", - "php": "^7.3 || ^8.0", - "symfony/yaml": "^5.0", - "vlucas/phpdotenv": "^5.1" + "php": "^8.0" }, "require-dev": { - "laravel/framework": "^8.75", - "laravel/laravel": "8.x-dev", - "mockery/mockery": "^1.4.4", - "orchestra/canvas": "^6.1", - "phpunit/phpunit": "^8.5.21 || ^9.5.10", - "spatie/laravel-ray": "^1.7.1", - "symfony/process": "^5.0" + "fakerphp/faker": "^1.21", + "laravel/framework": "^9.52.4", + "laravel/pint": "^1.4", + "mockery/mockery": "^1.5.1", + "orchestra/canvas": "^7.0", + "phpstan/phpstan": "^1.10.7", + "phpunit/phpunit": "^9.5.10", + "spatie/laravel-ray": "^1.32.4", + "symfony/process": "^6.0.9", + "symfony/yaml": "^6.0.9", + "vlucas/phpdotenv": "^5.4.1" }, "suggest": { - "laravel/framework": "Required for testing (^8.75).", - "mockery/mockery": "Allow using Mockery for testing (^1.4.4).", - "orchestra/testbench-browser-kit": "Allow using legacy Laravel BrowserKit for testing (^6.0).", - "orchestra/testbench-dusk": "Allow using Laravel Dusk for testing (^6.0).", - "phpunit/phpunit": "Allow using PHPUnit for testing (^8.5.21|^9.5.10|^10.0)." + "brianium/paratest": "Allow using parallel tresting (^6.4).", + "fakerphp/faker": "Allow using Faker for testing (^1.21).", + "laravel/framework": "Required for testing (^9.52.4).", + "mockery/mockery": "Allow using Mockery for testing (^1.5.1).", + "nunomaduro/collision": "Allow using Laravel style tests output and parallel testing (^6.2).", + "orchestra/testbench-browser-kit": "Allow using legacy Laravel BrowserKit for testing (^7.0).", + "orchestra/testbench-dusk": "Allow using Laravel Dusk for testing (^7.0).", + "phpunit/phpunit": "Allow using PHPUnit for testing (^9.5.10).", + "symfony/yaml": "Required for CLI Commander (^6.0.9).", + "vlucas/phpdotenv": "Required for CLI Commander (^5.4.1)." }, "bin": [ "testbench" @@ -7127,7 +7310,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.0-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -7154,26 +7337,16 @@ "keywords": [ "BDD", "TDD", + "dev", "laravel", - "orchestra-platform", - "orchestral", + "laravel-packages", "testing" ], "support": { "issues": "https://github.com/orchestral/testbench/issues", "source": "https://github.com/orchestral/testbench-core" }, - "funding": [ - { - "url": "https://paypal.me/crynobone", - "type": "custom" - }, - { - "url": "https://liberapay.com/crynobone", - "type": "liberapay" - } - ], - "time": "2022-10-11T12:12:52+00:00" + "time": "2023-04-02T16:09:59+00:00" }, { "name": "phar-io/manifest", @@ -7398,24 +7571,27 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "dfc078e8af9c99210337325ff5aa152872c98714" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", + "reference": "dfc078e8af9c99210337325ff5aa152872c98714", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -7447,22 +7623,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" }, - "time": "2022-10-14T12:47:21+00:00" + "time": "2023-03-27T19:02:04+00:00" }, { "name": "phpro/grumphp", - "version": "v1.13.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpro/grumphp.git", - "reference": "3ec61c1678c4c370f02b05fef606fd561d923c8e" + "reference": "533e45484be80d426010a318ff6f99fbe33350a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpro/grumphp/zipball/3ec61c1678c4c370f02b05fef606fd561d923c8e", - "reference": "3ec61c1678c4c370f02b05fef606fd561d923c8e", + "url": "https://api.github.com/repos/phpro/grumphp/zipball/533e45484be80d426010a318ff6f99fbe33350a5", + "reference": "533e45484be80d426010a318ff6f99fbe33350a5", "shasum": "" }, "require": { @@ -7470,25 +7646,25 @@ "amphp/parallel": "^1.4", "amphp/parallel-functions": "^1.1", "composer-plugin-api": "~2.0", - "doctrine/collections": "^1.6.8", + "doctrine/collections": "^1.6.8 || ^2.0", "ext-json": "*", "gitonomy/gitlib": "^1.3", "laravel/serializable-closure": "^1.1", "monolog/monolog": "^2.0 || ^3.0", "ondram/ci-detector": "^4.0", - "php": "^7.4 || ^8.0", + "php": "^8.0", "psr/container": "^1.1 || ^2.0", "seld/jsonlint": "~1.8", - "symfony/config": "~5.3 || ~6.0", - "symfony/console": "~5.3 || ~6.0", - "symfony/dependency-injection": "~5.3 || ~6.0", - "symfony/dotenv": "~5.3 || ~6.0", - "symfony/event-dispatcher": "~5.3 || ~6.0", - "symfony/filesystem": "~5.3 || ~6.0", - "symfony/finder": "~5.3 || ~6.0", - "symfony/options-resolver": "~5.3 || ~6.0", - "symfony/process": "~5.3 || ~6.0", - "symfony/yaml": "~5.3 || ~6.0" + "symfony/config": "~5.4 || ~6.0", + "symfony/console": "~5.4 || ~6.0", + "symfony/dependency-injection": "~5.4 || ~6.0", + "symfony/dotenv": "~5.4 || ~6.0", + "symfony/event-dispatcher": "~5.4 || ~6.0", + "symfony/filesystem": "~5.4 || ~6.0", + "symfony/finder": "~5.4 || ~6.0", + "symfony/options-resolver": "~5.4 || ~6.0", + "symfony/process": "~5.4 || ~6.0", + "symfony/yaml": "~5.4 || ~6.0" }, "require-dev": { "amphp/sync": "^v1.4", @@ -7521,11 +7697,13 @@ "phan/phan": "Lets GrumPHP unleash a static analyzer on your code", "phing/phing": "Lets GrumPHP run your automated PHP tasks.", "php-parallel-lint/php-parallel-lint": "Lets GrumPHP quickly lint your entire code base.", + "phparkitect/phparkitect": "Let GrumPHP keep your codebase coherent and solid, by permitting to add some architectural constraint check to your workflow.", "phpmd/phpmd": "Lets GrumPHP sort out the mess in your code", "phpspec/phpspec": "Lets GrumPHP spec your code.", "phpstan/phpstan": "Lets GrumPHP discover bugs in your code without running it.", "phpunit/phpunit": "Lets GrumPHP run your unit tests.", "povils/phpmnd": "Lets GrumPHP help you detect magic numbers in PHP code.", + "rector/rector ": "Lets GrumPHP instantly upgrade and automatically refactor your PHP code.", "roave/security-advisories": "Lets GrumPHP be sure that there are no known security issues.", "sebastian/phpcpd": "Lets GrumPHP find duplicated code.", "squizlabs/php_codesniffer": "Lets GrumPHP sniff on your code.", @@ -7563,22 +7741,22 @@ "description": "A composer plugin that enables source code quality checks.", "support": { "issues": "https://github.com/phpro/grumphp/issues", - "source": "https://github.com/phpro/grumphp/tree/v1.13.0" + "source": "https://github.com/phpro/grumphp/tree/v1.15.0" }, - "time": "2022-06-24T08:32:25+00:00" + "time": "2022-12-22T12:36:10+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.15.3", + "version": "1.17.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "61800f71a5526081d1b5633766aa88341f1ade76" + "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/61800f71a5526081d1b5633766aa88341f1ade76", - "reference": "61800f71a5526081d1b5633766aa88341f1ade76", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", + "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", "shasum": "" }, "require": { @@ -7608,22 +7786,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.15.3" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.17.1" }, - "time": "2022-12-20T20:56:55+00:00" + "time": "2023-04-04T11:11:22+00:00" }, { "name": "phpstan/phpstan", - "version": "1.9.4", + "version": "1.10.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "d03bccee595e2146b7c9d174486b84f4dc61b0f2" + "reference": "f1e22c9b17a879987f8743d81533250a5fff47f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d03bccee595e2146b7c9d174486b84f4dc61b0f2", - "reference": "d03bccee595e2146b7c9d174486b84f4dc61b0f2", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f1e22c9b17a879987f8743d81533250a5fff47f9", + "reference": "f1e22c9b17a879987f8743d81533250a5fff47f9", "shasum": "" }, "require": { @@ -7652,8 +7830,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.4" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -7669,27 +7850,27 @@ "type": "tidelift" } ], - "time": "2022-12-17T13:33:52+00:00" + "time": "2023-04-01T17:06:15+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.22", + "version": "9.2.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "e4bf60d2220b4baaa0572986b5d69870226b06df" + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e4bf60d2220b4baaa0572986b5d69870226b06df", - "reference": "e4bf60d2220b4baaa0572986b5d69870226b06df", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.15", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -7704,8 +7885,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { @@ -7738,7 +7919,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.22" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" }, "funding": [ { @@ -7746,7 +7927,7 @@ "type": "github" } ], - "time": "2022-12-18T16:40:55+00:00" + "time": "2023-03-06T12:58:08+00:00" }, { "name": "phpunit/php-file-iterator", @@ -7991,20 +8172,20 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.27", + "version": "9.6.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38" + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2bc7ffdca99f92d959b3f2270529334030bba38", - "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -8033,8 +8214,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" @@ -8042,7 +8223,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { @@ -8073,7 +8254,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.27" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" }, "funding": [ { @@ -8089,7 +8271,7 @@ "type": "tidelift" } ], - "time": "2022-12-09T07:31:23+00:00" + "time": "2023-03-27T11:43:46+00:00" }, { "name": "pimple/pimple", @@ -8624,16 +8806,16 @@ }, { "name": "sebastian/environment", - "version": "5.1.4", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { @@ -8675,7 +8857,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -8683,7 +8865,7 @@ "type": "github" } ], - "time": "2022-04-03T09:37:03+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", @@ -8997,16 +9179,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { @@ -9045,10 +9227,10 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { @@ -9056,7 +9238,7 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", @@ -9115,16 +9297,16 @@ }, { "name": "sebastian/type", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { @@ -9159,7 +9341,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { @@ -9167,7 +9349,7 @@ "type": "github" } ], - "time": "2022-09-12T14:47:03+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -9349,16 +9531,16 @@ }, { "name": "spatie/backtrace", - "version": "1.2.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/spatie/backtrace.git", - "reference": "4ee7d41aa5268107906ea8a4d9ceccde136dbd5b" + "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/4ee7d41aa5268107906ea8a4d9ceccde136dbd5b", - "reference": "4ee7d41aa5268107906ea8a4d9ceccde136dbd5b", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/ec4dd16476b802dbdc6b4467f84032837e316b8c", + "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c", "shasum": "" }, "require": { @@ -9367,6 +9549,7 @@ "require-dev": { "ext-json": "*", "phpunit/phpunit": "^9.3", + "spatie/phpunit-snapshot-assertions": "^4.2", "symfony/var-dumper": "^5.1" }, "type": "library", @@ -9394,8 +9577,7 @@ "spatie" ], "support": { - "issues": "https://github.com/spatie/backtrace/issues", - "source": "https://github.com/spatie/backtrace/tree/1.2.1" + "source": "https://github.com/spatie/backtrace/tree/1.4.0" }, "funding": [ { @@ -9407,41 +9589,42 @@ "type": "other" } ], - "time": "2021-11-09T10:57:15+00:00" + "time": "2023-03-04T08:57:24+00:00" }, { "name": "spatie/laravel-ray", - "version": "1.31.0", + "version": "1.32.4", "source": { "type": "git", "url": "https://github.com/spatie/laravel-ray.git", - "reference": "7394694afd89d05879e7a69c54abab73c1199acd" + "reference": "2274653f0a90dd87fbb887437be1c1ea1388a47c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/7394694afd89d05879e7a69c54abab73c1199acd", - "reference": "7394694afd89d05879e7a69c54abab73c1199acd", + "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/2274653f0a90dd87fbb887437be1c1ea1388a47c", + "reference": "2274653f0a90dd87fbb887437be1c1ea1388a47c", "shasum": "" }, "require": { "ext-json": "*", - "illuminate/contracts": "^7.20|^8.19|^9.0", - "illuminate/database": "^7.20|^8.19|^9.0", - "illuminate/queue": "^7.20|^8.19|^9.0", - "illuminate/support": "^7.20|^8.19|^9.0", - "php": "^7.3|^8.0", + "illuminate/contracts": "^7.20|^8.19|^9.0|^10.0", + "illuminate/database": "^7.20|^8.19|^9.0|^10.0", + "illuminate/queue": "^7.20|^8.19|^9.0|^10.0", + "illuminate/support": "^7.20|^8.19|^9.0|^10.0", + "php": "^7.4|^8.0", "spatie/backtrace": "^1.0", - "spatie/ray": "^1.33", + "spatie/ray": "^1.37", "symfony/stopwatch": "4.2|^5.1|^6.0", "zbateson/mail-mime-parser": "^1.3.1|^2.0" }, "require-dev": { "guzzlehttp/guzzle": "^7.3", - "laravel/framework": "^7.20|^8.19|^9.0", - "orchestra/testbench-core": "^5.0|^6.0|^7.0", + "laravel/framework": "^7.20|^8.19|^9.0|^10.0", + "orchestra/testbench-core": "^5.0|^6.0|^7.0|^8.0", + "pestphp/pest": "^1.22", "phpstan/phpstan": "^0.12.93", "phpunit/phpunit": "^9.3", - "spatie/phpunit-snapshot-assertions": "^4.2" + "spatie/pest-plugin-snapshots": "^1.1" }, "type": "library", "extra": { @@ -9479,7 +9662,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-ray/issues", - "source": "https://github.com/spatie/laravel-ray/tree/1.31.0" + "source": "https://github.com/spatie/laravel-ray/tree/1.32.4" }, "funding": [ { @@ -9491,24 +9674,24 @@ "type": "other" } ], - "time": "2022-09-20T13:13:22+00:00" + "time": "2023-03-23T08:04:54+00:00" }, { "name": "spatie/macroable", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/spatie/macroable.git", - "reference": "7a99549fc001c925714b329220dea680c04bfa48" + "reference": "ec2c320f932e730607aff8052c44183cf3ecb072" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/macroable/zipball/7a99549fc001c925714b329220dea680c04bfa48", - "reference": "7a99549fc001c925714b329220dea680c04bfa48", + "url": "https://api.github.com/repos/spatie/macroable/zipball/ec2c320f932e730607aff8052c44183cf3ecb072", + "reference": "ec2c320f932e730607aff8052c44183cf3ecb072", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^8.0" }, "require-dev": { "phpunit/phpunit": "^8.0|^9.3" @@ -9539,22 +9722,22 @@ ], "support": { "issues": "https://github.com/spatie/macroable/issues", - "source": "https://github.com/spatie/macroable/tree/1.0.1" + "source": "https://github.com/spatie/macroable/tree/2.0.0" }, - "time": "2020-11-03T10:15:05+00:00" + "time": "2021-03-26T22:39:02+00:00" }, { "name": "spatie/ray", - "version": "1.36.0", + "version": "1.37.1", "source": { "type": "git", "url": "https://github.com/spatie/ray.git", - "reference": "4a4def8cda4806218341b8204c98375aa8c34323" + "reference": "a915e327f04c0fbed3bdd26e076e39feea091062" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/ray/zipball/4a4def8cda4806218341b8204c98375aa8c34323", - "reference": "4a4def8cda4806218341b8204c98375aa8c34323", + "url": "https://api.github.com/repos/spatie/ray/zipball/a915e327f04c0fbed3bdd26e076e39feea091062", + "reference": "a915e327f04c0fbed3bdd26e076e39feea091062", "shasum": "" }, "require": { @@ -9569,8 +9752,9 @@ }, "require-dev": { "illuminate/support": "6.x|^8.18|^9.0", - "nesbot/carbon": "^2.43", - "phpstan/phpstan": "^0.12.92", + "nesbot/carbon": "^2.63", + "pestphp/pest": "^1.22", + "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.5", "spatie/phpunit-snapshot-assertions": "^4.2", "spatie/test-time": "^1.2" @@ -9604,7 +9788,7 @@ ], "support": { "issues": "https://github.com/spatie/ray/issues", - "source": "https://github.com/spatie/ray/tree/1.36.0" + "source": "https://github.com/spatie/ray/tree/1.37.1" }, "funding": [ { @@ -9616,20 +9800,20 @@ "type": "other" } ], - "time": "2022-08-11T14:04:18+00:00" + "time": "2023-03-06T07:22:28+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.1", + "version": "3.7.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", "shasum": "" }, "require": { @@ -9665,46 +9849,46 @@ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], "support": { "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2022-06-18T07:21:10+00:00" + "time": "2023-02-22T23:07:41+00:00" }, { "name": "symfony/config", - "version": "v5.4.11", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "ec79e03125c1d2477e43dde8528535d90cc78379" + "reference": "db4fc45c24e0c3e2198e68ada9d7f90daa1f97e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/ec79e03125c1d2477e43dde8528535d90cc78379", - "reference": "ec79e03125c1d2477e43dde8528535d90cc78379", + "url": "https://api.github.com/repos/symfony/config/zipball/db4fc45c24e0c3e2198e68ada9d7f90daa1f97e3", + "reference": "db4fc45c24e0c3e2198e68ada9d7f90daa1f97e3", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^5.4|^6.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", "symfony/polyfill-php81": "^1.22" }, "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/event-dispatcher": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/messenger": "^5.4|^6.0", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" + "symfony/yaml": "^5.4|^6.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -9735,7 +9919,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.11" + "source": "https://github.com/symfony/config/tree/v6.0.19" }, "funding": [ { @@ -9751,45 +9935,44 @@ "type": "tidelift" } ], - "time": "2022-07-20T13:00:38+00:00" + "time": "2023-01-09T04:36:00+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.16", + "version": "v6.0.20", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "a93e1863500940780fc1235f52d54397be2d14b3" + "reference": "359806e1adebd1c43e18e5ea22acd14bef7fcf8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a93e1863500940780fc1235f52d54397be2d14b3", - "reference": "a93e1863500940780fc1235f52d54397be2d14b3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/359806e1adebd1c43e18e5ea22acd14bef7fcf8c", + "reference": "359806e1adebd1c43e18e5ea22acd14bef7fcf8c", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1.1", + "php": ">=8.0.2", + "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16", "symfony/polyfill-php81": "^1.22", - "symfony/service-contracts": "^1.1.6|^2" + "symfony/service-contracts": "^1.1.6|^2.0|^3.0" }, "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" + "symfony/config": "<5.4", + "symfony/finder": "<5.4", + "symfony/proxy-manager-bridge": "<5.4", + "symfony/yaml": "<5.4" }, "provide": { - "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0|2.0" + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.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" + "symfony/config": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" }, "suggest": { "symfony/config": "", @@ -9824,7 +10007,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.16" + "source": "https://github.com/symfony/dependency-injection/tree/v6.0.20" }, "funding": [ { @@ -9840,29 +10023,28 @@ "type": "tidelift" } ], - "time": "2022-11-25T07:33:13+00:00" + "time": "2023-01-30T15:41:07+00:00" }, { "name": "symfony/dotenv", - "version": "v5.4.5", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "83a2310904a4f5d4f42526227b5a578ac82232a9" + "reference": "9cee123707e689f7e06c09624c145d206468bcf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/83a2310904a4f5d4f42526227b5a578ac82232a9", - "reference": "83a2310904a4f5d4f42526227b5a578ac82232a9", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/9cee123707e689f7e06c09624c145d206468bcf2", + "reference": "9cee123707e689f7e06c09624c145d206468bcf2", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.0.2" }, "require-dev": { - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0" + "symfony/console": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -9895,7 +10077,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v5.4.5" + "source": "https://github.com/symfony/dotenv/tree/v6.0.19" }, "funding": [ { @@ -9911,27 +10093,26 @@ "type": "tidelift" } ], - "time": "2022-02-15T17:04:12+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.13", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ac09569844a9109a5966b9438fc29113ce77cf51" + "reference": "3d49eec03fda1f0fc19b7349fbbe55ebc1004214" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ac09569844a9109a5966b9438fc29113ce77cf51", - "reference": "ac09569844a9109a5966b9438fc29113ce77cf51", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3d49eec03fda1f0fc19b7349fbbe55ebc1004214", + "reference": "3d49eec03fda1f0fc19b7349fbbe55ebc1004214", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "~1.8" }, "type": "library", "autoload": { @@ -9959,7 +10140,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.13" + "source": "https://github.com/symfony/filesystem/tree/v6.0.19" }, "funding": [ { @@ -9975,27 +10156,25 @@ "type": "tidelift" } ], - "time": "2022-09-21T19:53:16+00:00" + "time": "2023-01-20T17:44:14+00:00" }, { "name": "symfony/options-resolver", - "version": "v5.4.11", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690" + "reference": "6a180d1c45e0d9797470ca9eb46215692de00fa3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/54f14e36aa73cb8f7261d7686691fd4d75ea2690", - "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/6a180d1c45e0d9797470ca9eb46215692de00fa3", + "reference": "6a180d1c45e0d9797470ca9eb46215692de00fa3", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2", + "symfony/deprecation-contracts": "^2.1|^3" }, "type": "library", "autoload": { @@ -10028,7 +10207,90 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.11" + "source": "https://github.com/symfony/options-resolver/tree/v6.0.19" + }, + "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-01T08:36:10+00:00" + }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "927013f3aac555983a5059aada98e1907d842695" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/927013f3aac555983a5059aada98e1907d842695", + "reference": "927013f3aac555983a5059aada98e1907d842695", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-iconv": "*" + }, + "suggest": { + "ext-iconv": "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\\Iconv\\": "" + } + }, + "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 Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.27.0" }, "funding": [ { @@ -10044,24 +10306,24 @@ "type": "tidelift" } ], - "time": "2022-07-20T13:00:38+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.4.13", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "6df7a3effde34d81717bbef4591e5ffe32226d69" + "reference": "011e781839dd1d2eb8119f65ac516a530f60226d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/6df7a3effde34d81717bbef4591e5ffe32226d69", - "reference": "6df7a3effde34d81717bbef4591e5ffe32226d69", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/011e781839dd1d2eb8119f65ac516a530f60226d", + "reference": "011e781839dd1d2eb8119f65ac516a530f60226d", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/service-contracts": "^1|^2|^3" }, "type": "library", @@ -10090,7 +10352,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.13" + "source": "https://github.com/symfony/stopwatch/tree/v6.0.19" }, "funding": [ { @@ -10106,32 +10368,31 @@ "type": "tidelift" } ], - "time": "2022-09-28T13:19:49+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.16", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "ebd37c71f62d5ec5f6e27de3e06fee492d4c6298" + "reference": "deec3a812a0305a50db8ae689b183f43d915c884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/ebd37c71f62d5ec5f6e27de3e06fee492d4c6298", - "reference": "ebd37c71f62d5ec5f6e27de3e06fee492d4c6298", + "url": "https://api.github.com/repos/symfony/yaml/zipball/deec3a812a0305a50db8ae689b183f43d915c884", + "reference": "deec3a812a0305a50db8ae689b183f43d915c884", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.0.2", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<5.3" + "symfony/console": "<5.4" }, "require-dev": { - "symfony/console": "^5.3|^6.0" + "symfony/console": "^5.4|^6.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -10165,7 +10426,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.16" + "source": "https://github.com/symfony/yaml/tree/v6.0.19" }, "funding": [ { @@ -10181,7 +10442,7 @@ "type": "tidelift" } ], - "time": "2022-11-25T16:04:03+00:00" + "time": "2023-01-11T11:50:03+00:00" }, { "name": "theseer/tokenizer", @@ -10394,28 +10655,30 @@ }, { "name": "zbateson/mail-mime-parser", - "version": "2.2.3", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/zbateson/mail-mime-parser.git", - "reference": "295c7f82a8c44af685680d9df6714beb812e90ff" + "reference": "20b3e48eb799537683780bc8782fbbe9bc25934a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/295c7f82a8c44af685680d9df6714beb812e90ff", - "reference": "295c7f82a8c44af685680d9df6714beb812e90ff", + "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/20b3e48eb799537683780bc8782fbbe9bc25934a", + "reference": "20b3e48eb799537683780bc8782fbbe9bc25934a", "shasum": "" }, "require": { "guzzlehttp/psr7": "^1.7.0|^2.0", - "php": ">=5.4", + "php": ">=7.1", "pimple/pimple": "^3.0", "zbateson/mb-wrapper": "^1.0.1", "zbateson/stream-decorators": "^1.0.6" }, "require-dev": { + "friendsofphp/php-cs-fixer": "*", "mikey179/vfsstream": "^1.6.0", - "sanmai/phpunit-legacy-adapter": "^6.3 || ^8.2" + "phpstan/phpstan": "*", + "phpunit/phpunit": "<10" }, "suggest": { "ext-iconv": "For best support/performance", @@ -10463,29 +10726,31 @@ "type": "github" } ], - "time": "2022-09-28T16:31:49+00:00" + "time": "2023-02-14T22:58:03+00:00" }, { "name": "zbateson/mb-wrapper", - "version": "1.1.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/zbateson/mb-wrapper.git", - "reference": "5d9d190ef18ce6d424e3ac6f5ebe13901f92b74a" + "reference": "faf35dddfacfc5d4d5f9210143eafd7a7fe74334" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/5d9d190ef18ce6d424e3ac6f5ebe13901f92b74a", - "reference": "5d9d190ef18ce6d424e3ac6f5ebe13901f92b74a", + "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/faf35dddfacfc5d4d5f9210143eafd7a7fe74334", + "reference": "faf35dddfacfc5d4d5f9210143eafd7a7fe74334", "shasum": "" }, "require": { - "php": ">=5.4", + "php": ">=7.1", "symfony/polyfill-iconv": "^1.9", "symfony/polyfill-mbstring": "^1.9" }, "require-dev": { - "sanmai/phpunit-legacy-adapter": "^6.3 || ^8" + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "<=9.0" }, "suggest": { "ext-iconv": "For best support/performance", @@ -10522,7 +10787,7 @@ ], "support": { "issues": "https://github.com/zbateson/mb-wrapper/issues", - "source": "https://github.com/zbateson/mb-wrapper/tree/1.1.2" + "source": "https://github.com/zbateson/mb-wrapper/tree/1.2.0" }, "funding": [ { @@ -10530,29 +10795,31 @@ "type": "github" } ], - "time": "2022-05-26T15:55:05+00:00" + "time": "2023-01-11T23:05:44+00:00" }, { "name": "zbateson/stream-decorators", - "version": "1.0.7", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/zbateson/stream-decorators.git", - "reference": "8f8ca208572963258b7e6d91106181706deacd10" + "reference": "7466ff45d249c86b96267a83cdae68365ae1787e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/8f8ca208572963258b7e6d91106181706deacd10", - "reference": "8f8ca208572963258b7e6d91106181706deacd10", + "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/7466ff45d249c86b96267a83cdae68365ae1787e", + "reference": "7466ff45d249c86b96267a83cdae68365ae1787e", "shasum": "" }, "require": { - "guzzlehttp/psr7": "^1.7.0|^2.0", - "php": ">=5.4", + "guzzlehttp/psr7": "^1.9 | ^2.0", + "php": ">=7.1", "zbateson/mb-wrapper": "^1.0.0" }, "require-dev": { - "sanmai/phpunit-legacy-adapter": "^6.3 || ^8" + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "<=9.0" }, "type": "library", "autoload": { @@ -10583,7 +10850,7 @@ ], "support": { "issues": "https://github.com/zbateson/stream-decorators/issues", - "source": "https://github.com/zbateson/stream-decorators/tree/1.0.7" + "source": "https://github.com/zbateson/stream-decorators/tree/1.1.0" }, "funding": [ { @@ -10591,7 +10858,7 @@ "type": "github" } ], - "time": "2022-09-08T15:44:55+00:00" + "time": "2023-01-11T23:22:44+00:00" } ], "aliases": [], @@ -10602,8 +10869,8 @@ "platform": { "ext-rdkafka": ">=4.0", "ext-json": "*", - "php": ">=7.4" + "php": "^8.0" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.3.0" } diff --git a/docker/Dockerfile b/docker/Dockerfile index 1531adc3..f44c507e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM php:7.4-fpm +FROM php:8.0-fpm LABEL maintainer="boitata@leroymerlin.com.br" USER root:root From 7034a3446badb26281a4a62d8d748e84cdef2ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Get=C3=BAlio=20Meirelles?= Date: Tue, 25 Jul 2023 10:42:47 -0300 Subject: [PATCH 02/75] chore(workflow): drop 7.4 and add 8.2 --- .github/workflows/continuous-integration.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 59efe8d6..f30f0b91 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -14,24 +14,18 @@ jobs: strategy: matrix: php: - - '7.4' - '8.0' - '8.1' + - '8.2' env: KAFKA_BROKER_CONNECTIONS: 'localhost:9092' services: - zookeeper: - image: bitnami/zookeeper - env: - ALLOW_ANONYMOUS_LOGIN: yes kafka: image: bitnami/kafka ports: - '9092:9092' env: - KAFKA_LISTENERS: 'PLAINTEXT://:9092' KAFKA_CFG_ADVERTISED_LISTENERS: 'PLAINTEXT://localhost:9092' - KAFKA_CFG_ZOOKEEPER_CONNECT: 'zookeeper:2181' ALLOW_PLAINTEXT_LISTENER: yes steps: - name: Checkout From cc86844bf5a3066e4810540d9bc46a79d9e07135 Mon Sep 17 00:00:00 2001 From: Orlando Cavassani Date: Fri, 11 Aug 2023 13:57:33 -0300 Subject: [PATCH 03/75] chore(deps): bump packages --- .github/workflows/continuous-integration.yml | 6 + composer.json | 8 +- composer.lock | 762 ++++++++++--------- 3 files changed, 409 insertions(+), 367 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index f30f0b91..e57a08ef 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,12 +20,18 @@ jobs: env: KAFKA_BROKER_CONNECTIONS: 'localhost:9092' services: + zookeeper: + image: bitnami/zookeeper + env: + ALLOW_ANONYMOUS_LOGIN: yes kafka: image: bitnami/kafka ports: - '9092:9092' env: + KAFKA_LISTENERS: 'PLAINTEXT://:9092' KAFKA_CFG_ADVERTISED_LISTENERS: 'PLAINTEXT://localhost:9092' + KAFKA_CFG_ZOOKEEPER_CONNECT: 'zookeeper:2181' ALLOW_PLAINTEXT_LISTENER: yes steps: - name: Checkout diff --git a/composer.json b/composer.json index 9a7b21a5..a2ecc6ce 100644 --- a/composer.json +++ b/composer.json @@ -14,16 +14,16 @@ "illuminate/console": "^9.0 || ^10.0", "illuminate/config": "^9.0 || ^10.0", "php": "^8.0", - "wikimedia/avro": "^1.9.0" + "rg/avro-php": "^3.0" }, "require-dev": { "leroy-merlin-br/coding-standard": "^v3.1.0", - "phpunit/phpunit": "^9.5.27", - "mockery/mockery": "^1.5.1", + "phpunit/phpunit": "^9.6.10", + "mockery/mockery": "^1.6.6", "kwn/php-rdkafka-stubs": "^2.2.1", "orchestra/testbench": "^7.0|^8.0", "dms/phpunit-arraysubset-asserts": "^0.2.1", - "phpro/grumphp": "^1.13.0", + "phpro/grumphp": "^1.16.0", "vimeo/psalm": "^4.30.0", "psalm/plugin-mockery": "^0.9.1", "rector/rector": "^0.13.10" diff --git a/composer.lock b/composer.lock index 37d642f5..878e9168 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,29 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "70981de1c0e9abf6f6ea296fca4d0cd6", + "content-hash": "6330c32352756e224d344653f7dc551c", "packages": [ { "name": "brick/math", - "version": "0.10.2", + "version": "0.11.0", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f" + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/459f2781e1a08d52ee56b0b1444086e038561e3f", - "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f", + "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", "shasum": "" }, "require": { - "ext-json": "*", - "php": "^7.4 || ^8.0" + "php": "^8.0" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^9.0", - "vimeo/psalm": "4.25.0" + "vimeo/psalm": "5.0.0" }, "type": "library", "autoload": { @@ -52,7 +51,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.10.2" + "source": "https://github.com/brick/math/tree/0.11.0" }, "funding": [ { @@ -60,7 +59,7 @@ "type": "github" } ], - "time": "2022-08-10T22:54:19+00:00" + "time": "2023-01-15T23:15:59+00:00" }, { "name": "dflydev/dot-access-data", @@ -139,25 +138,29 @@ }, { "name": "doctrine/deprecations", - "version": "v1.0.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", "shasum": "" }, "require": { - "php": "^7.1|^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -176,34 +179,34 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" }, - "time": "2022-05-02T15:47:09+00:00" + "time": "2023-06-03T09:27:29+00:00" }, { "name": "doctrine/inflector", - "version": "2.0.6", + "version": "2.0.8", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024" + "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", - "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", + "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^10", + "doctrine/coding-standard": "^11.0", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.3", "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25" + "vimeo/psalm": "^4.25 || ^5.4" }, "type": "library", "autoload": { @@ -253,7 +256,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.6" + "source": "https://github.com/doctrine/inflector/tree/2.0.8" }, "funding": [ { @@ -269,7 +272,7 @@ "type": "tidelift" } ], - "time": "2022-10-20T09:10:12+00:00" + "time": "2023-06-16T13:40:37+00:00" }, { "name": "doctrine/lexer", @@ -351,16 +354,16 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.3.2", + "version": "v3.3.3", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8" + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", "shasum": "" }, "require": { @@ -400,7 +403,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3" }, "funding": [ { @@ -408,20 +411,20 @@ "type": "github" } ], - "time": "2022-09-10T18:51:20+00:00" + "time": "2023-08-10T19:36:49+00:00" }, { "name": "egulias/email-validator", - "version": "3.2.5", + "version": "3.2.6", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "b531a2311709443320c786feb4519cfaf94af796" + "reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b531a2311709443320c786feb4519cfaf94af796", - "reference": "b531a2311709443320c786feb4519cfaf94af796", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7", + "reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7", "shasum": "" }, "require": { @@ -467,7 +470,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/3.2.5" + "source": "https://github.com/egulias/EmailValidator/tree/3.2.6" }, "funding": [ { @@ -475,7 +478,7 @@ "type": "github" } ], - "time": "2023-01-02T17:26:14+00:00" + "time": "2023-06-01T07:04:22+00:00" }, { "name": "fruitcake/php-cors", @@ -612,22 +615,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.5.0", + "version": "7.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba" + "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba", - "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5", + "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5", - "guzzlehttp/psr7": "^1.9 || ^2.4", + "guzzlehttp/promises": "^1.5.3 || ^2.0", + "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -638,7 +641,8 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.1", "ext-curl": "*", - "php-http/client-integration-tests": "^3.0", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.29 || ^9.5.23", "psr/log": "^1.1 || ^2.0 || ^3.0" }, @@ -652,9 +656,6 @@ "bamarni-bin": { "bin-links": true, "forward-command": false - }, - "branch-alias": { - "dev-master": "7.5-dev" } }, "autoload": { @@ -720,7 +721,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.5.0" + "source": "https://github.com/guzzle/guzzle/tree/7.7.0" }, "funding": [ { @@ -736,38 +737,37 @@ "type": "tidelift" } ], - "time": "2022-08-28T15:39:27+00:00" + "time": "2023-05-21T14:04:53+00:00" }, { "name": "guzzlehttp/promises", - "version": "1.5.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "b94b2807d85443f9719887892882d0329d1e2598" + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", - "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", "shasum": "" }, "require": { - "php": ">=5.5" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" + "bamarni/composer-bin-plugin": "^1.8.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.5-dev" + "bamarni-bin": { + "bin-links": true, + "forward-command": false } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\Promise\\": "src/" } @@ -804,7 +804,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.5.2" + "source": "https://github.com/guzzle/promises/tree/2.0.1" }, "funding": [ { @@ -820,26 +820,26 @@ "type": "tidelift" } ], - "time": "2022-08-28T14:55:35+00:00" + "time": "2023-08-03T15:11:55+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.4.4", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf" + "reference": "8bd7c33a0734ae1c5d074360512beb716bef3f77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", - "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/8bd7c33a0734ae1c5d074360512beb716bef3f77", + "reference": "8bd7c33a0734ae1c5d074360512beb716bef3f77", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.1 || ^2.0", "ralouphie/getallheaders": "^3.0" }, "provide": { @@ -859,9 +859,6 @@ "bamarni-bin": { "bin-links": true, "forward-command": false - }, - "branch-alias": { - "dev-master": "2.4-dev" } }, "autoload": { @@ -923,7 +920,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.4.4" + "source": "https://github.com/guzzle/psr7/tree/2.6.0" }, "funding": [ { @@ -939,7 +936,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T13:19:02+00:00" + "time": "2023-08-03T15:06:02+00:00" }, { "name": "guzzlehttp/uri-template", @@ -1027,16 +1024,16 @@ }, { "name": "laravel/framework", - "version": "v9.52.5", + "version": "v9.52.15", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "e14d28c0f9403630d13f308bb43f3d3cb73d6d67" + "reference": "e3350e87a52346af9cc655a3012d2175d2d05ad7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/e14d28c0f9403630d13f308bb43f3d3cb73d6d67", - "reference": "e14d28c0f9403630d13f308bb43f3d3cb73d6d67", + "url": "https://api.github.com/repos/laravel/framework/zipball/e3350e87a52346af9cc655a3012d2175d2d05ad7", + "reference": "e3350e87a52346af9cc655a3012d2175d2d05ad7", "shasum": "" }, "require": { @@ -1133,7 +1130,7 @@ "league/flysystem-read-only": "^3.3", "league/flysystem-sftp-v3": "^3.0", "mockery/mockery": "^1.5.1", - "orchestra/testbench-core": "^7.16", + "orchestra/testbench-core": "^7.24", "pda/pheanstalk": "^4.0", "phpstan/phpdoc-parser": "^1.15", "phpstan/phpstan": "^1.4.7", @@ -1221,20 +1218,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-03-28T18:03:54+00:00" + "time": "2023-08-08T14:28:40+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.3.0", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37" + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/e5a3057a5591e1cfe8183034b0203921abe2c902", + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902", "shasum": "" }, "require": { @@ -1281,7 +1278,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-01-30T18:31:20+00:00" + "time": "2023-07-14T13:56:28+00:00" }, { "name": "league/commonmark", @@ -1473,19 +1470,20 @@ }, { "name": "league/flysystem", - "version": "3.12.3", + "version": "3.15.1", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "81e87e74dd5213795c7846d65089712d2dda90ce" + "reference": "a141d430414fcb8bf797a18716b09f759a385bed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/81e87e74dd5213795c7846d65089712d2dda90ce", - "reference": "81e87e74dd5213795c7846d65089712d2dda90ce", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a141d430414fcb8bf797a18716b09f759a385bed", + "reference": "a141d430414fcb8bf797a18716b09f759a385bed", "shasum": "" }, "require": { + "league/flysystem-local": "^3.0.0", "league/mime-type-detection": "^1.0.0", "php": "^8.0.2" }, @@ -1544,7 +1542,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.12.3" + "source": "https://github.com/thephpleague/flysystem/tree/3.15.1" }, "funding": [ { @@ -1554,36 +1552,92 @@ { "url": "https://github.com/frankdejonge", "type": "github" + } + ], + "time": "2023-05-04T09:04:26+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.15.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/543f64c397fefdf9cfeac443ffb6beff602796b3", + "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem-local/issues", + "source": "https://github.com/thephpleague/flysystem-local/tree/3.15.0" + }, + "funding": [ + { + "url": "https://ecologi.com/frankdejonge", + "type": "custom" }, { - "url": "https://tidelift.com/funding/github/packagist/league/flysystem", - "type": "tidelift" + "url": "https://github.com/frankdejonge", + "type": "github" } ], - "time": "2023-02-18T15:32:41+00:00" + "time": "2023-05-02T20:02:14+00:00" }, { "name": "league/mime-type-detection", - "version": "1.11.0", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" + "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/a6dfb1194a2946fcdc1f38219445234f65b35c96", + "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96", "shasum": "" }, "require": { "ext-fileinfo": "*", - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.2", "phpstan/phpstan": "^0.12.68", - "phpunit/phpunit": "^8.5.8 || ^9.3" + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" }, "type": "library", "autoload": { @@ -1604,7 +1658,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.13.0" }, "funding": [ { @@ -1616,7 +1670,7 @@ "type": "tidelift" } ], - "time": "2022-04-17T13:12:02+00:00" + "time": "2023-08-05T12:09:49+00:00" }, { "name": "monolog/monolog", @@ -1722,16 +1776,16 @@ }, { "name": "nesbot/carbon", - "version": "2.66.0", + "version": "2.68.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "496712849902241f04902033b0441b269effe001" + "reference": "4f991ed2a403c85efbc4f23eb4030063fdbe01da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/496712849902241f04902033b0441b269effe001", - "reference": "496712849902241f04902033b0441b269effe001", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4f991ed2a403c85efbc4f23eb4030063fdbe01da", + "reference": "4f991ed2a403c85efbc4f23eb4030063fdbe01da", "shasum": "" }, "require": { @@ -1820,25 +1874,25 @@ "type": "tidelift" } ], - "time": "2023-01-29T18:53:47+00:00" + "time": "2023-06-20T18:29:04+00:00" }, { "name": "nette/schema", - "version": "v1.2.3", + "version": "v1.2.4", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "abbdbb70e0245d5f3bf77874cea1dfb0c930d06f" + "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/abbdbb70e0245d5f3bf77874cea1dfb0c930d06f", - "reference": "abbdbb70e0245d5f3bf77874cea1dfb0c930d06f", + "url": "https://api.github.com/repos/nette/schema/zipball/c9ff517a53903b3d4e29ec547fb20feecb05b8ab", + "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab", "shasum": "" }, "require": { "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", - "php": ">=7.1 <8.3" + "php": "7.1 - 8.3" }, "require-dev": { "nette/tester": "^2.3 || ^2.4", @@ -1880,26 +1934,26 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.2.3" + "source": "https://github.com/nette/schema/tree/v1.2.4" }, - "time": "2022-10-13T01:24:26+00:00" + "time": "2023-08-05T18:56:25+00:00" }, { "name": "nette/utils", - "version": "v4.0.0", + "version": "v4.0.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e" + "reference": "9124157137da01b1f5a5a22d6486cb975f26db7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/cacdbf5a91a657ede665c541eda28941d4b09c1e", - "reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e", + "url": "https://api.github.com/repos/nette/utils/zipball/9124157137da01b1f5a5a22d6486cb975f26db7e", + "reference": "9124157137da01b1f5a5a22d6486cb975f26db7e", "shasum": "" }, "require": { - "php": ">=8.0 <8.3" + "php": ">=8.0 <8.4" }, "conflict": { "nette/finder": "<3", @@ -1907,7 +1961,7 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "dev-master", - "nette/tester": "^2.4", + "nette/tester": "^2.5", "phpstan/phpstan": "^1.0", "tracy/tracy": "^2.9" }, @@ -1967,9 +2021,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.0" + "source": "https://github.com/nette/utils/tree/v4.0.1" }, - "time": "2023-02-02T10:41:53+00:00" + "time": "2023-07-30T15:42:21+00:00" }, { "name": "nunomaduro/termwind", @@ -2237,21 +2291,21 @@ }, { "name": "psr/http-client", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", "shasum": "" }, "require": { "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -2271,7 +2325,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP clients", @@ -2283,27 +2337,27 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/master" + "source": "https://github.com/php-fig/http-client/tree/1.0.2" }, - "time": "2020-06-29T06:28:15+00:00" + "time": "2023-04-10T20:12:12+00:00" }, { "name": "psr/http-factory", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + "reference": "e616d01114759c4c489f93b099585439f795fe35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", "shasum": "" }, "require": { "php": ">=7.0.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -2323,7 +2377,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for PSR-7 HTTP message factories", @@ -2338,22 +2392,22 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" }, - "time": "2019-04-30T12:38:16+00:00" + "time": "2023-04-10T20:10:41+00:00" }, { "name": "psr/http-message", - "version": "1.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { @@ -2362,7 +2416,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -2377,7 +2431,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -2391,9 +2445,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2023-04-04T09:50:52+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/log", @@ -2632,20 +2686,20 @@ }, { "name": "ramsey/uuid", - "version": "4.7.3", + "version": "4.7.4", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "433b2014e3979047db08a17a205f410ba3869cf2" + "reference": "60a4c63ab724854332900504274f6150ff26d286" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/433b2014e3979047db08a17a205f410ba3869cf2", - "reference": "433b2014e3979047db08a17a205f410ba3869cf2", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286", + "reference": "60a4c63ab724854332900504274f6150ff26d286", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", "ext-json": "*", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" @@ -2708,7 +2762,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.3" + "source": "https://github.com/ramsey/uuid/tree/4.7.4" }, "funding": [ { @@ -2720,7 +2774,47 @@ "type": "tidelift" } ], - "time": "2023-01-12T18:13:24+00:00" + "time": "2023-04-15T23:01:58+00:00" + }, + { + "name": "rg/avro-php", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/researchgate/avro-php.git", + "reference": "35565bb7f5aa85acbf7eeee8c1683a0da3cd6c2c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/researchgate/avro-php/zipball/35565bb7f5aa85acbf7eeee8c1683a0da3cd6c2c", + "reference": "35565bb7f5aa85acbf7eeee8c1683a0da3cd6c2c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "ext-gmp": "Large integer support for 32-bit platforms." + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Composer packaging for vanilla Apache Avro, with fixes", + "support": { + "issues": "https://github.com/researchgate/avro-php/issues", + "source": "https://github.com/researchgate/avro-php/tree/3.0.0" + }, + "time": "2022-07-05T08:21:34+00:00" }, { "name": "symfony/console", @@ -5239,79 +5333,6 @@ "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, "time": "2022-06-03T18:03:27+00:00" - }, - { - "name": "wikimedia/avro", - "version": "v1.9.0", - "source": { - "type": "git", - "url": "https://github.com/wikimedia/avro-php.git", - "reference": "b2e0c9d750da03d95ba979215397f62a6121ddea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wikimedia/avro-php/zipball/b2e0c9d750da03d95ba979215397f62a6121ddea", - "reference": "b2e0c9d750da03d95ba979215397f62a6121ddea", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "jakub-onderka/php-console-highlighter": "0.3.2", - "jakub-onderka/php-parallel-lint": "1.0.0", - "mediawiki/minus-x": "0.3.1", - "phpunit/phpunit": "4.8.36" - }, - "suggest": { - "ext-gmp": "Large integer support for 32-bit platforms." - }, - "type": "library", - "autoload": { - "classmap": [ - "lib/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Michael Glaesemann", - "email": "grzm@seespotcode.net" - }, - { - "name": "Andy Wick", - "email": "awick@purple.org" - }, - { - "name": "Saleem Shafi", - "email": "saleemshafi@gmail.com" - }, - { - "name": "A B", - "email": "abawany@x.com" - }, - { - "name": "Doug Cutting", - "email": "cutting@apache.org" - }, - { - "name": "Tom White", - "email": "tom@cloudera.com" - } - ], - "description": "A library for using Apache Avro with PHP.", - "homepage": "https://avro.apache.org/", - "keywords": [ - "serialization" - ], - "support": { - "source": "https://github.com/wikimedia/avro-php/tree/v1.9.0" - }, - "abandoned": "rg/avro-php", - "time": "2019-09-16T15:18:39+00:00" } ], "packages-dev": [ @@ -6456,16 +6477,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.21.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d" + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/92efad6a967f0b79c499705c69b662f738cc9e4d", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", "shasum": "" }, "require": { @@ -6518,9 +6539,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.21.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.0" }, - "time": "2022-12-13T13:54:32+00:00" + "time": "2023-06-12T08:44:38+00:00" }, { "name": "felixfbecker/advanced-json-rpc", @@ -6625,16 +6646,16 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.3.7", + "version": "v1.3.8", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "00b57b79f02396aa4c7c163f76fe2bc48faebbb7" + "reference": "9fea656e75ad6e3452feb2cac46a6c1239cd7f74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/00b57b79f02396aa4c7c163f76fe2bc48faebbb7", - "reference": "00b57b79f02396aa4c7c163f76fe2bc48faebbb7", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/9fea656e75ad6e3452feb2cac46a6c1239cd7f74", + "reference": "9fea656e75ad6e3452feb2cac46a6c1239cd7f74", "shasum": "" }, "require": { @@ -6688,7 +6709,7 @@ "description": "Library for accessing git", "support": { "issues": "https://github.com/gitonomy/gitlib/issues", - "source": "https://github.com/gitonomy/gitlib/tree/v1.3.7" + "source": "https://github.com/gitonomy/gitlib/tree/v1.3.8" }, "funding": [ { @@ -6696,7 +6717,7 @@ "type": "tidelift" } ], - "time": "2022-10-04T14:20:15+00:00" + "time": "2023-05-11T08:29:06+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -6836,38 +6857,40 @@ }, { "name": "mockery/mockery", - "version": "1.5.1", + "version": "1.6.6", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e" + "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/e92dcc83d5a51851baf5f5591d32cb2b16e3684e", - "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e", + "url": "https://api.github.com/repos/mockery/mockery/zipball/b8e0bb7d8c604046539c1115994632c74dcb361e", + "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e", "shasum": "" }, "require": { "hamcrest/hamcrest-php": "^2.0.1", "lib-pcre": ">=7.0", - "php": "^7.3 || ^8.0" + "php": ">=7.3" }, "conflict": { "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.3" + "phpunit/phpunit": "^8.5 || ^9.6.10", + "psalm/plugin-phpunit": "^0.18.4", + "symplify/easy-coding-standard": "^11.5.0", + "vimeo/psalm": "^4.30" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, "autoload": { - "psr-0": { - "Mockery": "library/" + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" } }, "notification-url": "https://packagist.org/downloads/", @@ -6878,12 +6901,20 @@ { "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" + "homepage": "https://github.com/padraic", + "role": "Author" }, { "name": "Dave Marshall", "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" } ], "description": "Mockery is a simple yet flexible PHP mock object framework", @@ -6901,10 +6932,13 @@ "testing" ], "support": { + "docs": "https://docs.mockery.io/", "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/1.5.1" + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" }, - "time": "2022-09-07T15:32:08+00:00" + "time": "2023-08-09T00:03:52+00:00" }, { "name": "myclabs/deep-copy", @@ -6967,16 +7001,16 @@ }, { "name": "netresearch/jsonmapper", - "version": "v4.1.0", + "version": "v4.2.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", "shasum": "" }, "require": { @@ -7012,22 +7046,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" }, - "time": "2022-12-08T20:46:14+00:00" + "time": "2023-04-09T17:37:40+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.4", + "version": "v4.16.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -7068,9 +7102,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, - "time": "2023-03-05T19:49:14+00:00" + "time": "2023-06-25T14:52:30+00:00" }, { "name": "ondram/ci-detector", @@ -7205,23 +7239,23 @@ }, { "name": "orchestra/testbench", - "version": "v7.24.1", + "version": "v7.26.2", "source": { "type": "git", "url": "https://github.com/orchestral/testbench.git", - "reference": "6c38cf3d6a3523a25974d8457ca94439eaf12ab0" + "reference": "6355e41b4f279875e996836f39204ef130f703f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/6c38cf3d6a3523a25974d8457ca94439eaf12ab0", - "reference": "6c38cf3d6a3523a25974d8457ca94439eaf12ab0", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/6355e41b4f279875e996836f39204ef130f703f1", + "reference": "6355e41b4f279875e996836f39204ef130f703f1", "shasum": "" }, "require": { "fakerphp/faker": "^1.21", - "laravel/framework": "^9.52.4", + "laravel/framework": "^9.52.15", "mockery/mockery": "^1.5.1", - "orchestra/testbench-core": "^7.24.1", + "orchestra/testbench-core": "^7.26.2", "php": "^8.0", "phpunit/phpunit": "^9.5.10", "spatie/laravel-ray": "^1.32.4", @@ -7251,29 +7285,29 @@ "keywords": [ "BDD", "TDD", + "dev", "laravel", - "orchestra-platform", - "orchestral", + "laravel-packages", "testing" ], "support": { "issues": "https://github.com/orchestral/testbench/issues", - "source": "https://github.com/orchestral/testbench/tree/v7.24.1" + "source": "https://github.com/orchestral/testbench/tree/v7.26.2" }, - "time": "2023-04-03T01:22:44+00:00" + "time": "2023-08-10T02:40:53+00:00" }, { "name": "orchestra/testbench-core", - "version": "v7.24.1", + "version": "v7.26.3", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "4d9277728235a7fe3724397b8195dda3d39e1bdf" + "reference": "cbffadcc4da002b19503ac0e45a145fbc987c0e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/4d9277728235a7fe3724397b8195dda3d39e1bdf", - "reference": "4d9277728235a7fe3724397b8195dda3d39e1bdf", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/cbffadcc4da002b19503ac0e45a145fbc987c0e6", + "reference": "cbffadcc4da002b19503ac0e45a145fbc987c0e6", "shasum": "" }, "require": { @@ -7281,10 +7315,9 @@ }, "require-dev": { "fakerphp/faker": "^1.21", - "laravel/framework": "^9.52.4", + "laravel/framework": "^9.52.9", "laravel/pint": "^1.4", "mockery/mockery": "^1.5.1", - "orchestra/canvas": "^7.0", "phpstan/phpstan": "^1.10.7", "phpunit/phpunit": "^9.5.10", "spatie/laravel-ray": "^1.32.4", @@ -7295,7 +7328,7 @@ "suggest": { "brianium/paratest": "Allow using parallel tresting (^6.4).", "fakerphp/faker": "Allow using Faker for testing (^1.21).", - "laravel/framework": "Required for testing (^9.52.4).", + "laravel/framework": "Required for testing (^9.52.9).", "mockery/mockery": "Allow using Mockery for testing (^1.5.1).", "nunomaduro/collision": "Allow using Laravel style tests output and parallel testing (^6.2).", "orchestra/testbench-browser-kit": "Allow using legacy Laravel BrowserKit for testing (^7.0).", @@ -7346,7 +7379,7 @@ "issues": "https://github.com/orchestral/testbench/issues", "source": "https://github.com/orchestral/testbench-core" }, - "time": "2023-04-02T16:09:59+00:00" + "time": "2023-08-11T08:18:39+00:00" }, { "name": "phar-io/manifest", @@ -7571,16 +7604,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714" + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "shasum": "" }, "require": { @@ -7623,22 +7656,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" }, - "time": "2023-03-27T19:02:04+00:00" + "time": "2023-05-30T18:13:47+00:00" }, { "name": "phpro/grumphp", - "version": "v1.15.0", + "version": "v1.16.0", "source": { "type": "git", "url": "https://github.com/phpro/grumphp.git", - "reference": "533e45484be80d426010a318ff6f99fbe33350a5" + "reference": "bf8785bd90eff4661c5eaf3574048f4fb78611dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpro/grumphp/zipball/533e45484be80d426010a318ff6f99fbe33350a5", - "reference": "533e45484be80d426010a318ff6f99fbe33350a5", + "url": "https://api.github.com/repos/phpro/grumphp/zipball/bf8785bd90eff4661c5eaf3574048f4fb78611dd", + "reference": "bf8785bd90eff4661c5eaf3574048f4fb78611dd", "shasum": "" }, "require": { @@ -7741,28 +7774,30 @@ "description": "A composer plugin that enables source code quality checks.", "support": { "issues": "https://github.com/phpro/grumphp/issues", - "source": "https://github.com/phpro/grumphp/tree/v1.15.0" + "source": "https://github.com/phpro/grumphp/tree/v1.16.0" }, - "time": "2022-12-22T12:36:10+00:00" + "time": "2023-04-27T11:04:18+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.17.1", + "version": "1.23.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee" + "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", - "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26", + "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", @@ -7786,22 +7821,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.17.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.1" }, - "time": "2023-04-04T11:11:22+00:00" + "time": "2023-08-03T16:32:59+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.10", + "version": "1.10.28", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "f1e22c9b17a879987f8743d81533250a5fff47f9" + "reference": "e4545b55904ebef470423d3ddddb74fa7325497a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f1e22c9b17a879987f8743d81533250a5fff47f9", - "reference": "f1e22c9b17a879987f8743d81533250a5fff47f9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e4545b55904ebef470423d3ddddb74fa7325497a", + "reference": "e4545b55904ebef470423d3ddddb74fa7325497a", "shasum": "" }, "require": { @@ -7850,20 +7885,20 @@ "type": "tidelift" } ], - "time": "2023-04-01T17:06:15+00:00" + "time": "2023-08-08T12:33:42+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.26", + "version": "9.2.27", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", "shasum": "" }, "require": { @@ -7919,7 +7954,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" }, "funding": [ { @@ -7927,7 +7963,7 @@ "type": "github" } ], - "time": "2023-03-06T12:58:08+00:00" + "time": "2023-07-26T13:44:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -8172,16 +8208,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.6", + "version": "9.6.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", - "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", "shasum": "" }, "require": { @@ -8255,7 +8291,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" }, "funding": [ { @@ -8271,7 +8307,7 @@ "type": "tidelift" } ], - "time": "2023-03-27T11:43:46+00:00" + "time": "2023-07-10T04:04:23+00:00" }, { "name": "pimple/pimple", @@ -8740,16 +8776,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -8794,7 +8830,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -8802,7 +8838,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", @@ -8946,16 +8982,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -8998,7 +9034,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -9006,7 +9042,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", @@ -9406,16 +9442,16 @@ }, { "name": "seld/jsonlint", - "version": "1.9.0", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "4211420d25eba80712bff236a98960ef68b866b7" + "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/4211420d25eba80712bff236a98960ef68b866b7", - "reference": "4211420d25eba80712bff236a98960ef68b866b7", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/594fd6462aad8ecee0b45ca5045acea4776667f1", + "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1", "shasum": "" }, "require": { @@ -9454,7 +9490,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.9.0" + "source": "https://github.com/Seldaek/jsonlint/tree/1.10.0" }, "funding": [ { @@ -9466,7 +9502,7 @@ "type": "tidelift" } ], - "time": "2022-04-01T13:37:23+00:00" + "time": "2023-05-11T13:16:46+00:00" }, { "name": "slevomat/coding-standard", @@ -9531,16 +9567,16 @@ }, { "name": "spatie/backtrace", - "version": "1.4.0", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/spatie/backtrace.git", - "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c" + "reference": "483f76a82964a0431aa836b6ed0edde0c248e3ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/ec4dd16476b802dbdc6b4467f84032837e316b8c", - "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/483f76a82964a0431aa836b6ed0edde0c248e3ab", + "reference": "483f76a82964a0431aa836b6ed0edde0c248e3ab", "shasum": "" }, "require": { @@ -9577,7 +9613,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/backtrace/tree/1.4.0" + "source": "https://github.com/spatie/backtrace/tree/1.5.3" }, "funding": [ { @@ -9589,20 +9625,20 @@ "type": "other" } ], - "time": "2023-03-04T08:57:24+00:00" + "time": "2023-06-28T12:59:17+00:00" }, { "name": "spatie/laravel-ray", - "version": "1.32.4", + "version": "1.32.6", "source": { "type": "git", "url": "https://github.com/spatie/laravel-ray.git", - "reference": "2274653f0a90dd87fbb887437be1c1ea1388a47c" + "reference": "8526dd6c6c838b4bac4e0df2ea7896b688b0d43e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/2274653f0a90dd87fbb887437be1c1ea1388a47c", - "reference": "2274653f0a90dd87fbb887437be1c1ea1388a47c", + "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/8526dd6c6c838b4bac4e0df2ea7896b688b0d43e", + "reference": "8526dd6c6c838b4bac4e0df2ea7896b688b0d43e", "shasum": "" }, "require": { @@ -9662,7 +9698,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-ray/issues", - "source": "https://github.com/spatie/laravel-ray/tree/1.32.4" + "source": "https://github.com/spatie/laravel-ray/tree/1.32.6" }, "funding": [ { @@ -9674,7 +9710,7 @@ "type": "other" } ], - "time": "2023-03-23T08:04:54+00:00" + "time": "2023-07-19T12:30:16+00:00" }, { "name": "spatie/macroable", @@ -9728,16 +9764,16 @@ }, { "name": "spatie/ray", - "version": "1.37.1", + "version": "1.37.2", "source": { "type": "git", "url": "https://github.com/spatie/ray.git", - "reference": "a915e327f04c0fbed3bdd26e076e39feea091062" + "reference": "dea16182d4bc9d9833adec7e39fbb3d7b553425d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/ray/zipball/a915e327f04c0fbed3bdd26e076e39feea091062", - "reference": "a915e327f04c0fbed3bdd26e076e39feea091062", + "url": "https://api.github.com/repos/spatie/ray/zipball/dea16182d4bc9d9833adec7e39fbb3d7b553425d", + "reference": "dea16182d4bc9d9833adec7e39fbb3d7b553425d", "shasum": "" }, "require": { @@ -9788,7 +9824,7 @@ ], "support": { "issues": "https://github.com/spatie/ray/issues", - "source": "https://github.com/spatie/ray/tree/1.37.1" + "source": "https://github.com/spatie/ray/tree/1.37.2" }, "funding": [ { @@ -9800,7 +9836,7 @@ "type": "other" } ], - "time": "2023-03-06T07:22:28+00:00" + "time": "2023-05-17T06:35:47+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -10799,27 +10835,27 @@ }, { "name": "zbateson/stream-decorators", - "version": "1.1.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/zbateson/stream-decorators.git", - "reference": "7466ff45d249c86b96267a83cdae68365ae1787e" + "reference": "783b034024fda8eafa19675fb2552f8654d3a3e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/7466ff45d249c86b96267a83cdae68365ae1787e", - "reference": "7466ff45d249c86b96267a83cdae68365ae1787e", + "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/783b034024fda8eafa19675fb2552f8654d3a3e9", + "reference": "783b034024fda8eafa19675fb2552f8654d3a3e9", "shasum": "" }, "require": { "guzzlehttp/psr7": "^1.9 | ^2.0", - "php": ">=7.1", + "php": ">=7.2", "zbateson/mb-wrapper": "^1.0.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", "phpstan/phpstan": "*", - "phpunit/phpunit": "<=9.0" + "phpunit/phpunit": "<10.0" }, "type": "library", "autoload": { @@ -10850,7 +10886,7 @@ ], "support": { "issues": "https://github.com/zbateson/stream-decorators/issues", - "source": "https://github.com/zbateson/stream-decorators/tree/1.1.0" + "source": "https://github.com/zbateson/stream-decorators/tree/1.2.1" }, "funding": [ { @@ -10858,7 +10894,7 @@ "type": "github" } ], - "time": "2023-01-11T23:22:44+00:00" + "time": "2023-05-30T22:51:52+00:00" } ], "aliases": [], From 36763656bb5c1bea6f0081669f1b4573d9565e32 Mon Sep 17 00:00:00 2001 From: GetulioMR Date: Thu, 24 Aug 2023 15:10:07 -0300 Subject: [PATCH 04/75] feat: improve config to accept max pool interval ms --- config/kafka.php | 4 ++++ src/Connectors/Consumer/HighLevel.php | 6 ++++++ src/Connectors/Consumer/LowLevel.php | 7 +++++++ tests/Unit/Connectors/Consumer/HighLevelTest.php | 1 + tests/Unit/Connectors/Consumer/LowLevelTest.php | 1 + 5 files changed, 19 insertions(+) diff --git a/config/kafka.php b/config/kafka.php index 9f9ae370..00912858 100644 --- a/config/kafka.php +++ b/config/kafka.php @@ -102,6 +102,10 @@ // time we need to wait until receiving a message? 'timeout' => 20000, + // A max interval for consumer to make poll calls. That means: how much + // time we need to wait for poll calls until consider the consumer has inactive. + 'max_poll_interval_ms' => 300000, + // Once you've enabled this, the Kafka consumer will commit the // offset of the last message received in response to its poll() call 'auto_commit' => true, diff --git a/src/Connectors/Consumer/HighLevel.php b/src/Connectors/Consumer/HighLevel.php index 7a61a171..27d5f3a3 100644 --- a/src/Connectors/Consumer/HighLevel.php +++ b/src/Connectors/Consumer/HighLevel.php @@ -14,9 +14,15 @@ class HighLevel implements ConnectorInterface public function getConsumer(bool $autoCommit, AbstractConfigManager $configManager): ConsumerInterface { $conf = $this->getConf($configManager); + $maxPollIntervalMs = (int) $configManager->get('max_poll_interval_ms'); $conf->set('group.id', $configManager->get('consumer_group')); $conf->set('auto.offset.reset', $configManager->get('offset_reset')); + $conf->set( + 'max.poll.interval.ms', + $maxPollIntervalMs ?: 300000 + ); + if (!$autoCommit) { $conf->set('enable.auto.commit', 'false'); } diff --git a/src/Connectors/Consumer/LowLevel.php b/src/Connectors/Consumer/LowLevel.php index 6c4d3993..c270fc74 100644 --- a/src/Connectors/Consumer/LowLevel.php +++ b/src/Connectors/Consumer/LowLevel.php @@ -15,7 +15,14 @@ class LowLevel implements ConnectorInterface public function getConsumer(bool $autoCommit, AbstractConfigManager $configManager): ConsumerInterface { $conf = $this->getConf(); + $maxPollIntervalMs = (int) $configManager->get('max_poll_interval_ms'); + $conf->set('group.id', $configManager->get('consumer_group')); + $conf->set( + 'max.poll.interval.ms', + $maxPollIntervalMs ?: 300000 + ); + if (!$autoCommit) { $conf->set('enable.auto.commit', 'false'); } diff --git a/tests/Unit/Connectors/Consumer/HighLevelTest.php b/tests/Unit/Connectors/Consumer/HighLevelTest.php index 52d58fc4..681c7ce5 100644 --- a/tests/Unit/Connectors/Consumer/HighLevelTest.php +++ b/tests/Unit/Connectors/Consumer/HighLevelTest.php @@ -20,6 +20,7 @@ public function testItShouldMakeConnectorSetup(): void 'topic_id' => 'some_topic', 'offset_reset' => 'earliest', 'timeout' => 1000, + 'max_poll_interval_ms' => 900000, ]); $connector = new HighLevel(); diff --git a/tests/Unit/Connectors/Consumer/LowLevelTest.php b/tests/Unit/Connectors/Consumer/LowLevelTest.php index 039d096c..b3a081df 100644 --- a/tests/Unit/Connectors/Consumer/LowLevelTest.php +++ b/tests/Unit/Connectors/Consumer/LowLevelTest.php @@ -19,6 +19,7 @@ public function testItShouldMakeConnectorSetup(): void 'consumer_group' => 'some-group', 'topic' => 'some_topic', 'offset_reset' => 'earliest', + 'max_poll_interval_ms' => 900000, 'offset' => 0, 'partition' => 1, ]); From 7e50037a50206a220e7c89310ebeeb8a610ec924 Mon Sep 17 00:00:00 2001 From: Hugo Ferreira Date: Mon, 31 Jan 2022 17:13:51 -0300 Subject: [PATCH 05/75] chore(configOptions): add ConfigOptions command to ServiceProvider --- src/MetamorphosisServiceProvider.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/MetamorphosisServiceProvider.php b/src/MetamorphosisServiceProvider.php index 687c739a..4938fbac 100644 --- a/src/MetamorphosisServiceProvider.php +++ b/src/MetamorphosisServiceProvider.php @@ -3,6 +3,7 @@ namespace Metamorphosis; use Illuminate\Support\ServiceProvider; +use Metamorphosis\Console\ConfigOptionsCommand; use Metamorphosis\Console\ConsumerCommand; use Metamorphosis\Console\ConsumerMakeCommand; use Metamorphosis\Console\MiddlewareMakeCommand; @@ -26,6 +27,7 @@ public function register() ConsumerMakeCommand::class, MiddlewareMakeCommand::class, ProducerMakeCommand::class, + ConfigOptionsCommand::class, ]); $this->app->bind('metamorphosis', function ($app) { From ab06105c475c185a3eded288df63193a91e15ac0 Mon Sep 17 00:00:00 2001 From: Hugo Ferreira Date: Mon, 31 Jan 2022 17:16:15 -0300 Subject: [PATCH 06/75] chore(configOptions): call new configOptions artisan command --- .../ProducerWithConfigOptionsTest.php | 41 +++---------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/tests/Integration/ProducerWithConfigOptionsTest.php b/tests/Integration/ProducerWithConfigOptionsTest.php index 3382b590..5f5017a0 100644 --- a/tests/Integration/ProducerWithConfigOptionsTest.php +++ b/tests/Integration/ProducerWithConfigOptionsTest.php @@ -24,14 +24,13 @@ public function testShouldRunAProducerMessagesWithConfigOptions(): void $this->haveAHandlerConfigured(); // I Expect That - $this->myMessagesHaveBeenProduced(); - $this->expectNotToPerformAssertions(); + //$this->myMessagesHaveBeenProduced(); // When I - $this->haveSomeRandomMessageProduced(); + //$this->haveSomeRandomMessageProduced(); // I Expect That - $this->myMessagesHaveBeenLogged(); + //$this->myMessagesHaveBeenLogged(); // When I $this->runTheConsumer(); @@ -41,39 +40,11 @@ protected function runTheConsumer(): void { $dummy = new MessageConsumer($this->consumerConfigOptions); $this->instance('\App\Kafka\Consumers\ConsumerOverride', $dummy); - config([ - 'kafka_new_config' => [ - 'brokers' => [ - 'override' => [ - 'connections' => env( - 'KAFKA_BROKER_CONNECTIONS', - 'kafka:9092' - ), - ], - ], - 'topics' => [ - 'default' => [ - 'broker' => 'override', - 'consumer' => [ - 'consumer_groups' => [ - 'test-consumer-group' => [ - 'handler' => '\App\Kafka\Consumers\ConsumerOverride', - 'offset_reset' => 'earliest', - ], - ], - ], - ], - ], - ], - ]); + $this->artisan( - 'kafka:consume', + 'kafka:consume-config-class', [ - 'topic' => 'default', - 'consumer_group' => 'test-consumer-group', - '--timeout' => 20000, - '--times' => 2, - '--config_name' => 'kafka_new_config', + 'handler' => '\\App\\Kafka\\Consumers\\ConsumerOverride', ] ); } From 571eeb0d5fa192769878fcc4bedeae0e1cf27d46 Mon Sep 17 00:00:00 2001 From: Hugo Ferreira Date: Mon, 31 Jan 2022 17:19:05 -0300 Subject: [PATCH 07/75] chore(configOptions): add ConfigOptionsCommand --- src/Console/ConfigOptionsCommand.php | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/Console/ConfigOptionsCommand.php diff --git a/src/Console/ConfigOptionsCommand.php b/src/Console/ConfigOptionsCommand.php new file mode 100644 index 00000000..ccd8bb37 --- /dev/null +++ b/src/Console/ConfigOptionsCommand.php @@ -0,0 +1,49 @@ +make($this->option(), $this->argument()); + +// $this->writeStartingConsumer($configManager); + + $config = $this->argument()['handler']; + + $manager = Factory::make($this->argument()['handler']); + + $runner = app(Runner::class, compact('manager')); + //$runner->run($manager->get('times')); + } + + private function writeStartingConsumer(AbstractConfigManager $configManager) + { + $text = 'Starting consumer for topic: '.$configManager->get('topic').PHP_EOL; + $text .= ' on consumer group: '.$configManager->get('consumer_group').PHP_EOL; + $text .= 'Connecting in '.$configManager->get('connections').PHP_EOL; + $text .= 'Running consumer..'; + + $this->output->writeln($text); + } +} From 76f4ae3284009be7726250ea6d75175e60c7004e Mon Sep 17 00:00:00 2001 From: David Franca Date: Mon, 31 Jan 2022 17:55:13 -0300 Subject: [PATCH 08/75] chore: make config manager with config options --- src/Connectors/Consumer/Config.php | 8 ++++++++ src/Console/ConfigOptionsCommand.php | 13 ++++++------- tests/Integration/ProducerWithConfigOptionsTest.php | 6 +++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index 306600aa..57b8b92d 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -39,6 +39,14 @@ class Config extends AbstractConfig 'middlewares' => 'array', ]; + public function makeWithConfigOptions(string $handlerClass): AbstractConfigManager + { + $configManager = app(ConsumerConfigManager::class); + $configManager->set(['handler' => $handlerClass]); + + return $configManager; + } + public function make(array $options, array $arguments): AbstractConfigManager { $configName = $options['config_name'] ?? 'kafka'; diff --git a/src/Console/ConfigOptionsCommand.php b/src/Console/ConfigOptionsCommand.php index ccd8bb37..37dab14c 100644 --- a/src/Console/ConfigOptionsCommand.php +++ b/src/Console/ConfigOptionsCommand.php @@ -3,6 +3,7 @@ use Illuminate\Console\Command as BaseCommand; use Metamorphosis\AbstractConfigManager; +use Metamorphosis\Connectors\Consumer\Config; use Metamorphosis\Connectors\Consumer\Factory; use Metamorphosis\Consumers\Runner; @@ -23,18 +24,16 @@ class ConfigOptionsCommand extends BaseCommand */ protected $signature = 'kafka:consume-config-class {handler : handler.}'; - public function handle() + public function handle(Config $config) { -// $configManager = $config->make($this->option(), $this->argument()); + $configManager = $config->makeWithConfigOptions($this->argument()['handler']); -// $this->writeStartingConsumer($configManager); + $this->writeStartingConsumer($configManager); - $config = $this->argument()['handler']; - - $manager = Factory::make($this->argument()['handler']); + $manager = Factory::make($configManager); $runner = app(Runner::class, compact('manager')); - //$runner->run($manager->get('times')); + $runner->run(2); } private function writeStartingConsumer(AbstractConfigManager $configManager) diff --git a/tests/Integration/ProducerWithConfigOptionsTest.php b/tests/Integration/ProducerWithConfigOptionsTest.php index 5f5017a0..4a45d8e0 100644 --- a/tests/Integration/ProducerWithConfigOptionsTest.php +++ b/tests/Integration/ProducerWithConfigOptionsTest.php @@ -24,13 +24,13 @@ public function testShouldRunAProducerMessagesWithConfigOptions(): void $this->haveAHandlerConfigured(); // I Expect That - //$this->myMessagesHaveBeenProduced(); + $this->myMessagesHaveBeenProduced(); // When I - //$this->haveSomeRandomMessageProduced(); + $this->haveSomeRandomMessageProduced(); // I Expect That - //$this->myMessagesHaveBeenLogged(); + $this->myMessagesHaveBeenLogged(); // When I $this->runTheConsumer(); From 64345304b870d74690f242fa797b0647f684095d Mon Sep 17 00:00:00 2001 From: David Franca Date: Mon, 31 Jan 2022 18:44:46 -0300 Subject: [PATCH 09/75] chore: replace config manager to config options --- src/Authentication/Factory.php | 16 +++---- src/Authentication/SASLAuthentication.php | 26 +++------- src/Authentication/SSLAuthentication.php | 26 +++------- src/Connectors/Consumer/Config.php | 4 +- .../Consumer/ConnectorInterface.php | 4 +- src/Connectors/Consumer/Factory.php | 48 ++++++++----------- src/Connectors/Consumer/HighLevel.php | 31 ++++++------ src/Connectors/Consumer/LowLevel.php | 35 +++++--------- src/Connectors/Producer/Connector.php | 9 ++-- src/Console/ConfigOptionsCommand.php | 23 +++++---- src/Consumers/LowLevel.php | 8 ++-- src/Producer.php | 30 ++++-------- src/Producer/Poll.php | 15 +++--- .../ProducerWithConfigOptionsTest.php | 1 + 14 files changed, 112 insertions(+), 164 deletions(-) diff --git a/src/Authentication/Factory.php b/src/Authentication/Factory.php index 67e3e1fa..c679209a 100644 --- a/src/Authentication/Factory.php +++ b/src/Authentication/Factory.php @@ -4,6 +4,8 @@ use Metamorphosis\AbstractConfigManager; use Metamorphosis\Exceptions\AuthenticationException; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\AuthInterface; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; use RdKafka\Conf; class Factory @@ -14,9 +16,9 @@ class Factory private const TYPE_NONE = 'none'; - public static function authenticate(Conf $conf, AbstractConfigManager $configManager): void + public static function authenticate(Conf $conf, AuthInterface $configOptions): void { - $type = $configManager->get('auth.type'); + $type = $configOptions->getType(); switch ($type) { case null: case self::TYPE_NONE: @@ -24,17 +26,11 @@ public static function authenticate(Conf $conf, AbstractConfigManager $configMan break; case self::TYPE_SSL: - app( - SSLAuthentication::class, - compact('conf', 'configManager') - ); + app(SSLAuthentication::class, compact('conf', 'configOptions')); break; case self::TYPE_SASL_SSL: - app( - SASLAuthentication::class, - compact('conf', 'configManager') - ); + app(SASLAuthentication::class, compact('conf', 'configOptions')); break; default: diff --git a/src/Authentication/SASLAuthentication.php b/src/Authentication/SASLAuthentication.php index c0ebb42e..9b2fb0d0 100644 --- a/src/Authentication/SASLAuthentication.php +++ b/src/Authentication/SASLAuthentication.php @@ -2,7 +2,7 @@ namespace Metamorphosis\Authentication; -use Metamorphosis\AbstractConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\SaslSsl; use RdKafka\Conf; class SASLAuthentication implements AuthenticationInterface @@ -11,35 +11,23 @@ class SASLAuthentication implements AuthenticationInterface private AbstractConfigManager $configManager; - public function __construct(Conf $conf, AbstractConfigManager $configManager) + public function __construct(Conf $conf, SaslSsl $config) { $this->conf = $conf; - $this->configManager = $configManager; + $this->config = $config; $this->authenticate(); } private function authenticate(): void { - $this->conf->set( - 'security.protocol', - $this->configManager->get('auth.type') - ); + $this->conf->set('security.protocol', $this->config->getType()); // The mechanisms key is optional when configuring this kind of authentication // If the user does not specify the mechanism, the default will be 'PLAIN'. // But, to make config more clear, we are asking the user every time. - $this->conf->set( - 'sasl.mechanisms', - $this->configManager->get('auth.mechanisms') - ); - $this->conf->set( - 'sasl.username', - $this->configManager->get('auth.username') - ); - $this->conf->set( - 'sasl.password', - $this->configManager->get('auth.password') - ); + $this->conf->set('sasl.mechanisms', $this->config->getMechanisms()); + $this->conf->set('sasl.username', $this->config->getUsername()); + $this->conf->set('sasl.password', $this->config->getPassword()); } } diff --git a/src/Authentication/SSLAuthentication.php b/src/Authentication/SSLAuthentication.php index 246ab5e7..750552e8 100644 --- a/src/Authentication/SSLAuthentication.php +++ b/src/Authentication/SSLAuthentication.php @@ -2,7 +2,7 @@ namespace Metamorphosis\Authentication; -use Metamorphosis\AbstractConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\Ssl; use RdKafka\Conf; class SSLAuthentication implements AuthenticationInterface @@ -11,31 +11,19 @@ class SSLAuthentication implements AuthenticationInterface private AbstractConfigManager $configManager; - public function __construct(Conf $conf, AbstractConfigManager $configManager) + public function __construct(Conf $conf, Ssl $configSsl) { $this->conf = $conf; - $this->configManager = $configManager; + $this->configSsl = $configSsl; $this->authenticate(); } private function authenticate(): void { - $this->conf->set( - 'security.protocol', - $this->configManager->get('auth.type') - ); - $this->conf->set( - 'ssl.ca.location', - $this->configManager->get('auth.ca') - ); - $this->conf->set( - 'ssl.certificate.location', - $this->configManager->get('auth.certificate') - ); - $this->conf->set( - 'ssl.key.location', - $this->configManager->get('auth.key') - ); + $this->conf->set('security.protocol', $this->configSsl->getType()); + $this->conf->set('ssl.ca.location', $this->configSsl->getCa()); + $this->conf->set('ssl.certificate.location', $this->configSsl->getCertificate()); + $this->conf->set('ssl.key.location', $this->configSsl->getKey()); } } diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index 57b8b92d..9216cf18 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -39,10 +39,10 @@ class Config extends AbstractConfig 'middlewares' => 'array', ]; - public function makeWithConfigOptions(string $handlerClass): AbstractConfigManager + public function makeWithConfigOptions(string $handlerClass, ?int $times = null): AbstractConfigManager { $configManager = app(ConsumerConfigManager::class); - $configManager->set(['handler' => $handlerClass]); + $configManager->set(['handler' => $handlerClass], ['times' => $times]); return $configManager; } diff --git a/src/Connectors/Consumer/ConnectorInterface.php b/src/Connectors/Consumer/ConnectorInterface.php index 3163fca6..738a6d0e 100644 --- a/src/Connectors/Consumer/ConnectorInterface.php +++ b/src/Connectors/Consumer/ConnectorInterface.php @@ -2,10 +2,10 @@ namespace Metamorphosis\Connectors\Consumer; -use Metamorphosis\AbstractConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; use Metamorphosis\Consumers\ConsumerInterface; interface ConnectorInterface { - public function getConsumer(bool $autoCommit, AbstractConfigManager $configManager): ConsumerInterface; + public function getConsumer(bool $autoCommit, ConfigOptions $configOptions): ConsumerInterface; } diff --git a/src/Connectors/Consumer/Factory.php b/src/Connectors/Consumer/Factory.php index bc7258e9..f48fe56d 100644 --- a/src/Connectors/Consumer/Factory.php +++ b/src/Connectors/Consumer/Factory.php @@ -5,6 +5,7 @@ use Metamorphosis\AbstractConfigManager; use Metamorphosis\Consumers\ConsumerInterface; use Metamorphosis\Middlewares\Handler\Dispatcher; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; /** * This factory will determine what kind of connector will be used. @@ -13,44 +14,33 @@ */ class Factory { - public static function make(AbstractConfigManager $configManager): Manager + public static function make(ConfigOptions $configOptions): Manager { - $autoCommit = $configManager->get('auto_commit', true); - $commitAsync = $configManager->get('commit_async', true); - - $consumer = self::getConsumer($autoCommit, $configManager); - $handler = app($configManager->get('handler')); - - $dispatcher = self::getMiddlewareDispatcher( - $configManager->middlewares() - ); - - return new Manager( - $consumer, - $handler, - $dispatcher, - $autoCommit, - $commitAsync - ); + $autoCommit = $configOptions->isAutoCommit(); + $commitAsync = $configOptions->isCommitASync(); + + $consumer = self::getConsumer($autoCommit, $configOptions); + $handler = app($configOptions->getHandler()); + + $dispatcher = self::getMiddlewareDispatcher($configOptions->getMiddlewares()); + + return new Manager($consumer, $handler, $dispatcher, $autoCommit, $commitAsync); } - public static function getConsumer(bool $autoCommit, AbstractConfigManager $configManager): ConsumerInterface + protected static function requiresPartition(ConfigOptions $configOptions): bool { - if (self::requiresPartition($configManager)) { - return app(LowLevel::class)->getConsumer( - $autoCommit, - $configManager - ); - } + $partition = $configOptions->getPartition(); - return app(HighLevel::class)->getConsumer($autoCommit, $configManager); + return !is_null($partition) && $partition >= 0; } - protected static function requiresPartition(AbstractConfigManager $configManager): bool + public static function getConsumer(bool $autoCommit, ConfigOptions $configOptions): ConsumerInterface { - $partition = $configManager->get('partition'); + if (self::requiresPartition($configOptions)) { + return app(LowLevel::class)->getConsumer($autoCommit, $configOptions); + } - return !is_null($partition) && $partition >= 0; + return app(HighLevel::class)->getConsumer($autoCommit, $configOptions); } private static function getMiddlewareDispatcher(array $middlewares): Dispatcher diff --git a/src/Connectors/Consumer/HighLevel.php b/src/Connectors/Consumer/HighLevel.php index 27d5f3a3..9c832ae0 100644 --- a/src/Connectors/Consumer/HighLevel.php +++ b/src/Connectors/Consumer/HighLevel.php @@ -2,44 +2,43 @@ namespace Metamorphosis\Connectors\Consumer; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Authentication\Factory; use Metamorphosis\Consumers\ConsumerInterface; use Metamorphosis\Consumers\HighLevel as HighLevelConsumer; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; use RdKafka\Conf; use RdKafka\KafkaConsumer; class HighLevel implements ConnectorInterface { - public function getConsumer(bool $autoCommit, AbstractConfigManager $configManager): ConsumerInterface + public function getConsumer(bool $autoCommit, ConfigOptions $configOptions): ConsumerInterface { - $conf = $this->getConf($configManager); - $maxPollIntervalMs = (int) $configManager->get('max_poll_interval_ms'); - - $conf->set('group.id', $configManager->get('consumer_group')); - $conf->set('auto.offset.reset', $configManager->get('offset_reset')); + $conf = $this->getConf($configOptions); + $maxPollIntervalMs = (int) $configOptions->getTimeout(); + $conf->set('group.id', $configOptions->getConsumerGroup()); + $conf->set('auto.offset.reset', $configOptions->getOffsetReset()); + if (!$autoCommit) { + $conf->set('enable.auto.commit', 'false'); + } $conf->set( 'max.poll.interval.ms', $maxPollIntervalMs ?: 300000 ); - if (!$autoCommit) { - $conf->set('enable.auto.commit', 'false'); - } - $consumer = app(KafkaConsumer::class, ['conf' => $conf]); - $consumer->subscribe([$configManager->get('topic_id')]); - $timeout = $configManager->get('timeout'); + $consumer->subscribe([$configOptions->getTopicId()]); + $timeout = $configOptions->getTimeout(); return app(HighLevelConsumer::class, compact('consumer', 'timeout')); } - protected function getConf(AbstractConfigManager $configManager): Conf + protected function getConf(ConfigOptions $configOptions): Conf { $conf = resolve(Conf::class); - Factory::authenticate($conf, $configManager); + $broker = $configOptions->getBroker(); + Factory::authenticate($conf, $broker->getAuth()); - $conf->set('metadata.broker.list', $configManager->get('connections')); + $conf->set('metadata.broker.list', $broker->getConnections()); return $conf; } diff --git a/src/Connectors/Consumer/LowLevel.php b/src/Connectors/Consumer/LowLevel.php index c270fc74..09033a71 100644 --- a/src/Connectors/Consumer/LowLevel.php +++ b/src/Connectors/Consumer/LowLevel.php @@ -6,57 +6,48 @@ use Metamorphosis\Authentication\Factory; use Metamorphosis\Consumers\ConsumerInterface; use Metamorphosis\Consumers\LowLevel as LowLevelConsumer; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; use RdKafka\Conf; use RdKafka\Consumer; use RdKafka\TopicConf; class LowLevel implements ConnectorInterface { - public function getConsumer(bool $autoCommit, AbstractConfigManager $configManager): ConsumerInterface + public function getConsumer(bool $autoCommit, ConfigOptions $configOptions): ConsumerInterface { $conf = $this->getConf(); - $maxPollIntervalMs = (int) $configManager->get('max_poll_interval_ms'); - - $conf->set('group.id', $configManager->get('consumer_group')); + $maxPollIntervalMs = (int) $configOptions->getTimeout(); $conf->set( 'max.poll.interval.ms', $maxPollIntervalMs ?: 300000 ); - + $conf->set('group.id', $configOptions->getConsumerGroup()); if (!$autoCommit) { $conf->set('enable.auto.commit', 'false'); } - Factory::authenticate($conf, $configManager); + $broker = $configOptions->getBroker(); + Factory::authenticate($conf, $broker->getAuth()); $consumer = new Consumer($conf); - $consumer->addBrokers($configManager->get('connections')); + $consumer->addBrokers($broker->getConnections()); - $topicConf = $this->getTopicConfigs($configManager); - $topicConsumer = $consumer->newTopic( - $configManager->get('topic_id'), - $topicConf - ); + $topicConf = $this->getTopicConfigs($configOptions); + $topicConsumer = $consumer->newTopic($configOptions->getTopicId(), $topicConf); - $topicConsumer->consumeStart( - $configManager->get('partition'), - $configManager->get('offset') - ); + $topicConsumer->consumeStart($configOptions->getPartition(), $configOptions->getOffset()); - return new LowLevelConsumer($topicConsumer, $configManager); + return new LowLevelConsumer($topicConsumer, $configOptions); } - protected function getTopicConfigs(AbstractConfigManager $configManager) + protected function getTopicConfigs(ConfigOptions $configOptions) { $topicConfig = new TopicConf(); // Set where to start consuming messages when there is no initial offset in // offset store or the desired offset is out of range. // 'smallest': start from the beginning - $topicConfig->set( - 'auto.offset.reset', - $configManager->get('offset_reset') - ); + $topicConfig->set('auto.offset.reset', $configOptions->getOffsetReset()); return $topicConfig; } diff --git a/src/Connectors/Producer/Connector.php b/src/Connectors/Producer/Connector.php index ebe696ea..68eafb07 100644 --- a/src/Connectors/Producer/Connector.php +++ b/src/Connectors/Producer/Connector.php @@ -2,8 +2,8 @@ namespace Metamorphosis\Connectors\Producer; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Authentication\Factory; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptions; use Metamorphosis\TopicHandler\Producer\HandleableResponseInterface; use Metamorphosis\TopicHandler\Producer\HandlerInterface; use RdKafka\Conf; @@ -12,7 +12,7 @@ class Connector { - public function getProducerTopic(HandlerInterface $handler, AbstractConfigManager $configManager): KafkaProducer + public function getProducerTopic(HandlerInterface $handler, ConfigOptions $configOptions): KafkaProducer { $conf = resolve(Conf::class); @@ -29,9 +29,10 @@ function ($kafka, Message $message) use ($handler) { ); } - $conf->set('metadata.broker.list', $configManager->get('connections')); + $broker = $configOptions->getBroker(); + $conf->set('metadata.broker.list', $broker->getConnections()); - Factory::authenticate($conf, $configManager); + Factory::authenticate($conf, $broker->getAuth()); return app(KafkaProducer::class, compact('conf')); } diff --git a/src/Console/ConfigOptionsCommand.php b/src/Console/ConfigOptionsCommand.php index 37dab14c..4d37240b 100644 --- a/src/Console/ConfigOptionsCommand.php +++ b/src/Console/ConfigOptionsCommand.php @@ -6,6 +6,7 @@ use Metamorphosis\Connectors\Consumer\Config; use Metamorphosis\Connectors\Consumer\Factory; use Metamorphosis\Consumers\Runner; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; class ConfigOptionsCommand extends BaseCommand { @@ -22,25 +23,29 @@ class ConfigOptionsCommand extends BaseCommand /** * @var {inheritdoc} */ - protected $signature = 'kafka:consume-config-class {handler : handler.}'; + protected $signature = 'kafka:consume-config-class + {handler : handler.} + {--times= : Amount of messages to be consumed.}'; public function handle(Config $config) { - $configManager = $config->makeWithConfigOptions($this->argument()['handler']); + $consumerHandler = app($this->argument('handler')); - $this->writeStartingConsumer($configManager); + $configOptions = $consumerHandler->getConfigOptions(); - $manager = Factory::make($configManager); + $this->writeStartingConsumer($configOptions); + + $manager = Factory::make($configOptions); $runner = app(Runner::class, compact('manager')); - $runner->run(2); + $runner->run($this->option('times')); } - private function writeStartingConsumer(AbstractConfigManager $configManager) + private function writeStartingConsumer(ConfigOptions $configOptions) { - $text = 'Starting consumer for topic: '.$configManager->get('topic').PHP_EOL; - $text .= ' on consumer group: '.$configManager->get('consumer_group').PHP_EOL; - $text .= 'Connecting in '.$configManager->get('connections').PHP_EOL; + $text = 'Starting consumer for topic: '.$configOptions->getTopicId().PHP_EOL; + $text .= ' on consumer group: '.$configOptions->getConsumerGroup().PHP_EOL; + $text .= 'Connecting in '.$configOptions->getBroker()->getConnections().PHP_EOL; $text .= 'Running consumer..'; $this->output->writeln($text); diff --git a/src/Consumers/LowLevel.php b/src/Consumers/LowLevel.php index 0a1d762b..e4a31ea0 100644 --- a/src/Consumers/LowLevel.php +++ b/src/Consumers/LowLevel.php @@ -2,7 +2,7 @@ namespace Metamorphosis\Consumers; -use Metamorphosis\AbstractConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; use RdKafka\ConsumerTopic; use RdKafka\Message; @@ -14,12 +14,12 @@ class LowLevel implements ConsumerInterface private ?int $timeout; - public function __construct(ConsumerTopic $consumer, AbstractConfigManager $configManager) + public function __construct(ConsumerTopic $consumer, ConfigOptions $configOptions) { $this->consumer = $consumer; - $this->partition = $configManager->get('partition'); - $this->timeout = $configManager->get('timeout'); + $this->partition = $configOptions->getPartition(); + $this->timeout = $configOptions->getTimeout(); } public function consume(): ?Message diff --git a/src/Producer.php b/src/Producer.php index 61c155a3..e1187cf0 100644 --- a/src/Producer.php +++ b/src/Producer.php @@ -7,6 +7,7 @@ use Metamorphosis\Middlewares\Handler\Dispatcher; use Metamorphosis\Middlewares\Handler\Producer as ProducerMiddleware; use Metamorphosis\Producer\Poll; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptions; use Metamorphosis\TopicHandler\Producer\AbstractProducer; use Metamorphosis\TopicHandler\Producer\HandlerInterface; @@ -31,32 +32,21 @@ public function produce(HandlerInterface $producerHandler): void public function build(HandlerInterface $producerHandler): Dispatcher { - $configManager = $this->getConfigManager($producerHandler); + $configOptions = $producerHandler->getConfigOptions(); - $middlewares = $configManager->middlewares(); - $middlewares[] = $this->getProducerMiddleware( - $producerHandler, - $configManager - ); + $middlewares = $configOptions->getMiddlewares(); + $middlewares[] = $this->getProducerMiddleware($producerHandler, $configOptions); return new Dispatcher($middlewares); } - public function getProducerMiddleware( - HandlerInterface $producerHandler, - AbstractConfigManager $configManager - ): ProducerMiddleware { - $producer = $this->connector->getProducerTopic( - $producerHandler, - $configManager - ); + public function getProducerMiddleware(HandlerInterface $producerHandler, ConfigOptions $configOptions): ProducerMiddleware + { + $producer = $this->connector->getProducerTopic($producerHandler, $configOptions); - $topic = $producer->newTopic($configManager->get('topic_id')); - $poll = app( - Poll::class, - ['producer' => $producer, 'configManager' => $configManager] - ); - $partition = $configManager->get('partition'); + $topic = $producer->newTopic($configOptions->getTopicId()); + $poll = app(Poll::class, ['producer' => $producer, 'configOptions' => $configOptions]); + $partition = $configOptions->getPartition(); return app( ProducerMiddleware::class, diff --git a/src/Producer/Poll.php b/src/Producer/Poll.php index afb8d081..d6a64626 100644 --- a/src/Producer/Poll.php +++ b/src/Producer/Poll.php @@ -3,6 +3,7 @@ namespace Metamorphosis\Producer; use Metamorphosis\AbstractConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptions; use RdKafka\Producer; use RuntimeException; @@ -24,15 +25,13 @@ class Poll private Producer $producer; - public function __construct(Producer $producer, AbstractConfigManager $configManager) + public function __construct(Producer $producer, ConfigOptions $configOptions) { - $this->isAsync = $configManager->get('is_async'); - $this->maxPollRecords = $configManager->get('max_poll_records'); - $this->requiredAcknowledgment = $configManager->get( - 'required_acknowledgment' - ); - $this->maxFlushAttempts = $configManager->get('flush_attempts'); - $this->timeout = $configManager->get('timeout'); + $this->isAsync = $configOptions->isAsync(); + $this->maxPollRecords = $configOptions->getMaxPollRecords(); + $this->requiredAcknowledgment = $configOptions->isRequiredAcknowledgment(); + $this->maxFlushAttempts = $configOptions->getFlushAttempts(); + $this->timeout = $configOptions->getTimeout(); $this->producer = $producer; } diff --git a/tests/Integration/ProducerWithConfigOptionsTest.php b/tests/Integration/ProducerWithConfigOptionsTest.php index 4a45d8e0..4e256a42 100644 --- a/tests/Integration/ProducerWithConfigOptionsTest.php +++ b/tests/Integration/ProducerWithConfigOptionsTest.php @@ -45,6 +45,7 @@ protected function runTheConsumer(): void 'kafka:consume-config-class', [ 'handler' => '\\App\\Kafka\\Consumers\\ConsumerOverride', + '--times' => 2, ] ); } From cc761f3137233117a17302347ef4a3e0881ea2e7 Mon Sep 17 00:00:00 2001 From: David Franca Date: Tue, 1 Feb 2022 09:46:24 -0300 Subject: [PATCH 10/75] chore: migrate Avro to use ConfigOptions\AvroSchema --- src/Avro/ClientFactory.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Avro/ClientFactory.php b/src/Avro/ClientFactory.php index 0e537e4c..b30d0c1b 100644 --- a/src/Avro/ClientFactory.php +++ b/src/Avro/ClientFactory.php @@ -3,29 +3,31 @@ namespace Metamorphosis\Avro; use GuzzleHttp\Client as GuzzleClient; -use Metamorphosis\AbstractConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema; class ClientFactory { - public function make(AbstractConfigManager $configManager): CachedSchemaRegistryClient + const REQUEST_TIMEOUT = 2000; + + public function make(AvroSchema $avroSchema): CachedSchemaRegistryClient { - $guzzleHttp = $this->getGuzzleHttpClient($configManager); + $guzzleHttp = $this->getGuzzleHttpClient($avroSchema); $client = app(Client::class, ['client' => $guzzleHttp]); return app(CachedSchemaRegistryClient::class, compact('client')); } - private function getGuzzleHttpClient(AbstractConfigManager $configManager): GuzzleClient + private function getGuzzleHttpClient(AvroSchema $avroSchema): GuzzleClient { - $config = $configManager->get('request_options') ?: []; - $config['timeout'] = $configManager->get('timeout'); - $config['base_uri'] = $configManager->get('url'); + $config = $avroSchema->getRequestOptions(); + $config['timeout'] = self::REQUEST_TIMEOUT; + $config['base_uri'] = $avroSchema->getUrl(); $config['headers'] = array_merge( $this->getDefaultHeaders(), $config['headers'] ?? [] ); - $config['verify'] = $configManager->get('ssl_verify') ?? false; + $config['verify'] = $avroSchema->getRequestOptions()['ssl_verify'] ?? false; return app(GuzzleClient::class, compact('config')); } From de4331cd91881dc6b770c33599f9cdae457d7ff4 Mon Sep 17 00:00:00 2001 From: David Franca Date: Tue, 1 Feb 2022 10:00:06 -0300 Subject: [PATCH 11/75] chore: migrate Aith factory to use config options --- src/Authentication/Factory.php | 2 -- src/Authentication/SASLAuthentication.php | 17 +++++---- src/Authentication/SSLAuthentication.php | 17 +++++---- src/Connectors/Consumer/Config.php | 5 ++- src/Console/ConsumerCommand.php | 1 + src/Middlewares/AvroSchemaDecoder.php | 19 +++++----- tests/Unit/Authentication/FactoryTest.php | 43 ++++++++++------------- 7 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/Authentication/Factory.php b/src/Authentication/Factory.php index c679209a..c8a8f38a 100644 --- a/src/Authentication/Factory.php +++ b/src/Authentication/Factory.php @@ -2,10 +2,8 @@ namespace Metamorphosis\Authentication; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Exceptions\AuthenticationException; use Metamorphosis\TopicHandler\ConfigOptions\Auth\AuthInterface; -use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; use RdKafka\Conf; class Factory diff --git a/src/Authentication/SASLAuthentication.php b/src/Authentication/SASLAuthentication.php index 9b2fb0d0..3918558d 100644 --- a/src/Authentication/SASLAuthentication.php +++ b/src/Authentication/SASLAuthentication.php @@ -9,25 +9,28 @@ class SASLAuthentication implements AuthenticationInterface { private Conf $conf; - private AbstractConfigManager $configManager; + /** + * @var SaslSsl + */ + private $configOptions; - public function __construct(Conf $conf, SaslSsl $config) + public function __construct(Conf $conf, SaslSsl $configOptions) { $this->conf = $conf; - $this->config = $config; + $this->configOptions = $configOptions; $this->authenticate(); } private function authenticate(): void { - $this->conf->set('security.protocol', $this->config->getType()); + $this->conf->set('security.protocol', $this->configOptions->getType()); // The mechanisms key is optional when configuring this kind of authentication // If the user does not specify the mechanism, the default will be 'PLAIN'. // But, to make config more clear, we are asking the user every time. - $this->conf->set('sasl.mechanisms', $this->config->getMechanisms()); - $this->conf->set('sasl.username', $this->config->getUsername()); - $this->conf->set('sasl.password', $this->config->getPassword()); + $this->conf->set('sasl.mechanisms', $this->configOptions->getMechanisms()); + $this->conf->set('sasl.username', $this->configOptions->getUsername()); + $this->conf->set('sasl.password', $this->configOptions->getPassword()); } } diff --git a/src/Authentication/SSLAuthentication.php b/src/Authentication/SSLAuthentication.php index 750552e8..5dfc06e4 100644 --- a/src/Authentication/SSLAuthentication.php +++ b/src/Authentication/SSLAuthentication.php @@ -9,21 +9,24 @@ class SSLAuthentication implements AuthenticationInterface { private Conf $conf; - private AbstractConfigManager $configManager; + /** + * @var Ssl + */ + private $configOptions; - public function __construct(Conf $conf, Ssl $configSsl) + public function __construct(Conf $conf, Ssl $configOptions) { $this->conf = $conf; - $this->configSsl = $configSsl; + $this->configOptions = $configOptions; $this->authenticate(); } private function authenticate(): void { - $this->conf->set('security.protocol', $this->configSsl->getType()); - $this->conf->set('ssl.ca.location', $this->configSsl->getCa()); - $this->conf->set('ssl.certificate.location', $this->configSsl->getCertificate()); - $this->conf->set('ssl.key.location', $this->configSsl->getKey()); + $this->conf->set('security.protocol', $this->configOptions->getType()); + $this->conf->set('ssl.ca.location', $this->configOptions->getCa()); + $this->conf->set('ssl.certificate.location', $this->configOptions->getCertificate()); + $this->conf->set('ssl.key.location', $this->configOptions->getKey()); } } diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index 9216cf18..fa6d1398 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -6,6 +6,7 @@ use Metamorphosis\Connectors\AbstractConfig; use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Exceptions\ConfigurationException; +use Metamorphosis\TopicHandler\ConfigOptions\Factories\ConsumerFactory; /** * This class is responsible for handling all configuration made on the @@ -75,10 +76,8 @@ public function make(array $options, array $arguments): AbstractConfigManager ); $this->validate(array_merge($config, $override)); - $configManager = app(ConsumerConfigManager::class); - $configManager->set($config, $override); - return $configManager; + return ConsumerFactory::make($brokerConfig, $topicConfig, $schemaConfig); } /** diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index c4bdab76..bd80175e 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -7,6 +7,7 @@ use Metamorphosis\Connectors\Consumer\Config; use Metamorphosis\Connectors\Consumer\Factory; use Metamorphosis\Consumers\Runner; +use Metamorphosis\TopicHandler\ConfigOptions\Factories\ConsumerFactory; class ConsumerCommand extends BaseCommand { diff --git a/src/Middlewares/AvroSchemaDecoder.php b/src/Middlewares/AvroSchemaDecoder.php index 4ae626c9..8d185fdd 100644 --- a/src/Middlewares/AvroSchemaDecoder.php +++ b/src/Middlewares/AvroSchemaDecoder.php @@ -3,28 +3,29 @@ namespace Metamorphosis\Middlewares; use Closure; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Avro\ClientFactory; use Metamorphosis\Avro\Serializer\MessageDecoder; use Metamorphosis\Exceptions\ConfigurationException; use Metamorphosis\Record\RecordInterface; +use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema; class AvroSchemaDecoder implements MiddlewareInterface { private MessageDecoder $decoder; - private AbstractConfigManager $configManager; + /** + * @var AvroSchema + */ + private $avroSchema; - public function __construct(AbstractConfigManager $configManager, ClientFactory $factory) + public function __construct(AvroSchema $avroSchema, ClientFactory $factory) { - $this->configManager = $configManager; - if (!$this->configManager->get('url')) { - throw new ConfigurationException( - "Avro schema url not found, it's required to use AvroSchemaDecoder Middleware" - ); + $this->avroSchema = $avroSchema; + if (!$this->avroSchema->getUrl()) { + throw new ConfigurationException("Avro schema url not found, it's required to use AvroSchemaDecoder Middleware"); } - $this->decoder = new MessageDecoder($factory->make($configManager)); + $this->decoder = new MessageDecoder($factory->make($avroSchema)); } public function process(RecordInterface $record, Closure $next) diff --git a/tests/Unit/Authentication/FactoryTest.php b/tests/Unit/Authentication/FactoryTest.php index 53999f8a..717abe16 100644 --- a/tests/Unit/Authentication/FactoryTest.php +++ b/tests/Unit/Authentication/FactoryTest.php @@ -3,8 +3,11 @@ namespace Tests\Unit\Authentication; use Metamorphosis\Authentication\Factory; -use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Exceptions\AuthenticationException; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\AuthInterface; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\SaslSsl; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\Ssl; +use Mockery as m; use RdKafka\Conf; use Tests\LaravelTestCase; @@ -13,15 +16,7 @@ class FactoryTest extends LaravelTestCase public function testItMakesSslAuthenticationClass(): void { // Set - $configManager = new ConsumerConfigManager(); - $configManager->set([ - 'auth' => [ - 'type' => 'ssl', - 'ca' => 'path/to/ca', - 'certificate' => 'path/to/certificate', - 'key' => 'path/to/key', - ], - ]); + $configOptionsSsl = new Ssl('path/to/ca', 'path/to/certificate', 'path/to/key'); $conf = new Conf(); $expected = [ 'security.protocol' => 'ssl', @@ -31,7 +26,7 @@ public function testItMakesSslAuthenticationClass(): void ]; // Actions - Factory::authenticate($conf, $configManager); + Factory::authenticate($conf, $configOptionsSsl); // Assertions $this->assertArraySubset($expected, $conf->dump()); @@ -40,15 +35,11 @@ public function testItMakesSslAuthenticationClass(): void public function testItMakesSASLAuthenticationClass(): void { // Set - $configManager = new ConsumerConfigManager(); - $configManager->set([ - 'auth' => [ - 'type' => 'sasl_ssl', - 'mechanisms' => 'PLAIN', - 'username' => 'some-username', - 'password' => 'some-password', - ], - ]); + $configOptionsSaslSsl = new SaslSsl( + 'PLAIN', + 'some-username', + 'some-password' + ); $conf = new Conf(); $expected = [ 'security.protocol' => 'sasl_ssl', @@ -58,7 +49,7 @@ public function testItMakesSASLAuthenticationClass(): void ]; // Actions - Factory::authenticate($conf, $configManager); + Factory::authenticate($conf, $configOptionsSaslSsl); // Assertions $this->assertArraySubset($expected, $conf->dump()); @@ -67,13 +58,17 @@ public function testItMakesSASLAuthenticationClass(): void public function testItThrowsExceptionWhenInvalidProtocolIsPassed(): void { // Set - $configManager = new ConsumerConfigManager(); - $configManager->set(['auth' => ['type' => 'some-invalid-type']]); + $invalidAuth = m::mock(AuthInterface::class); $conf = new Conf(); + // Expectations + $invalidAuth->expects() + ->getType() + ->andReturn('some-invalid-type'); + $this->expectException(AuthenticationException::class); // Actions - Factory::authenticate($conf, $configManager); + Factory::authenticate($conf, $invalidAuth); } } From 4147c57152dc582d64e26e19a57dbdfa5e6cab74 Mon Sep 17 00:00:00 2001 From: Hugo Ferreira Date: Tue, 1 Feb 2022 10:28:02 -0300 Subject: [PATCH 12/75] chore: remove configManager and add Sasl config class --- .../Authentication/SASLAuthenticationTest.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/Unit/Authentication/SASLAuthenticationTest.php b/tests/Unit/Authentication/SASLAuthenticationTest.php index ce1078b3..f9e9a474 100644 --- a/tests/Unit/Authentication/SASLAuthenticationTest.php +++ b/tests/Unit/Authentication/SASLAuthenticationTest.php @@ -3,7 +3,7 @@ namespace Tests\Unit\Authentication; use Metamorphosis\Authentication\SASLAuthentication; -use Metamorphosis\ConsumerConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\SaslSsl; use RdKafka\Conf; use Tests\LaravelTestCase; @@ -12,16 +12,9 @@ class SASLAuthenticationTest extends LaravelTestCase public function testItShouldValidateAuthenticationConfigurations(): void { // Set - $configManager = new ConsumerConfigManager(); - $configManager->set([ - 'auth' => [ - 'type' => 'sasl_ssl', - 'mechanisms' => 'PLAIN', - 'username' => 'some-username', - 'password' => 'some-password', - ], - ]); + $configSaslSsl = new SaslSsl('PLAIN', 'some-username', 'some-password'); $conf = new Conf(); + $expected = [ 'security.protocol' => 'sasl_ssl', 'sasl.username' => 'some-username', @@ -30,7 +23,7 @@ public function testItShouldValidateAuthenticationConfigurations(): void ]; // Actions - new SASLAuthentication($conf, $configManager); + new SASLAuthentication($conf, $configSaslSsl); // Assertions $this->assertArraySubset($expected, $conf->dump()); From 2ff2aa20ad5acd6a028a03164a6d035d6d3eeb77 Mon Sep 17 00:00:00 2001 From: Hugo Ferreira Date: Tue, 1 Feb 2022 10:31:05 -0300 Subject: [PATCH 13/75] chore: remove configManager and add SSL config class --- .../Unit/Authentication/SSLAuthenticationTest.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tests/Unit/Authentication/SSLAuthenticationTest.php b/tests/Unit/Authentication/SSLAuthenticationTest.php index 11c93691..35a9168e 100644 --- a/tests/Unit/Authentication/SSLAuthenticationTest.php +++ b/tests/Unit/Authentication/SSLAuthenticationTest.php @@ -3,7 +3,7 @@ namespace Tests\Unit\Authentication; use Metamorphosis\Authentication\SSLAuthentication; -use Metamorphosis\ConsumerConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\Ssl; use RdKafka\Conf; use Tests\LaravelTestCase; @@ -12,16 +12,8 @@ class SSLAuthenticationTest extends LaravelTestCase public function testItShouldValidateAuthenticationConfigurations(): void { // Set - $configManager = new ConsumerConfigManager(); - $configManager->set([ - 'auth' => [ - 'type' => 'ssl', - 'ca' => 'path/to/ca', - 'certificate' => 'path/to/certificate', - 'key' => 'path/to/key', - ], - ]); $conf = new Conf(); + $configSsl = new Ssl('path/to/ca', 'path/to/certificate', 'path/to/key'); $expected = [ 'security.protocol' => 'ssl', 'ssl.ca.location' => 'path/to/ca', @@ -30,7 +22,7 @@ public function testItShouldValidateAuthenticationConfigurations(): void ]; // Actions - new SSLAuthentication($conf, $configManager); + new SSLAuthentication($conf, $configSsl); // Assertions $this->assertArraySubset($expected, $conf->dump()); From 0628b306c079a7feef679c77bc23d2165e9cec24 Mon Sep 17 00:00:00 2001 From: Hugo Ferreira Date: Tue, 1 Feb 2022 12:04:03 -0300 Subject: [PATCH 14/75] chore: fix code standard with phpcbf --- src/Connectors/Consumer/ConnectorInterface.php | 2 +- src/Connectors/Consumer/Factory.php | 1 - src/Connectors/Consumer/LowLevel.php | 1 - src/Console/ConfigOptionsCommand.php | 1 - src/Console/ConsumerCommand.php | 1 - src/Producer/Poll.php | 1 - 6 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Connectors/Consumer/ConnectorInterface.php b/src/Connectors/Consumer/ConnectorInterface.php index 738a6d0e..f9a7934d 100644 --- a/src/Connectors/Consumer/ConnectorInterface.php +++ b/src/Connectors/Consumer/ConnectorInterface.php @@ -2,8 +2,8 @@ namespace Metamorphosis\Connectors\Consumer; -use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; use Metamorphosis\Consumers\ConsumerInterface; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; interface ConnectorInterface { diff --git a/src/Connectors/Consumer/Factory.php b/src/Connectors/Consumer/Factory.php index f48fe56d..893e9030 100644 --- a/src/Connectors/Consumer/Factory.php +++ b/src/Connectors/Consumer/Factory.php @@ -2,7 +2,6 @@ namespace Metamorphosis\Connectors\Consumer; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Consumers\ConsumerInterface; use Metamorphosis\Middlewares\Handler\Dispatcher; use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; diff --git a/src/Connectors/Consumer/LowLevel.php b/src/Connectors/Consumer/LowLevel.php index 09033a71..7c7395ac 100644 --- a/src/Connectors/Consumer/LowLevel.php +++ b/src/Connectors/Consumer/LowLevel.php @@ -2,7 +2,6 @@ namespace Metamorphosis\Connectors\Consumer; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Authentication\Factory; use Metamorphosis\Consumers\ConsumerInterface; use Metamorphosis\Consumers\LowLevel as LowLevelConsumer; diff --git a/src/Console/ConfigOptionsCommand.php b/src/Console/ConfigOptionsCommand.php index 4d37240b..eb4c1071 100644 --- a/src/Console/ConfigOptionsCommand.php +++ b/src/Console/ConfigOptionsCommand.php @@ -2,7 +2,6 @@ namespace Metamorphosis\Console; use Illuminate\Console\Command as BaseCommand; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Connectors\Consumer\Config; use Metamorphosis\Connectors\Consumer\Factory; use Metamorphosis\Consumers\Runner; diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index bd80175e..c4bdab76 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -7,7 +7,6 @@ use Metamorphosis\Connectors\Consumer\Config; use Metamorphosis\Connectors\Consumer\Factory; use Metamorphosis\Consumers\Runner; -use Metamorphosis\TopicHandler\ConfigOptions\Factories\ConsumerFactory; class ConsumerCommand extends BaseCommand { diff --git a/src/Producer/Poll.php b/src/Producer/Poll.php index d6a64626..4c3b9c81 100644 --- a/src/Producer/Poll.php +++ b/src/Producer/Poll.php @@ -2,7 +2,6 @@ namespace Metamorphosis\Producer; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptions; use RdKafka\Producer; use RuntimeException; From 602bcbd65dd5cc1d82adb2b26e168b7b4fad934b Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 7 Mar 2022 18:11:01 -0300 Subject: [PATCH 15/75] chore: debug config options --- src/Connectors/Consumer/Config.php | 3 +- src/Console/ConsumerCommand.php | 24 ++++------- src/Consumer.php | 4 +- .../Producer/AbstractProducer.php | 15 ++++--- tests/Integration/ConsumerTest.php | 11 ++--- tests/Integration/Dummies/MessageProducer.php | 14 +------ tests/Integration/ProducerTest.php | 41 ++++++++++++------- tests/Unit/ProducerTest.php | 16 ++++---- 8 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index fa6d1398..d14770fb 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -6,6 +6,7 @@ use Metamorphosis\Connectors\AbstractConfig; use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Exceptions\ConfigurationException; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer; use Metamorphosis\TopicHandler\ConfigOptions\Factories\ConsumerFactory; /** @@ -48,7 +49,7 @@ public function makeWithConfigOptions(string $handlerClass, ?int $times = null): return $configManager; } - public function make(array $options, array $arguments): AbstractConfigManager + public function make(array $options, array $arguments): Consumer { $configName = $options['config_name'] ?? 'kafka'; $topicConfig = $this->getTopicConfig($configName, $arguments['topic']); diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index c4bdab76..5c233db4 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -3,10 +3,10 @@ namespace Metamorphosis\Console; use Illuminate\Console\Command as BaseCommand; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Connectors\Consumer\Config; use Metamorphosis\Connectors\Consumer\Factory; use Metamorphosis\Consumers\Runner; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer; class ConsumerCommand extends BaseCommand { @@ -38,27 +38,21 @@ class ConsumerCommand extends BaseCommand public function handle(Config $config) { - $configManager = $config->make($this->option(), $this->argument()); + $consumer = $config->make($this->option(), $this->argument()); - $this->writeStartingConsumer($configManager); + $this->writeStartingConsumer($consumer); - $manager = Factory::make($configManager); + $manager = Factory::make($consumer); $runner = app(Runner::class, compact('manager')); - $runner->run($configManager->get('times')); + $runner->run($this->option('times')); } - private function writeStartingConsumer(AbstractConfigManager $configManager) + private function writeStartingConsumer(Consumer $consumer) { - $text = 'Starting consumer for topic: ' . $configManager->get( - 'topic' - ) . PHP_EOL; - $text .= ' on consumer group: ' . $configManager->get( - 'consumer_group' - ) . PHP_EOL; - $text .= 'Connecting in ' . $configManager->get( - 'connections' - ) . PHP_EOL; + $text = 'Starting consumer for topic: '.$consumer->getTopicId().PHP_EOL; + $text .= ' on consumer group: '.$consumer->getConsumerGroup().PHP_EOL; + $text .= 'Connecting in '.$consumer->getBroker()->getConnections().PHP_EOL; $text .= 'Running consumer..'; $this->output->writeln($text); diff --git a/src/Consumer.php b/src/Consumer.php index ba04c783..1d35a0c1 100644 --- a/src/Consumer.php +++ b/src/Consumer.php @@ -19,8 +19,8 @@ public function __construct(ConsumerConfigManager $configManager, ConsumerConfig { $configManager->set($configOptions->toArray()); - $this->consumer = Factory::getConsumer(true, $configManager); - $this->dispatcher = new Dispatcher($configManager->middlewares()); + $this->consumer = Factory::getConsumer(true, $configOptions); + $this->dispatcher = new Dispatcher($configOptions->getMiddlewares()); } public function consume(): ?RecordInterface diff --git a/src/TopicHandler/Producer/AbstractProducer.php b/src/TopicHandler/Producer/AbstractProducer.php index e95a6f63..946db3ce 100644 --- a/src/TopicHandler/Producer/AbstractProducer.php +++ b/src/TopicHandler/Producer/AbstractProducer.php @@ -4,7 +4,7 @@ use Metamorphosis\Exceptions\JsonException; use Metamorphosis\Record\ProducerRecord; -use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptionsProducer; +use Metamorphosis\TopicHandler\ConfigOptions\Producer; class AbstractProducer implements HandlerInterface { @@ -15,18 +15,21 @@ class AbstractProducer implements HandlerInterface protected ?string $key; - private ConfigOptionsProducer $configOptions; + /** + * @var Producer + */ + protected $producer; - public function __construct($record, ConfigOptionsProducer $configOptions, ?string $key = null) + public function __construct($record, Producer $producer, string $key = null) { $this->record = $record; $this->key = $key; - $this->configOptions = $configOptions; + $this->producer = $producer; } - public function getConfigOptions(): ConfigOptionsProducer + public function getConfigOptions(): Producer { - return $this->configOptions; + return $this->producer; } public function getRecord() diff --git a/tests/Integration/ConsumerTest.php b/tests/Integration/ConsumerTest.php index 8c107499..1d4397e8 100644 --- a/tests/Integration/ConsumerTest.php +++ b/tests/Integration/ConsumerTest.php @@ -59,16 +59,13 @@ public function testItShouldSetup(): void $saleOrderDispatcher = Metamorphosis::build($messageProducer); $saleOrderDispatcher->handle($messageProducer->createRecord()); - $consumer = $this->app->make( - Consumer::class, - ['configOptions' => $consumerConfigOptions] - ); - $expected = ['id' => 'MESSAGE_ID']; + $consumer = $this->app->make(Consumer::class, ['configOptions' => $consumerConfigOptions]); + $expected = '{"id":"MESSAGE_ID"}'; // Actions - $result = $consumer->consume(); + $result = $consumer->consume()->getPayload(); // Assertions - $this->assertSame($expected, $result->getPayload()); + $this->assertSame($expected, $result); } } diff --git a/tests/Integration/Dummies/MessageProducer.php b/tests/Integration/Dummies/MessageProducer.php index 22aac6f8..38fb8090 100644 --- a/tests/Integration/Dummies/MessageProducer.php +++ b/tests/Integration/Dummies/MessageProducer.php @@ -3,22 +3,12 @@ namespace Tests\Integration\Dummies; use Illuminate\Support\Facades\Log; -use Metamorphosis\TopicHandler\Producer\AbstractHandler; +use Metamorphosis\TopicHandler\Producer\AbstractProducer; use RdKafka\Message; use RuntimeException; -class MessageProducer extends AbstractHandler +class MessageProducer extends AbstractProducer { - public string $topic = 'default'; - - public function __construct($record, string $topic, ?string $key = null, ?int $partition = null) - { - $this->record = $record; - $this->topic = $topic; - $this->key = $key ?? 'recordId123'; - $this->partition = $partition; - } - public function success(Message $message): void { Log::info('Record successfully sent to broker.', [ diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index f7d13966..1689fe87 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -5,6 +5,9 @@ use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; use Metamorphosis\Facades\Metamorphosis; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\Broker; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use Tests\Integration\Dummies\MessageConsumer; use Tests\Integration\Dummies\MessageProducer; use Tests\LaravelTestCase; @@ -17,11 +20,13 @@ class ProducerTest extends LaravelTestCase protected string $secondLowLevelMessage; + /** + * @group runProducer + */ public function testShouldRunAProducerAndReceiveMessagesWithAHighLevelConsumer(): void { // Given That I $this->haveAConsumerHandlerConfigured(); - $this->haveNoPartitionConfigured(); $this->haveSomeRandomMessagesProduced(); // I Expect That @@ -128,13 +133,9 @@ protected function runTheLowLevelConsumerSkippingTheFirstTwoMessagesAndLimitingT private function haveSomeRandomMessagesProduced(): void { $this->highLevelMessage = Str::random(10); - $producer = app( - MessageProducer::class, - [ - 'record' => $this->highLevelMessage, - 'topic' => 'default', - ] - ); + $configOptionsProducer = $this->createConfigOptionsProducer('kafka-test'); + //$producer = app(MessageProducer::class, ['record' => $this->highLevelMessage, 'configOptions'=> $configOptionsProducer]); + $producer = new MessageProducer($this->highLevelMessage, $configOptionsProducer, 'recordId123'); Metamorphosis::produce($producer); Metamorphosis::produce($producer); @@ -142,8 +143,10 @@ private function haveSomeRandomMessagesProduced(): void private function produceRecordMessage(string $record): string { - $topic = 'low_level'; - $producer = app(MessageProducer::class, compact('record', 'topic')); + $configOptionsProducer = $this->createConfigOptionsProducer('low_level'); + $producer = new MessageProducer($record, $configOptionsProducer, 'recordId123'); + //$producer = app(MessageProducer::class, ['record'=>$record, 'configOptions' => $a]); + //$producer->topic = 'low_level'; Metamorphosis::produce($producer); Metamorphosis::produce($producer); @@ -183,10 +186,20 @@ private function haveFourProducedMessages(): void $this->produceRecordMessage($this->secondLowLevelMessage); } - private function haveNoPartitionConfigured(): void - { - config( - ['kafka.topics.default.consumer.consumer_groups.test-consumer-group.partition' => -1] + private function createConfigOptionsProducer(string $topicId = 'kafka-test'): ProducerConfigOptions + { + $brokerOptions = new Broker('kafka:9092', new None()); + return new ProducerConfigOptions( + $topicId, + $brokerOptions, + null, + null, + [], + 20000, + false, + true, + 10, + 500 ); } } diff --git a/tests/Unit/ProducerTest.php b/tests/Unit/ProducerTest.php index 5a93dc8c..31650aef 100644 --- a/tests/Unit/ProducerTest.php +++ b/tests/Unit/ProducerTest.php @@ -12,7 +12,6 @@ use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; use Metamorphosis\TopicHandler\ConfigOptions\Broker; use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; -use Metamorphosis\TopicHandler\Producer\AbstractHandler; use Metamorphosis\TopicHandler\Producer\AbstractProducer; use Mockery as m; use RdKafka\Producer as KafkaProducer; @@ -38,7 +37,7 @@ public function testItShouldProduceRecordAsArrayThroughMiddlewareQueue(): void $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $producerHandler = new class ($record, $topic) extends AbstractHandler { + $producerHandler = new class($record, $topic) extends AbstractProducer { }; // Expectations @@ -95,7 +94,7 @@ public function testItShouldProduceRecordAsStringThroughMiddlewareQueue(): void $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $producerHandler = new class ($record, $topic) extends AbstractHandler { + $producerHandler = new class($record, $topic) extends AbstractProducer { }; // Expectations @@ -128,7 +127,10 @@ public function testItShouldProduceRecordAsStringThroughMiddlewareQueue(): void ->withAnyArgs(); // Actions - $producer->produce($producerHandler); + $result = $producer->produce($producerHandler); + + // Assertions + $this->assertNull($result); } public function testItShouldThrowJsonExceptionWhenPassingMalFormattedArray(): void @@ -147,7 +149,7 @@ public function testItShouldThrowJsonExceptionWhenPassingMalFormattedArray(): vo $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $producerHandler = new class ($record, $topic) extends AbstractHandler { + $producerHandler = new class($record, $topic) extends AbstractProducer { }; // Expectations @@ -223,7 +225,7 @@ public function testShouldBuildDispatcher(): void $producerTopic = m::mock(ProducerTopic::class); $configManager = m::mock(ProducerConfigManager::class); - $producerHandler = new class ($record, $topic) extends AbstractHandler { + $producerHandler = new class($record, $topic) extends AbstractProducer { }; // Expectations @@ -298,7 +300,7 @@ public function testShouldBuildDispatcherWithConfigOptions(): void $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); $broker = new Broker($connections, new None()); $configOptions = new ProducerConfigOptions($topicId, $broker); - $producerHandler = new class ($record, $configOptions) extends AbstractProducer { + $producerHandler = new class($record, $configOptions) extends AbstractProducer { }; // Expectations From 56f721bfc6bd5ae4005742d7f5b55120ea260aff Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 9 Mar 2022 09:45:27 -0300 Subject: [PATCH 16/75] chore: debug config options --- src/Connectors/Consumer/Config.php | 19 ++++-- src/ConsumerConfigManager.php | 7 +-- tests/Unit/AbstractConfigManagerTest.php | 75 ---------------------- tests/Unit/ConsumerConfigManagerTest.php | 79 ------------------------ 4 files changed, 16 insertions(+), 164 deletions(-) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index d14770fb..d2c97dd3 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -2,12 +2,14 @@ namespace Metamorphosis\Connectors\Consumer; +use InvalidArgumentException; use Metamorphosis\AbstractConfigManager; use Metamorphosis\Connectors\AbstractConfig; use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Exceptions\ConfigurationException; use Metamorphosis\TopicHandler\ConfigOptions\Consumer; use Metamorphosis\TopicHandler\ConfigOptions\Factories\ConsumerFactory; +use Metamorphosis\TopicHandler\Consumer\AbstractHandler; /** * This class is responsible for handling all configuration made on the @@ -41,12 +43,21 @@ class Config extends AbstractConfig 'middlewares' => 'array', ]; - public function makeWithConfigOptions(string $handlerClass, ?int $times = null): AbstractConfigManager + /** + * @param string $handlerClass + * @param int|null $times + * @return Consumer + */ + public function makeWithConfigOptions(string $handlerClass, ?int $times = null): ?Consumer { - $configManager = app(ConsumerConfigManager::class); - $configManager->set(['handler' => $handlerClass], ['times' => $times]); + /** @var AbstractHandler */ + $handler = app($handlerClass); + $configOptions = $handler->getConfigOptions(); + if(is_null($configOptions)){ + throw new InvalidArgumentException('Handler class cannot be null'); + } - return $configManager; + return $configOptions; } public function make(array $options, array $arguments): Consumer diff --git a/src/ConsumerConfigManager.php b/src/ConsumerConfigManager.php index 36d31c40..88207c97 100644 --- a/src/ConsumerConfigManager.php +++ b/src/ConsumerConfigManager.php @@ -22,12 +22,7 @@ public function set(array $config, ?array $commandConfig = null): void $this->remove('middlewares'); foreach ($middlewares as $middleware) { - $this->middlewares[] = is_string($middleware) - ? app( - $middleware, - ['configManager' => $this] - ) - : $middleware; + $this->middlewares[] = is_string($middleware) ? app($middleware) : $middleware; } if (!$consumerHandler) { diff --git a/tests/Unit/AbstractConfigManagerTest.php b/tests/Unit/AbstractConfigManagerTest.php index 7cf86812..e69de29b 100644 --- a/tests/Unit/AbstractConfigManagerTest.php +++ b/tests/Unit/AbstractConfigManagerTest.php @@ -1,75 +0,0 @@ -instance( - AbstractHandler::class, - m::mock(AbstractHandler::class) - ); - $config = [ - 'middlewares' => [], - 'handler' => AbstractHandler::class, - 'broker' => [ - 'default' => [ - 'connections' => 'kafka:9092', - ], - ], - 'topic_id' => 'kafka-test', - ]; - $broker = new Broker('kafka:9092', new None()); - $configOptions = new ConsumerConfigOptions( - 'kafka-override', - $broker, - '\App\Kafka\Consumers\ConsumerExample', - null, - null, - 'default', - null, - [MiddlewareDummy::class], - 200, - false, - true - ); - - $expected = [ - 'topic_id' => 'kafka-override', - 'connections' => 'kafka:9092', - 'auth' => null, - 'timeout' => 200, - 'handler' => '\App\Kafka\Consumers\ConsumerExample', - 'partition' => -1, - 'offset' => null, - 'consumer_group' => 'default', - 'auto_commit' => false, - 'commit_async' => true, - 'offset_reset' => 'smallest', - ]; - - $configManager = new ConsumerConfigManager(); - - // Expectations - $handler->expects() - ->getConfigOptions() - ->andReturn($configOptions); - - // Actions - $configManager->set($config); - - // Expectations - $this->assertEquals($expected, $configManager->get()); - } -} diff --git a/tests/Unit/ConsumerConfigManagerTest.php b/tests/Unit/ConsumerConfigManagerTest.php index 347aea6c..e69de29b 100644 --- a/tests/Unit/ConsumerConfigManagerTest.php +++ b/tests/Unit/ConsumerConfigManagerTest.php @@ -1,79 +0,0 @@ -instance( - AbstractHandler::class, - m::mock(AbstractHandler::class) - ); - $config = [ - 'middlewares' => [], - 'handler' => AbstractHandler::class, - 'broker' => [ - 'default' => [ - 'connections' => 'kafka:9092', - ], - ], - 'topic_id' => 'kafka-test', - ]; - $broker = new Broker('kafka:9092', new None()); - $configOptions = new ConsumerConfigOptions( - 'kafka-override', - $broker, - '\App\Kafka\Consumers\ConsumerExample', - null, - null, - 'default', - null, - [MiddlewareDummy::class], - 200, - false - ); - - $expected = [ - 'topic_id' => 'kafka-override', - 'connections' => 'kafka:9092', - 'auth' => null, - 'timeout' => 1000, - 'handler' => '\App\Kafka\Consumers\ConsumerExample', - 'partition' => -1, - 'offset' => null, - 'consumer_group' => 'default', - 'auto_commit' => false, - 'commit_async' => true, - 'offset_reset' => 'smallest', - 'times' => 2, - ]; - - $configManager = new ConsumerConfigManager(); - - $commandConfig = [ - 'timeout' => 1000, - 'times' => 2, - ]; - - // Expectations - $handler->expects() - ->getConfigOptions() - ->andReturn($configOptions); - - // Actions - $configManager->set($config, $commandConfig); - - // Expectations - $this->assertEquals($expected, $configManager->get()); - } -} From e90d589d05e8a4a4888c57c1b72e7cf59a4f1525 Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 10 Mar 2022 17:23:57 -0300 Subject: [PATCH 17/75] chore: create interfaces for classes --- src/Avro/CachedSchemaRegistryClient.php | 4 ++-- src/Avro/Client.php | 2 +- src/Avro/Serializer/Encoders/SchemaId.php | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Avro/CachedSchemaRegistryClient.php b/src/Avro/CachedSchemaRegistryClient.php index c91e643c..97706cd5 100644 --- a/src/Avro/CachedSchemaRegistryClient.php +++ b/src/Avro/CachedSchemaRegistryClient.php @@ -5,7 +5,7 @@ use AvroSchemaParseException; use RuntimeException; -class CachedSchemaRegistryClient +class CachedSchemaRegistryClient implements CachedSchemaRegistryClientInterface { private Client $client; @@ -20,7 +20,7 @@ class CachedSchemaRegistryClient */ private array $subjectVersionToSchema = []; - public function __construct(Client $client) + public function __construct(AvroClientInterface $client) { $this->client = $client; } diff --git a/src/Avro/Client.php b/src/Avro/Client.php index e0b714ac..02516b70 100644 --- a/src/Avro/Client.php +++ b/src/Avro/Client.php @@ -5,7 +5,7 @@ use GuzzleHttp\Client as GuzzleHttp; use Psr\Http\Message\ResponseInterface; -class Client +class Client implements AvroClientInterface { private GuzzleHttp $client; diff --git a/src/Avro/Serializer/Encoders/SchemaId.php b/src/Avro/Serializer/Encoders/SchemaId.php index ea428472..fd796333 100644 --- a/src/Avro/Serializer/Encoders/SchemaId.php +++ b/src/Avro/Serializer/Encoders/SchemaId.php @@ -6,6 +6,7 @@ use AvroIODatumWriter; use AvroStringIO; use Metamorphosis\Avro\CachedSchemaRegistryClient; +use Metamorphosis\Avro\CachedSchemaRegistryClientInterface; use Metamorphosis\Avro\Schema; use Metamorphosis\Avro\Serializer\SchemaFormats; @@ -13,7 +14,7 @@ class SchemaId implements EncoderInterface { private CachedSchemaRegistryClient $registry; - public function __construct(CachedSchemaRegistryClient $registry) + public function __construct(CachedSchemaRegistryClientInterface $registry) { $this->registry = $registry; } @@ -41,4 +42,9 @@ public function encode(Schema $schema, $message): string return $io->string(); } + + public function getRegistry() + { + return $this->registry; + } } From 5922eeee7e7abb4f3b59c7e9a09cfa8ce1b366ca Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 10 Mar 2022 17:25:28 -0300 Subject: [PATCH 18/75] chore: update calls from configManager to configOptions --- src/Middlewares/AvroSchemaMixedEncoder.php | 29 ++++++++++------------ 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/Middlewares/AvroSchemaMixedEncoder.php b/src/Middlewares/AvroSchemaMixedEncoder.php index 4df0beb7..11534359 100644 --- a/src/Middlewares/AvroSchemaMixedEncoder.php +++ b/src/Middlewares/AvroSchemaMixedEncoder.php @@ -3,12 +3,12 @@ namespace Metamorphosis\Middlewares; use Closure; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Avro\CachedSchemaRegistryClient; use Metamorphosis\Avro\ClientFactory; use Metamorphosis\Avro\Serializer\Encoders\SchemaId; use Metamorphosis\Exceptions\ConfigurationException; use Metamorphosis\Record\RecordInterface; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptionsProducer; /** * Fetches a schema for a topic by subject and version (currently only 'latest') @@ -21,30 +21,27 @@ class AvroSchemaMixedEncoder implements MiddlewareInterface private CachedSchemaRegistryClient $schemaRegistry; - private AbstractConfigManager $configManager; + /** + * @var ConfigOptionsProducer + */ + private $configOptionsProducer; - public function __construct(SchemaId $schemaIdEncoder, ClientFactory $factory, AbstractConfigManager $configManager) + public function __construct(SchemaId $schemaIdEncoder, ClientFactory $factory, ConfigOptionsProducer $configOptionsProducer) { - if (!$configManager->get('url')) { - throw new ConfigurationException( - "Avro schema url not found, it's required to use AvroSchemaEncoder Middleware" - ); + if (!$configOptionsProducer->getAvroSchema()->getUrl()) { + throw new ConfigurationException("Avro schema url not found, it's required to use AvroSchemaEncoder Middleware"); } - $schemaRegistry = $factory->make($configManager); +// $schemaRegistry = $factory->make($configOptionsProducer->getAvroSchema()); $this->schemaIdEncoder = $schemaIdEncoder; - $this->schemaRegistry = $schemaRegistry; - $this->configManager = $configManager; + $this->schemaRegistry = $schemaIdEncoder->getRegistry(); + $this->configOptionsProducer = $configOptionsProducer; } public function process(RecordInterface $record, Closure $next) { - $topic = $this->configManager->get('topic_id'); - $schema = $this->schemaRegistry->getBySubjectAndVersion( - "{$topic}-value", - 'latest' - ); - + $topic = $this->configOptionsProducer->getTopicId(); + $schema = $this->schemaRegistry->getBySubjectAndVersion("{$topic}-value", 'latest'); $arrayPayload = json_decode($record->getPayload(), true); $encodedPayload = $this->schemaIdEncoder->encode( $schema, From 65efb9808c9307d01eba2961a21e7ac717385da1 Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 10 Mar 2022 17:26:51 -0300 Subject: [PATCH 19/75] chore: add interfaces --- src/Avro/AvroClientInterface.php | 6 ++++++ src/Avro/CachedSchemaRegistryClientInterface.php | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 src/Avro/AvroClientInterface.php create mode 100644 src/Avro/CachedSchemaRegistryClientInterface.php diff --git a/src/Avro/AvroClientInterface.php b/src/Avro/AvroClientInterface.php new file mode 100644 index 00000000..d7617023 --- /dev/null +++ b/src/Avro/AvroClientInterface.php @@ -0,0 +1,6 @@ + Date: Thu, 10 Mar 2022 17:30:37 -0300 Subject: [PATCH 20/75] chore: add AvroSchemaMixedEncoderTest --- .../AvroSchemaMixedEncoderTest.php | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php diff --git a/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php b/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php new file mode 100644 index 00000000..9412bd4b --- /dev/null +++ b/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php @@ -0,0 +1,69 @@ +getSchemaTest(); + $configOptionsProducer = $this->createProducer(); + + $record = new ProducerRecord($schemaTest, 'kafka-test'); + $cachedSchemaRegistryClient = m::mock(CachedSchemaRegistryClient::class); + + $schema = (new Schema())->parse($schemaTest, '123'); + $clientFactory = new ClientFactory(); + $schemaIdEncoder = m::mock(SchemaId::class, [$cachedSchemaRegistryClient])->makePartial(); + + $avroSchemaMixedEncoder = new AvroSchemaMixedEncoder($schemaIdEncoder, $clientFactory, $configOptionsProducer); + + //expect + $cachedSchemaRegistryClient->shouldReceive('getBySubjectAndVersion')->andReturn($schema); + $schemaIdEncoder->shouldReceive('encode')->andReturn('string'); + + //act + $avroSchemaMixedEncoder->process($record, $closure); + + //assert + $this->assertInstanceOf(AvroSchemaMixedEncoder::class, $avroSchemaMixedEncoder); + } + + private function createProducer() + { + $brokerOptions = new Broker('kafka:9092', new None()); + return new ProducerConfigOptions( + 'kafka-test', + $brokerOptions, + null, + new AvroSchema('http://url.teste', []), + [], + 20000, + false, + true, + 10, + 500 + ); + } + + private function getSchemaTest(): string + { + return file_get_contents(__DIR__.'/../fixtures/schemas/sales_price.avsc'); + } +} From b91b3873226ee6ebc08caaea7cc697916b4c3240 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 21 Mar 2022 15:25:33 -0300 Subject: [PATCH 21/75] chore: remove inutilized interfaces --- src/Avro/CachedSchemaRegistryClient.php | 4 ++-- src/Avro/Client.php | 2 +- src/Avro/Serializer/Encoders/SchemaId.php | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Avro/CachedSchemaRegistryClient.php b/src/Avro/CachedSchemaRegistryClient.php index 97706cd5..c91e643c 100644 --- a/src/Avro/CachedSchemaRegistryClient.php +++ b/src/Avro/CachedSchemaRegistryClient.php @@ -5,7 +5,7 @@ use AvroSchemaParseException; use RuntimeException; -class CachedSchemaRegistryClient implements CachedSchemaRegistryClientInterface +class CachedSchemaRegistryClient { private Client $client; @@ -20,7 +20,7 @@ class CachedSchemaRegistryClient implements CachedSchemaRegistryClientInterface */ private array $subjectVersionToSchema = []; - public function __construct(AvroClientInterface $client) + public function __construct(Client $client) { $this->client = $client; } diff --git a/src/Avro/Client.php b/src/Avro/Client.php index 02516b70..e0b714ac 100644 --- a/src/Avro/Client.php +++ b/src/Avro/Client.php @@ -5,7 +5,7 @@ use GuzzleHttp\Client as GuzzleHttp; use Psr\Http\Message\ResponseInterface; -class Client implements AvroClientInterface +class Client { private GuzzleHttp $client; diff --git a/src/Avro/Serializer/Encoders/SchemaId.php b/src/Avro/Serializer/Encoders/SchemaId.php index fd796333..75d08216 100644 --- a/src/Avro/Serializer/Encoders/SchemaId.php +++ b/src/Avro/Serializer/Encoders/SchemaId.php @@ -6,7 +6,6 @@ use AvroIODatumWriter; use AvroStringIO; use Metamorphosis\Avro\CachedSchemaRegistryClient; -use Metamorphosis\Avro\CachedSchemaRegistryClientInterface; use Metamorphosis\Avro\Schema; use Metamorphosis\Avro\Serializer\SchemaFormats; @@ -14,7 +13,7 @@ class SchemaId implements EncoderInterface { private CachedSchemaRegistryClient $registry; - public function __construct(CachedSchemaRegistryClientInterface $registry) + public function __construct(CachedSchemaRegistryClient $registry) { $this->registry = $registry; } From 8ac1a92efd305b501e725cc4d241e109b97c5266 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 21 Mar 2022 15:37:01 -0300 Subject: [PATCH 22/75] chore: add method to get consumerGroupId --- src/Connectors/Consumer/Config.php | 54 +++++++++++++----------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index d2c97dd3..aace08a9 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -64,22 +64,11 @@ public function make(array $options, array $arguments): Consumer { $configName = $options['config_name'] ?? 'kafka'; $topicConfig = $this->getTopicConfig($configName, $arguments['topic']); - $consumerConfig = $this->getConsumerConfig( - $topicConfig, - $arguments['consumer_group'] - ); - $brokerConfig = $this->getBrokerConfig( - $configName, - $topicConfig['broker'] - ); - $schemaConfig = $this->getSchemaConfig( - $configName, - $arguments['topic'] - ); - $override = array_merge( - $this->filterValues($options), - $this->filterValues($arguments) - ); + $consumerGroupId = $this->getConsumerGroup($topicConfig, $arguments['consumer_group']); + $consumerConfig = $this->getConsumerConfig($topicConfig, $arguments, $consumerGroupId); + $brokerConfig = $this->getBrokerConfig($configName, $topicConfig['broker']); + $schemaConfig = $this->getSchemaConfig($configName, $arguments['topic']); + $override = array_merge($this->filterValues($options), $this->filterValues($arguments)); $config = array_merge( $topicConfig, $brokerConfig, @@ -89,6 +78,9 @@ public function make(array $options, array $arguments): Consumer $this->validate(array_merge($config, $override)); + $topicConfig['consumer']['consumer_groups'][$consumerConfig['consumer_group']]['partition'] = $consumerConfig['partition']; + $topicConfig['consumer_group'] = $consumerGroupId; + return ConsumerFactory::make($brokerConfig, $topicConfig, $schemaConfig); } @@ -110,31 +102,31 @@ private function getTopicConfig(string $configName, string $topicId): array return $topicConfig; } - private function getConsumerConfig(array $topicConfig, ?string $consumerGroupId = null): array + private function getConsumerConfig(array $topicConfig, array $arguments, string $consumerGroupId): array { - if ( - !$consumerGroupId && 1 === count( - $topicConfig['consumer']['consumer_groups'] - ) - ) { - $consumerGroupId = current( - array_keys($topicConfig['consumer']['consumer_groups']) - ); + $consumerConfig = $topicConfig['consumer']['consumer_groups'][$consumerGroupId] ?? null; + if (!$consumerConfig) { + throw new ConfigurationException("Consumer group '{$consumerGroupId}' not found"); } - $consumerGroupId = $consumerGroupId ?? 'default'; - $consumerConfig = $topicConfig['consumer']['consumer_groups'][$consumerGroupId] ?? null; $consumerConfig['consumer_group'] = $consumerGroupId; - if (!$consumerConfig) { - throw new ConfigurationException( - "Consumer group '{$consumerGroupId}' not found" - ); + if(isset($arguments['partition'])){ + $consumerConfig['partition'] = $arguments['partition']; } return $consumerConfig; } + private function getConsumerGroup(array $topicConfig, ?string $consumerGroupId): string + { + if (!$consumerGroupId && 1 === count($topicConfig['consumer']['consumer_groups'])) { + $consumerGroupId = current(array_keys($topicConfig['consumer']['consumer_groups'])); + } + + return $consumerGroupId ?? 'default'; + } + private function getMiddlewares(string $configName, array $topicConfig): array { return array_merge( From e97bf42c0026885e034667ca10637ed4d2dc083d Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 21 Mar 2022 15:58:27 -0300 Subject: [PATCH 23/75] chore: replace configManager by configOptions --- src/Connectors/Consumer/Config.php | 17 +- src/Connectors/Consumer/Factory.php | 12 +- src/Connectors/Producer/Connector.php | 6 +- src/Consumers/LowLevel.php | 8 +- src/Middlewares/AvroSchemaDecoder.php | 8 +- src/Middlewares/AvroSchemaMixedEncoder.php | 18 +- src/Producer.php | 23 +- src/Producer/Poll.php | 14 +- .../Factories/ConsumerFactory.php | 14 +- tests/Integration/ConsumerTest.php | 2 +- tests/Integration/ProducerTest.php | 31 ++- tests/Unit/Connectors/Consumer/ConfigTest.php | 8 +- .../Unit/Connectors/Consumer/FactoryTest.php | 75 +++--- .../Connectors/Consumer/HighLevelTest.php | 27 +- .../Unit/Connectors/Consumer/LowLevelTest.php | 28 ++- .../Connectors/Producer/ConnectorTest.php | 47 ++-- tests/Unit/Consumers/LowLevelTest.php | 19 +- .../Middlewares/AvroSchemaDecoderTest.php | 70 ++++++ .../AvroSchemaMixedEncoderTest.php | 97 ++++--- tests/Unit/Producer/PollTest.php | 69 +++-- tests/Unit/ProducerTest.php | 238 +++++------------- .../Factories/ConsumerFactoryTest.php | 1 + 22 files changed, 430 insertions(+), 402 deletions(-) create mode 100644 tests/Unit/Middlewares/AvroSchemaDecoderTest.php diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index aace08a9..4db8f76a 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -3,13 +3,10 @@ namespace Metamorphosis\Connectors\Consumer; use InvalidArgumentException; -use Metamorphosis\AbstractConfigManager; use Metamorphosis\Connectors\AbstractConfig; -use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Exceptions\ConfigurationException; use Metamorphosis\TopicHandler\ConfigOptions\Consumer; use Metamorphosis\TopicHandler\ConfigOptions\Factories\ConsumerFactory; -use Metamorphosis\TopicHandler\Consumer\AbstractHandler; /** * This class is responsible for handling all configuration made on the @@ -43,17 +40,11 @@ class Config extends AbstractConfig 'middlewares' => 'array', ]; - /** - * @param string $handlerClass - * @param int|null $times - * @return Consumer - */ public function makeWithConfigOptions(string $handlerClass, ?int $times = null): ?Consumer { - /** @var AbstractHandler */ $handler = app($handlerClass); $configOptions = $handler->getConfigOptions(); - if(is_null($configOptions)){ + if (is_null($configOptions)) { throw new InvalidArgumentException('Handler class cannot be null'); } @@ -77,8 +68,10 @@ public function make(array $options, array $arguments): Consumer ); $this->validate(array_merge($config, $override)); + if (isset($topicConfig['consumer']['consumer_groups'][$consumerConfig['consumer_group']]['partition'])) { + $topicConfig['consumer']['consumer_groups'][$consumerConfig['consumer_group']]['partition'] = $consumerConfig['partition']; + } - $topicConfig['consumer']['consumer_groups'][$consumerConfig['consumer_group']]['partition'] = $consumerConfig['partition']; $topicConfig['consumer_group'] = $consumerGroupId; return ConsumerFactory::make($brokerConfig, $topicConfig, $schemaConfig); @@ -111,7 +104,7 @@ private function getConsumerConfig(array $topicConfig, array $arguments, string $consumerConfig['consumer_group'] = $consumerGroupId; - if(isset($arguments['partition'])){ + if (isset($arguments['partition'])) { $consumerConfig['partition'] = $arguments['partition']; } diff --git a/src/Connectors/Consumer/Factory.php b/src/Connectors/Consumer/Factory.php index 893e9030..6a7c61aa 100644 --- a/src/Connectors/Consumer/Factory.php +++ b/src/Connectors/Consumer/Factory.php @@ -4,16 +4,20 @@ use Metamorphosis\Consumers\ConsumerInterface; use Metamorphosis\Middlewares\Handler\Dispatcher; -use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; /** * This factory will determine what kind of connector will be used. * Basically, if the user pass --partition and --offset as argument * means that we will use the low level approach. */ + +/** + * TODO Rename this class to ConsumerFactory, it will improve semantics + */ class Factory { - public static function make(ConfigOptions $configOptions): Manager + public static function make(ConsumerConfigOptions $configOptions): Manager { $autoCommit = $configOptions->isAutoCommit(); $commitAsync = $configOptions->isCommitASync(); @@ -26,14 +30,14 @@ public static function make(ConfigOptions $configOptions): Manager return new Manager($consumer, $handler, $dispatcher, $autoCommit, $commitAsync); } - protected static function requiresPartition(ConfigOptions $configOptions): bool + protected static function requiresPartition(ConsumerConfigOptions $configOptions): bool { $partition = $configOptions->getPartition(); return !is_null($partition) && $partition >= 0; } - public static function getConsumer(bool $autoCommit, ConfigOptions $configOptions): ConsumerInterface + public static function getConsumer(bool $autoCommit, ConsumerConfigOptions $configOptions): ConsumerInterface { if (self::requiresPartition($configOptions)) { return app(LowLevel::class)->getConsumer($autoCommit, $configOptions); diff --git a/src/Connectors/Producer/Connector.php b/src/Connectors/Producer/Connector.php index 68eafb07..1109a598 100644 --- a/src/Connectors/Producer/Connector.php +++ b/src/Connectors/Producer/Connector.php @@ -3,7 +3,7 @@ namespace Metamorphosis\Connectors\Producer; use Metamorphosis\Authentication\Factory; -use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use Metamorphosis\TopicHandler\Producer\HandleableResponseInterface; use Metamorphosis\TopicHandler\Producer\HandlerInterface; use RdKafka\Conf; @@ -12,7 +12,7 @@ class Connector { - public function getProducerTopic(HandlerInterface $handler, ConfigOptions $configOptions): KafkaProducer + public function getProducerTopic(HandlerInterface $handler, ProducerConfigOptions $producerConfigOptions): KafkaProducer { $conf = resolve(Conf::class); @@ -29,7 +29,7 @@ function ($kafka, Message $message) use ($handler) { ); } - $broker = $configOptions->getBroker(); + $broker = $producerConfigOptions->getBroker(); $conf->set('metadata.broker.list', $broker->getConnections()); Factory::authenticate($conf, $broker->getAuth()); diff --git a/src/Consumers/LowLevel.php b/src/Consumers/LowLevel.php index e4a31ea0..e9fee56c 100644 --- a/src/Consumers/LowLevel.php +++ b/src/Consumers/LowLevel.php @@ -2,7 +2,7 @@ namespace Metamorphosis\Consumers; -use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; use RdKafka\ConsumerTopic; use RdKafka\Message; @@ -14,12 +14,12 @@ class LowLevel implements ConsumerInterface private ?int $timeout; - public function __construct(ConsumerTopic $consumer, ConfigOptions $configOptions) + public function __construct(ConsumerTopic $consumer, ConsumerConfigOptions $consumerConfigOptions) { $this->consumer = $consumer; - $this->partition = $configOptions->getPartition(); - $this->timeout = $configOptions->getTimeout(); + $this->partition = $consumerConfigOptions->getPartition(); + $this->timeout = $consumerConfigOptions->getTimeout(); } public function consume(): ?Message diff --git a/src/Middlewares/AvroSchemaDecoder.php b/src/Middlewares/AvroSchemaDecoder.php index 8d185fdd..1aeffcff 100644 --- a/src/Middlewares/AvroSchemaDecoder.php +++ b/src/Middlewares/AvroSchemaDecoder.php @@ -8,6 +8,7 @@ use Metamorphosis\Exceptions\ConfigurationException; use Metamorphosis\Record\RecordInterface; use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; class AvroSchemaDecoder implements MiddlewareInterface { @@ -18,14 +19,13 @@ class AvroSchemaDecoder implements MiddlewareInterface */ private $avroSchema; - public function __construct(AvroSchema $avroSchema, ClientFactory $factory) + public function __construct(ClientFactory $factory, ConsumerConfigOptions $consumerConfigOptions) { - $this->avroSchema = $avroSchema; - if (!$this->avroSchema->getUrl()) { + if (!$consumerConfigOptions->getAvroSchema()->getUrl()) { throw new ConfigurationException("Avro schema url not found, it's required to use AvroSchemaDecoder Middleware"); } - $this->decoder = new MessageDecoder($factory->make($avroSchema)); + $this->decoder = new MessageDecoder($factory->make($consumerConfigOptions->getAvroSchema())); } public function process(RecordInterface $record, Closure $next) diff --git a/src/Middlewares/AvroSchemaMixedEncoder.php b/src/Middlewares/AvroSchemaMixedEncoder.php index 11534359..6969a80e 100644 --- a/src/Middlewares/AvroSchemaMixedEncoder.php +++ b/src/Middlewares/AvroSchemaMixedEncoder.php @@ -8,7 +8,7 @@ use Metamorphosis\Avro\Serializer\Encoders\SchemaId; use Metamorphosis\Exceptions\ConfigurationException; use Metamorphosis\Record\RecordInterface; -use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptionsProducer; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; /** * Fetches a schema for a topic by subject and version (currently only 'latest') @@ -22,25 +22,25 @@ class AvroSchemaMixedEncoder implements MiddlewareInterface private CachedSchemaRegistryClient $schemaRegistry; /** - * @var ConfigOptionsProducer + * @var ProducerConfigOptions */ - private $configOptionsProducer; + private $producerConfigOptions; - public function __construct(SchemaId $schemaIdEncoder, ClientFactory $factory, ConfigOptionsProducer $configOptionsProducer) + public function __construct(SchemaId $schemaIdEncoder, ClientFactory $factory, ProducerConfigOptions $producerConfigOptions) { - if (!$configOptionsProducer->getAvroSchema()->getUrl()) { + if (!$producerConfigOptions->getAvroSchema()->getUrl()) { throw new ConfigurationException("Avro schema url not found, it's required to use AvroSchemaEncoder Middleware"); } -// $schemaRegistry = $factory->make($configOptionsProducer->getAvroSchema()); + $schemaRegistry = $factory->make($producerConfigOptions->getAvroSchema()); $this->schemaIdEncoder = $schemaIdEncoder; - $this->schemaRegistry = $schemaIdEncoder->getRegistry(); - $this->configOptionsProducer = $configOptionsProducer; + $this->schemaRegistry = $schemaRegistry; + $this->producerConfigOptions = $producerConfigOptions; } public function process(RecordInterface $record, Closure $next) { - $topic = $this->configOptionsProducer->getTopicId(); + $topic = $this->producerConfigOptions->getTopicId(); $schema = $this->schemaRegistry->getBySubjectAndVersion("{$topic}-value", 'latest'); $arrayPayload = json_decode($record->getPayload(), true); $encodedPayload = $this->schemaIdEncoder->encode( diff --git a/src/Producer.php b/src/Producer.php index e1187cf0..ee277fdf 100644 --- a/src/Producer.php +++ b/src/Producer.php @@ -7,7 +7,7 @@ use Metamorphosis\Middlewares\Handler\Dispatcher; use Metamorphosis\Middlewares\Handler\Producer as ProducerMiddleware; use Metamorphosis\Producer\Poll; -use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use Metamorphosis\TopicHandler\Producer\AbstractProducer; use Metamorphosis\TopicHandler\Producer\HandlerInterface; @@ -32,21 +32,26 @@ public function produce(HandlerInterface $producerHandler): void public function build(HandlerInterface $producerHandler): Dispatcher { - $configOptions = $producerHandler->getConfigOptions(); + $producerConfigOptions = $producerHandler->getConfigOptions(); - $middlewares = $configOptions->getMiddlewares(); - $middlewares[] = $this->getProducerMiddleware($producerHandler, $configOptions); + $middlewares = $producerConfigOptions->getMiddlewares(); + + foreach ($middlewares as &$middleware) { + $middleware = is_string($middleware) ? app($middleware, ['producerConfigOptions' => $producerConfigOptions]) : $middleware; + } + + $middlewares[] = $this->getProducerMiddleware($producerHandler, $producerConfigOptions); return new Dispatcher($middlewares); } - public function getProducerMiddleware(HandlerInterface $producerHandler, ConfigOptions $configOptions): ProducerMiddleware + public function getProducerMiddleware(HandlerInterface $producerHandler, ProducerConfigOptions $producerConfigOptions): ProducerMiddleware { - $producer = $this->connector->getProducerTopic($producerHandler, $configOptions); + $producer = $this->connector->getProducerTopic($producerHandler, $producerConfigOptions); - $topic = $producer->newTopic($configOptions->getTopicId()); - $poll = app(Poll::class, ['producer' => $producer, 'configOptions' => $configOptions]); - $partition = $configOptions->getPartition(); + $topic = $producer->newTopic($producerConfigOptions->getTopicId()); + $poll = app(Poll::class, ['producer' => $producer, 'producerConfigOptions' => $producerConfigOptions]); + $partition = $producerConfigOptions->getPartition(); return app( ProducerMiddleware::class, diff --git a/src/Producer/Poll.php b/src/Producer/Poll.php index 4c3b9c81..c07508ec 100644 --- a/src/Producer/Poll.php +++ b/src/Producer/Poll.php @@ -2,7 +2,7 @@ namespace Metamorphosis\Producer; -use Metamorphosis\TopicHandler\ConfigOptions\Producer as ConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use RdKafka\Producer; use RuntimeException; @@ -24,13 +24,13 @@ class Poll private Producer $producer; - public function __construct(Producer $producer, ConfigOptions $configOptions) + public function __construct(Producer $producer, ProducerConfigOptions $producerConfigOptions) { - $this->isAsync = $configOptions->isAsync(); - $this->maxPollRecords = $configOptions->getMaxPollRecords(); - $this->requiredAcknowledgment = $configOptions->isRequiredAcknowledgment(); - $this->maxFlushAttempts = $configOptions->getFlushAttempts(); - $this->timeout = $configOptions->getTimeout(); + $this->isAsync = $producerConfigOptions->isAsync(); + $this->maxPollRecords = $producerConfigOptions->getMaxPollRecords(); + $this->requiredAcknowledgment = $producerConfigOptions->isRequiredAcknowledgment(); + $this->maxFlushAttempts = $producerConfigOptions->getFlushAttempts(); + $this->timeout = $producerConfigOptions->getTimeout(); $this->producer = $producer; } diff --git a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php index 103b882e..7bd58c93 100644 --- a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php +++ b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php @@ -22,20 +22,16 @@ public static function make( private static function getConsumerGroupConfig(array $topicData): array { $topicData['topicId'] = $topicData['topic_id']; + $topicData['consumerGroup'] = $topicData['consumer_group']; - $consumer = current($topicData['consumer']); - $topicData['consumerGroup'] = key($consumer); + $consumerGroup = $topicData['consumerGroup']; + $consumer = current($topicData['consumer'])[$consumerGroup]; - return array_merge( - $topicData, - self::convertConfigAttributes($consumer) - ); + return array_merge_recursive($topicData, self::convertConfigAttributes($consumer)); } - private static function convertConfigAttributes(array $topic): array + private static function convertConfigAttributes(array $consumerConfig): array { - $consumerConfig = current($topic); - if (isset($consumerConfig['auto_commit'])) { $consumerConfig['autoCommit'] = $consumerConfig['auto_commit']; } diff --git a/tests/Integration/ConsumerTest.php b/tests/Integration/ConsumerTest.php index 1d4397e8..7088e46b 100644 --- a/tests/Integration/ConsumerTest.php +++ b/tests/Integration/ConsumerTest.php @@ -51,7 +51,7 @@ public function testItShouldSetup(): void MessageProducerWithConfigOptions::class, [ 'record' => ['id' => 'MESSAGE_ID'], - 'configOptions' => $producerConfigOptions, + 'producer' => $producerConfigOptions, 'key' => 1, ] ); diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index 1689fe87..9780d74c 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -27,6 +27,7 @@ public function testShouldRunAProducerAndReceiveMessagesWithAHighLevelConsumer() { // Given That I $this->haveAConsumerHandlerConfigured(); + $this->haveAConsumerPartitionConfigured(); $this->haveSomeRandomMessagesProduced(); // I Expect That @@ -69,6 +70,11 @@ protected function haveAConsumerHandlerConfigured(): void ); } + protected function haveAConsumerPartitionConfigured(): void + { + config(['kafka.topics.default.consumer.consumer_groups.test-consumer-group.partition' => -1]); + } + protected function runTheConsumer(): void { $this->artisan( @@ -133,9 +139,9 @@ protected function runTheLowLevelConsumerSkippingTheFirstTwoMessagesAndLimitingT private function haveSomeRandomMessagesProduced(): void { $this->highLevelMessage = Str::random(10); - $configOptionsProducer = $this->createConfigOptionsProducer('kafka-test'); - //$producer = app(MessageProducer::class, ['record' => $this->highLevelMessage, 'configOptions'=> $configOptionsProducer]); - $producer = new MessageProducer($this->highLevelMessage, $configOptionsProducer, 'recordId123'); + $producerConfigOptions = $this->createProducerConfigOptions('kafka-test'); +// $producer = app(MessageProducer::class, ['record' => $this->highLevelMessage, 'producer'=> $producerConfigOptions]); + $producer = new MessageProducer($this->highLevelMessage, $producerConfigOptions, 'recordId123'); Metamorphosis::produce($producer); Metamorphosis::produce($producer); @@ -143,10 +149,8 @@ private function haveSomeRandomMessagesProduced(): void private function produceRecordMessage(string $record): string { - $configOptionsProducer = $this->createConfigOptionsProducer('low_level'); - $producer = new MessageProducer($record, $configOptionsProducer, 'recordId123'); - //$producer = app(MessageProducer::class, ['record'=>$record, 'configOptions' => $a]); - //$producer->topic = 'low_level'; + $producerConfigOptions = $this->createProducerConfigOptions('low_level'); + $producer = new MessageProducer($record, $producerConfigOptions, 'recordId123'); Metamorphosis::produce($producer); Metamorphosis::produce($producer); @@ -186,20 +190,15 @@ private function haveFourProducedMessages(): void $this->produceRecordMessage($this->secondLowLevelMessage); } - private function createConfigOptionsProducer(string $topicId = 'kafka-test'): ProducerConfigOptions + private function createProducerConfigOptions(string $topicId = 'kafka-test'): ProducerConfigOptions { - $brokerOptions = new Broker('kafka:9092', new None()); + $broker = new Broker('kafka:9092', new None()); return new ProducerConfigOptions( $topicId, - $brokerOptions, + $broker, null, null, - [], - 20000, - false, - true, - 10, - 500 + [] ); } } diff --git a/tests/Unit/Connectors/Consumer/ConfigTest.php b/tests/Unit/Connectors/Consumer/ConfigTest.php index 9e1c26f9..539b6ea0 100644 --- a/tests/Unit/Connectors/Consumer/ConfigTest.php +++ b/tests/Unit/Connectors/Consumer/ConfigTest.php @@ -84,10 +84,10 @@ public function testShouldValidateConsumerConfig(): void ]); // Actions - $configManager = $config->make($options, $arguments); + $configManager = $config->makeWithConfigOptions(ConsumerHandlerDummy::class); // Assertions - $this->assertArraySubset($expected, $configManager->get()); + $this->assertArraySubset($expected, $configManager->toArray()); } public function testShouldNotSetRuntimeConfigWhenOptionsIsInvalid(): void @@ -109,7 +109,7 @@ public function testShouldNotSetRuntimeConfigWhenOptionsIsInvalid(): void $configManager = $config->make($options, $arguments); // Assertions - $this->assertEmpty($configManager->get()); + $this->assertEmpty($configManager->toArray()); } public function testShouldNotSetRuntimeConfigWhenKafkaConfigIsInvalid(): void @@ -132,6 +132,6 @@ public function testShouldNotSetRuntimeConfigWhenKafkaConfigIsInvalid(): void $configManager = $config->make($options, $arguments); // Assertions - $this->assertEmpty($configManager->get()); + $this->assertEmpty($configManager->toArray()); } } diff --git a/tests/Unit/Connectors/Consumer/FactoryTest.php b/tests/Unit/Connectors/Consumer/FactoryTest.php index a90471d6..50a158f2 100644 --- a/tests/Unit/Connectors/Consumer/FactoryTest.php +++ b/tests/Unit/Connectors/Consumer/FactoryTest.php @@ -11,48 +11,6 @@ class FactoryTest extends LaravelTestCase { - public function testItMakesManagerWithLowLevelConsumer(): void - { - // Set - $config = new Config(); - $configManager = $config->make( - ['timeout' => 61], - ['topic' => 'topic_key', 'consumer_group' => 'with-partition'] - ); - $manager = Factory::make($configManager); - - // Assertions - $this->assertInstanceOf(LowLevel::class, $manager->getConsumer()); - } - - public function testItMakesManagerWithLowLevelConsumerWhenPartitionIsNotValid(): void - { - // Set - $config = new Config(); - $configManager = $config->make( - ['timeout' => 61], - ['topic' => 'topic_key', 'consumer_group' => 'with-partition', 'partition' => -1] - ); - $manager = Factory::make($configManager); - - // Assertions - $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); - } - - public function testItMakesHighLevelClass(): void - { - // Set - $config = new Config(); - $configManager = $config->make( - ['timeout' => 61], - ['topic' => 'topic_key', 'consumer_group' => 'without-partition'] - ); - $manager = Factory::make($configManager); - - // Assertions - $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); - } - protected function setUp(): void { parent::setUp(); @@ -88,4 +46,37 @@ protected function setUp(): void ], ]); } + + public function testItMakesManagerWithLowLevelConsumer(): void + { + // Set + $config = new Config(); + $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'with-partition']); + $manager = Factory::make($configConsumer); + + // Assertions + $this->assertInstanceOf(LowLevel::class, $manager->getConsumer()); + } + + public function testItMakesManagerWithLowLevelConsumerWhenPartitionIsNotValid(): void + { + // Set + $config = new Config(); + $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'with-partition', 'partition' => -1]); + $manager = Factory::make($configConsumer); + + // Assertions + $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); + } + + public function testItMakesHighLevelClass(): void + { + // Set + $config = new Config(); + $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'without-partition']); + $manager = Factory::make($configConsumer); + + // Assertions + $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); + } } diff --git a/tests/Unit/Connectors/Consumer/HighLevelTest.php b/tests/Unit/Connectors/Consumer/HighLevelTest.php index 681c7ce5..97ab8e91 100644 --- a/tests/Unit/Connectors/Consumer/HighLevelTest.php +++ b/tests/Unit/Connectors/Consumer/HighLevelTest.php @@ -3,8 +3,11 @@ namespace Tests\Unit\Connectors\Consumer; use Metamorphosis\Connectors\Consumer\HighLevel; -use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Consumers\HighLevel as HighLevelConsumer; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema as AvroSchemaConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Broker; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; use Tests\LaravelTestCase; class HighLevelTest extends LaravelTestCase @@ -12,20 +15,20 @@ class HighLevelTest extends LaravelTestCase public function testItShouldMakeConnectorSetup(): void { // Set - $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); - $configManager = new ConsumerConfigManager(); - $configManager->set([ - 'connections' => $connections, - 'consumer_group' => 'some-group', - 'topic_id' => 'some_topic', - 'offset_reset' => 'earliest', - 'timeout' => 1000, - 'max_poll_interval_ms' => 900000, - ]); $connector = new HighLevel(); + $brokerOptions = new Broker('kafka:9092', new None()); + $consumerConfigOptions = new ConsumerConfigOptions( + 'kafka-test', + $brokerOptions, + null, + 1, + 0, + 'some-group', + new AvroSchemaConfigOptions('http://url.teste') + ); // Actions - $result = $connector->getConsumer(false, $configManager); + $result = $connector->getConsumer(false, $consumerConfigOptions); // Assertions $this->assertInstanceOf(HighLevelConsumer::class, $result); diff --git a/tests/Unit/Connectors/Consumer/LowLevelTest.php b/tests/Unit/Connectors/Consumer/LowLevelTest.php index b3a081df..21c12291 100644 --- a/tests/Unit/Connectors/Consumer/LowLevelTest.php +++ b/tests/Unit/Connectors/Consumer/LowLevelTest.php @@ -3,8 +3,11 @@ namespace Tests\Unit\Connectors\Consumer; use Metamorphosis\Connectors\Consumer\LowLevel; -use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Consumers\LowLevel as LowLevelConsumer; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema as AvroSchemaConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Broker; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; use Tests\LaravelTestCase; class LowLevelTest extends LaravelTestCase @@ -12,21 +15,20 @@ class LowLevelTest extends LaravelTestCase public function testItShouldMakeConnectorSetup(): void { // Set - $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); - $configManager = new ConsumerConfigManager(); - $configManager->set([ - 'connections' => $connections, - 'consumer_group' => 'some-group', - 'topic' => 'some_topic', - 'offset_reset' => 'earliest', - 'max_poll_interval_ms' => 900000, - 'offset' => 0, - 'partition' => 1, - ]); $connector = new LowLevel(); + $brokerOptions = new Broker('kafka:9092', new None()); + $consumerConfigOptions = new ConsumerConfigOptions( + 'kafka-test', + $brokerOptions, + null, + 1, + 0, + 'some-group', + new AvroSchemaConfigOptions('http://url.teste') + ); // Actions - $result = $connector->getConsumer(true, $configManager); + $result = $connector->getConsumer(true, $consumerConfigOptions); // Assertions $this->assertInstanceOf(LowLevelConsumer::class, $result); diff --git a/tests/Unit/Connectors/Producer/ConnectorTest.php b/tests/Unit/Connectors/Producer/ConnectorTest.php index e0cb6123..f456dfb7 100644 --- a/tests/Unit/Connectors/Producer/ConnectorTest.php +++ b/tests/Unit/Connectors/Producer/ConnectorTest.php @@ -3,7 +3,8 @@ namespace Tests\Unit\Connectors\Producer; use Metamorphosis\Connectors\Producer\Connector; -use Metamorphosis\ProducerConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\Broker; use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use Metamorphosis\TopicHandler\Producer\AbstractProducer; use Metamorphosis\TopicHandler\Producer\HandleableResponseInterface; @@ -27,12 +28,12 @@ public function testItShouldMakeSetup(): void KafkaProducer::class, m::mock(KafkaProducer::class) ); - $configManager = m::mock(ProducerConfigManager::class); - $configOptions = m::mock(ProducerConfigOptions::class); + + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = m::mock(ProducerConfigOptions::class); $connector = new Connector(); - $handler = new class ('record', $configOptions) extends AbstractProducer implements HandleableResponseInterface { - /** @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter */ + $handler = new class('record', $producerConfigOptions) extends AbstractProducer implements HandleableResponseInterface { public function success(Message $message): void { } @@ -49,18 +50,14 @@ public function failed(Message $message): void ->withAnyArgs(); $conf->expects() - ->set('metadata.broker.list', 'kafka:9092'); - - $configManager->expects() - ->get('connections') - ->andReturn('kafka:9092'); + ->set('metadata.broker.list', 0); - $configManager->expects() - ->get('auth.type') - ->andReturn('none'); + $producerConfigOptions->expects() + ->getBroker() + ->andReturn($broker); // Actions - $result = $connector->getProducerTopic($handler, $configManager); + $result = $connector->getProducerTopic($handler, $producerConfigOptions); // Assertions $this->assertInstanceOf(KafkaProducer::class, $result); @@ -77,12 +74,12 @@ public function testItShouldMakeSetupWithoutHandleResponse(): void KafkaProducer::class, m::mock(KafkaProducer::class) ); - $configManager = m::mock(ProducerConfigManager::class); - $configOptions = m::mock(ProducerConfigOptions::class); + + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = m::mock(ProducerConfigOptions::class); $connector = new Connector(); - $handler = new class ('record', $configOptions) extends AbstractProducer implements HandlerInterface { - /** @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter */ + $handler = new class('record', $producerConfigOptions) extends AbstractProducer implements HandlerInterface { public function success(Message $message): void { } @@ -98,18 +95,14 @@ public function failed(Message $message): void ->never(); $conf->expects() - ->set('metadata.broker.list', 'kafka:9092'); - - $configManager->expects() - ->get('connections') - ->andReturn('kafka:9092'); + ->set('metadata.broker.list', 0); - $configManager->expects() - ->get('auth.type') - ->andReturn('none'); + $producerConfigOptions->expects() + ->getBroker() + ->andReturn($broker); // Actions - $result = $connector->getProducerTopic($handler, $configManager); + $result = $connector->getProducerTopic($handler, $producerConfigOptions); // Assertions $this->assertInstanceOf(KafkaProducer::class, $result); diff --git a/tests/Unit/Consumers/LowLevelTest.php b/tests/Unit/Consumers/LowLevelTest.php index 6b35f993..cc8bb988 100644 --- a/tests/Unit/Consumers/LowLevelTest.php +++ b/tests/Unit/Consumers/LowLevelTest.php @@ -4,6 +4,10 @@ use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Consumers\LowLevel; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema as AvroSchemaConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Broker; +use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; use Mockery as m; use RdKafka\ConsumerTopic; use RdKafka\Message; @@ -19,10 +23,23 @@ public function testItShouldConsume(): void $configManager = new ConsumerConfigManager(); $configManager->set(compact('timeout', 'partition')); + $brokerOptions = new Broker('kafka:9092', new None()); + $consumerConfigOptions = new ConsumerConfigOptions( + 'kafka-test', + $brokerOptions, + null, + $partition, + null, + '', + new AvroSchemaConfigOptions('http://url.teste'), + [], + $timeout + ); + $consumerTopic = m::mock(ConsumerTopic::class); $message = new Message(); - $lowLevelConsumer = new LowLevel($consumerTopic, $configManager); + $lowLevelConsumer = new LowLevel($consumerTopic, $consumerConfigOptions); // Expectations $consumerTopic->expects() diff --git a/tests/Unit/Middlewares/AvroSchemaDecoderTest.php b/tests/Unit/Middlewares/AvroSchemaDecoderTest.php new file mode 100644 index 00000000..6c8d31b0 --- /dev/null +++ b/tests/Unit/Middlewares/AvroSchemaDecoderTest.php @@ -0,0 +1,70 @@ +getAvroSchema(); + $avroSchema = new AvroSchema('string'); + $decoder = m::mock(Schema::class); + $clientFactory = m::mock(ClientFactory::class); + $cachedSchemaRegistryClient = m::mock(CachedSchemaRegistryClient::class); + $expected = 'my awesome message'; + + $message = new Message(); + $message->payload = "\x01\x00\x00\x00\fmy-topic-key\x00\x00\x00\x05\$my awesome message"; + $message->err = 0; + + $closure = Closure::fromCallable(function ($producerRecord) { + return $producerRecord; + }); + + $consumerRecord = new ConsumerRecord($message); + + // Expectations + $clientFactory->expects() + ->make($avroSchemaConfigOptions) + ->andReturn($cachedSchemaRegistryClient); + + $cachedSchemaRegistryClient->expects() + ->getBySubjectAndVersion('my-topic-key', 5) + ->andReturn($decoder); + + $decoder->expects() + ->getAvroSchema() + ->andReturn($avroSchema); + + $avroSchemaDecoder = new AvroSchemaDecoder($clientFactory, $consumerConfigOptions); + + $result = $avroSchemaDecoder->process($consumerRecord, $closure); + + $this->assertSame($expected, $result->getPayload()); + } +} diff --git a/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php b/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php index 9412bd4b..fcff2d6c 100644 --- a/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php +++ b/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php @@ -1,6 +1,8 @@ getSchemaFixture(); + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + 'kafka-test', + $broker, + null, + new AvroSchemaConfigOptions('subjects/kafka-test-value/versions/latest', []) + ); + $avroSchemaConfigOptions = $producerConfigOptions->getAvroSchema(); - $schemaTest = $this->getSchemaTest(); - $configOptionsProducer = $this->createProducer(); + $clientFactory = m::mock(ClientFactory::class); - $record = new ProducerRecord($schemaTest, 'kafka-test'); $cachedSchemaRegistryClient = m::mock(CachedSchemaRegistryClient::class); + $schemaIdEncoder = m::mock(SchemaId::class, [$cachedSchemaRegistryClient]); + + $schema = new Schema(); + $parsedSchema = $schema->parse($avroSchema, '123', 'kafka-test-value', 'latest'); + $record = $this->getRecord($parsedSchema->getAvroSchema()); + $producerRecord = new ProducerRecord($record, 'kafka-test'); + + $closure = Closure::fromCallable(function ($producerRecord) { + return $producerRecord; + }); + + $payload = json_decode($producerRecord->getPayload(), true); + $encodedMessage = 'binary_message'; - $schema = (new Schema())->parse($schemaTest, '123'); - $clientFactory = new ClientFactory(); - $schemaIdEncoder = m::mock(SchemaId::class, [$cachedSchemaRegistryClient])->makePartial(); + // Expectations + $clientFactory->expects() + ->make($avroSchemaConfigOptions) + ->andReturn($cachedSchemaRegistryClient); - $avroSchemaMixedEncoder = new AvroSchemaMixedEncoder($schemaIdEncoder, $clientFactory, $configOptionsProducer); + $cachedSchemaRegistryClient->expects() + ->getBySubjectAndVersion('kafka-test-value', 'latest') + ->andReturn($schema); - //expect - $cachedSchemaRegistryClient->shouldReceive('getBySubjectAndVersion')->andReturn($schema); - $schemaIdEncoder->shouldReceive('encode')->andReturn('string'); + $schemaIdEncoder->expects() + ->encode($schema, $payload) + ->andReturn($encodedMessage); - //act - $avroSchemaMixedEncoder->process($record, $closure); + // Actions + $avroSchemaMixedEncoder = new AvroSchemaMixedEncoder($schemaIdEncoder, $clientFactory, $producerConfigOptions); + $result = $avroSchemaMixedEncoder->process($producerRecord, $closure); - //assert - $this->assertInstanceOf(AvroSchemaMixedEncoder::class, $avroSchemaMixedEncoder); + // Assertions + $this->assertSame($record, $result->getOriginal()); + $this->assertSame($encodedMessage, $result->getPayload()); } - private function createProducer() + private function getRecord(AvroSchema $avroSchema): string { - $brokerOptions = new Broker('kafka:9092', new None()); - return new ProducerConfigOptions( - 'kafka-test', - $brokerOptions, - null, - new AvroSchema('http://url.teste', []), - [], - 20000, - false, - true, - 10, - 500 - ); + $defaultValues = [ + 'null' => null, + 'boolean' => true, + 'string' => 'abc', + 'int' => 1, + 'long' => 1.0, + 'float' => 1.0, + 'double' => 1.0, + 'array' => [], + ]; + + $result = []; + foreach ($avroSchema->fields() as $field) { + $result[$field->name()] = $defaultValues[$field->type->type]; + } + + return json_encode($result); } - private function getSchemaTest(): string + private function getSchemaFixture(): string { return file_get_contents(__DIR__.'/../fixtures/schemas/sales_price.avsc'); } diff --git a/tests/Unit/Producer/PollTest.php b/tests/Unit/Producer/PollTest.php index 8bda848d..3ef21c96 100644 --- a/tests/Unit/Producer/PollTest.php +++ b/tests/Unit/Producer/PollTest.php @@ -4,6 +4,10 @@ use Metamorphosis\Producer\Poll; use Metamorphosis\ProducerConfigManager; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema as AvroSchemaConfigOptions; +use Metamorphosis\TopicHandler\ConfigOptions\Broker; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use Mockery as m; use RdKafka\Producer as KafkaProducer; use RuntimeException; @@ -14,17 +18,21 @@ class PollTest extends LaravelTestCase public function testItShouldHandleMessageWithoutAcknowledgment(): void { // Set - $configManager = new ProducerConfigManager(); - $configManager->set([ - 'topic_id' => 'topic_name', - 'timeout' => 4000, - 'is_async' => true, - 'max_poll_records' => 500, - 'flush_attempts' => 10, - 'required_acknowledgment' => false, - ]); + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + 'topic_name', + $broker, + null, + new AvroSchemaConfigOptions('string', []), + [], + 4000, + true, + false, + 500, + 10 + ); $kafkaProducer = m::mock(KafkaProducer::class); - $poll = new Poll($kafkaProducer, $configManager); + $poll = new Poll($kafkaProducer, $producerConfigOptions); // Expectations $kafkaProducer->expects() @@ -51,8 +59,21 @@ public function testShouldThrowExceptionWhenFlushFailed(): void 'partition' => 0, ]); + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + 'topic_name', + $broker, + null, + new AvroSchemaConfigOptions('string', []), + [], + 100, + false, + true, + 500, + 10 + ); $kafkaProducer = m::mock(KafkaProducer::class); - $poll = new Poll($kafkaProducer, $configManager); + $poll = new Poll($kafkaProducer, $producerConfigOptions); // Expectations $kafkaProducer->expects() @@ -72,18 +93,22 @@ public function testShouldThrowExceptionWhenFlushFailed(): void public function testItShouldHandleResponseEveryTimeWhenAsyncModeIsTrue(): void { // Set - $configManager = new ProducerConfigManager(); - $configManager->set([ - 'topic_id' => 'topic_name', - 'timeout' => 4000, - 'is_async' => false, - 'max_poll_records' => 500, - 'flush_attempts' => 10, - 'required_acknowledgment' => true, - 'partition' => 0, - ]); + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + 'topic_name', + $broker, + null, + new AvroSchemaConfigOptions('string', []), + [], + 4000, + false, + true, + 10, + 500 + ); + $kafkaProducer = m::mock(KafkaProducer::class); - $poll = new Poll($kafkaProducer, $configManager); + $poll = new Poll($kafkaProducer, $producerConfigOptions); // Expectations $kafkaProducer->expects() diff --git a/tests/Unit/ProducerTest.php b/tests/Unit/ProducerTest.php index 31650aef..02808390 100644 --- a/tests/Unit/ProducerTest.php +++ b/tests/Unit/ProducerTest.php @@ -8,8 +8,8 @@ use Metamorphosis\Middlewares\Handler\Dispatcher; use Metamorphosis\Middlewares\Handler\Producer as ProducerMiddleware; use Metamorphosis\Producer; -use Metamorphosis\ProducerConfigManager; use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema as AvroSchemaConfigOptions; use Metamorphosis\TopicHandler\ConfigOptions\Broker; use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use Metamorphosis\TopicHandler\Producer\AbstractProducer; @@ -31,38 +31,22 @@ public function testItShouldProduceRecordAsArrayThroughMiddlewareQueue(): void ); $config = m::mock(Config::class); $connector = m::mock(Connector::class); - $configManager = m::mock(ProducerConfigManager::class)->makePartial(); $producer = new Producer($config, $connector); $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $producerHandler = new class($record, $topic) extends AbstractProducer { + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + $topic, + $broker + ); + $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations - $config->expects() - ->makeByTopic($topic) - ->andReturn($configManager); - - $configManager->expects() - ->middlewares() - ->andReturn([]); - - $configManager->expects() - ->get('topic_id') - ->andReturn($topic); - - $configManager->expects() - ->get('partition') - ->andReturn(0); - - $configManager->expects() - ->get('timeout') - ->andReturn(1000); - $connector->expects() - ->getProducerTopic($producerHandler, $configManager) + ->getProducerTopic($producerHandler, $producerConfigOptions) ->andReturn($kafkaProducer); $kafkaProducer->expects() @@ -86,36 +70,27 @@ public function testItShouldProduceRecordAsStringThroughMiddlewareQueue(): void ProducerMiddleware::class, m::mock(ProducerMiddleware::class) ); + $config = m::mock(Config::class); $connector = m::mock(Connector::class); - $configManager = m::mock(ProducerConfigManager::class)->makePartial(); + + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + $topic, + $broker + ); + $producer = new Producer($config, $connector); $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $producerHandler = new class($record, $topic) extends AbstractProducer { + $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations - $config->expects() - ->makeByTopic($topic) - ->andReturn($configManager); - - $configManager->expects() - ->middlewares() - ->andReturn([]); - - $configManager->expects() - ->get('topic_id') - ->andReturn($topic); - - $configManager->expects() - ->get('partition') - ->andReturn(0); - $connector->expects() - ->getProducerTopic($producerHandler, $configManager) + ->getProducerTopic($producerHandler, $producerConfigOptions) ->andReturn($kafkaProducer); $kafkaProducer->expects() @@ -127,10 +102,7 @@ public function testItShouldProduceRecordAsStringThroughMiddlewareQueue(): void ->withAnyArgs(); // Actions - $result = $producer->produce($producerHandler); - - // Assertions - $this->assertNull($result); + $producer->produce($producerHandler); } public function testItShouldThrowJsonExceptionWhenPassingMalFormattedArray(): void @@ -145,52 +117,29 @@ public function testItShouldThrowJsonExceptionWhenPassingMalFormattedArray(): vo $config = m::mock(Config::class); $connector = m::mock(Connector::class); $producer = new Producer($config, $connector); - $configManager = m::mock(ProducerConfigManager::class); + $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $producerHandler = new class($record, $topic) extends AbstractProducer { + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + $topic, + $broker, + 0, + new AvroSchemaConfigOptions('string'), + [], + 1000, + false, + true, + 500, + 1 + ); + $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations - $configManager->expects() - ->middlewares() - ->andReturn([]); - - $configManager->expects() - ->get('topic_id') - ->andReturn($topic); - - $configManager->expects() - ->get('partition') - ->andReturn(0); - - $configManager->expects() - ->get('max_poll_records') - ->andReturn(500); - - $configManager->expects() - ->get('required_acknowledgment') - ->andReturn(true); - - $configManager->expects() - ->get('flush_attempts') - ->andReturn(1); - - $configManager->expects() - ->get('timeout') - ->andReturn(1000); - - $configManager->expects() - ->get('is_async') - ->andReturn(false); - - $config->expects() - ->makeByTopic($topic) - ->andReturn($configManager); - $connector->expects() - ->getProducerTopic($producerHandler, $configManager) + ->getProducerTopic($producerHandler, $producerConfigOptions) ->andReturn($kafkaProducer); $kafkaProducer->expects() @@ -223,50 +172,27 @@ public function testShouldBuildDispatcher(): void $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $configManager = m::mock(ProducerConfigManager::class); - $producerHandler = new class($record, $topic) extends AbstractProducer { + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + $topic, + $broker, + null, + new AvroSchemaConfigOptions('string'), + [], + 1000, + true, + true, + 500, + 1 + ); + + $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations - $config->expects() - ->makeByTopic($topic) - ->andReturn($configManager); - - $configManager->expects() - ->middlewares() - ->andReturn([]); - - $configManager->expects() - ->get('topic_id') - ->andReturn($topic); - - $configManager->expects() - ->get('partition') - ->andReturn(0); - - $configManager->expects() - ->get('max_poll_records') - ->andReturn(500); - - $configManager->expects() - ->get('is_async') - ->andReturn(true); - - $configManager->expects() - ->get('required_acknowledgment') - ->andReturn(true); - - $configManager->expects() - ->get('flush_attempts') - ->andReturn(1); - - $configManager->expects() - ->get('timeout') - ->andReturn(1000); - $connector->expects() - ->getProducerTopic($producerHandler, $configManager) + ->getProducerTopic($producerHandler, $producerConfigOptions) ->andReturn($kafkaProducer); $kafkaProducer->expects() @@ -288,7 +214,7 @@ public function testShouldBuildDispatcherWithConfigOptions(): void { // Set $record = json_encode(['message' => 'some message']); - $topicId = 'TOPIC-ID'; + $topic = 'TOPIC-ID'; $config = m::mock(Config::class); $connector = m::mock(Connector::class); @@ -296,56 +222,30 @@ public function testShouldBuildDispatcherWithConfigOptions(): void $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $configManager = m::mock(ProducerConfigManager::class); - $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); - $broker = new Broker($connections, new None()); - $configOptions = new ProducerConfigOptions($topicId, $broker); - $producerHandler = new class($record, $configOptions) extends AbstractProducer { + + $broker = new Broker('kafka:9092', new None()); + $producerConfigOptions = new ProducerConfigOptions( + $topic, + $broker, + null, + new AvroSchemaConfigOptions('string'), + [], + 1000, + true, + true, + 500, + 1 + ); + $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations - $config->expects() - ->make($configOptions) - ->andReturn($configManager); - - $configManager->expects() - ->middlewares() - ->andReturn([]); - - $configManager->expects() - ->get('topic_id') - ->andReturn($topicId); - - $configManager->expects() - ->get('partition') - ->andReturn(0); - - $configManager->expects() - ->get('max_poll_records') - ->andReturn(500); - - $configManager->expects() - ->get('is_async') - ->andReturn(true); - - $configManager->expects() - ->get('required_acknowledgment') - ->andReturn(true); - - $configManager->expects() - ->get('flush_attempts') - ->andReturn(1); - - $configManager->expects() - ->get('timeout') - ->andReturn(1000); - $connector->expects() - ->getProducerTopic($producerHandler, $configManager) + ->getProducerTopic($producerHandler, $producerConfigOptions) ->andReturn($kafkaProducer); $kafkaProducer->expects() - ->newTopic($topicId) + ->newTopic($topic) ->andReturn($producerTopic); $kafkaProducer->expects() diff --git a/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php b/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php index cb78b0f7..f5c07f80 100644 --- a/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php +++ b/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php @@ -33,6 +33,7 @@ public function testShouldMakeConfigOptionWithAvroSchema(): void ]; $topicData = [ 'topic_id' => 'kafka-test', + 'consumer_group' => 'test-consumer-group', 'consumer' => [ 'consumer_groups' => [ 'test-consumer-group' => [ From 505c21c298840fc6b4ee763639f7eb2a844d2f78 Mon Sep 17 00:00:00 2001 From: David Franca Date: Mon, 21 Mar 2022 16:47:14 -0300 Subject: [PATCH 24/75] fix: update consumer middlewares --- src/Connectors/Consumer/Factory.php | 11 ++++++++++- src/Console/ConsumerCommand.php | 5 +++++ src/Facades/Metamorphosis.php | 1 + src/Producer.php | 1 - tests/Integration/ProducerTest.php | 27 ++++++++++++++++++++------- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/Connectors/Consumer/Factory.php b/src/Connectors/Consumer/Factory.php index 6a7c61aa..0da13cac 100644 --- a/src/Connectors/Consumer/Factory.php +++ b/src/Connectors/Consumer/Factory.php @@ -3,6 +3,7 @@ namespace Metamorphosis\Connectors\Consumer; use Metamorphosis\Consumers\ConsumerInterface; +use Metamorphosis\Middlewares\Handler\Consumer as ConsumerMiddleware; use Metamorphosis\Middlewares\Handler\Dispatcher; use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; @@ -23,9 +24,17 @@ public static function make(ConsumerConfigOptions $configOptions): Manager $commitAsync = $configOptions->isCommitASync(); $consumer = self::getConsumer($autoCommit, $configOptions); + $handler = app($configOptions->getHandler()); - $dispatcher = self::getMiddlewareDispatcher($configOptions->getMiddlewares()); + $middlewares = $configOptions->getMiddlewares(); + foreach ($middlewares as &$middleware) { + $middleware = is_string($middleware) ? app($middleware, ['consumerConfigOptions' => $configOptions]) : $middleware; + } + + $middlewares[] = app(ConsumerMiddleware::class, ['consumerTopicHandler' => $handler]); + + $dispatcher = self::getMiddlewareDispatcher($middlewares); return new Manager($consumer, $handler, $dispatcher, $autoCommit, $commitAsync); } diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index 5c233db4..bd4272e1 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -40,6 +40,11 @@ public function handle(Config $config) { $consumer = $config->make($this->option(), $this->argument()); + $middlewares = $consumer->getMiddlewares(); + foreach ($middlewares as &$middleware) { + $middleware = is_string($middleware) ? app($middleware, ['consumerConfigOptions' => $consumer]) : $middleware; + } + $this->writeStartingConsumer($consumer); $manager = Factory::make($consumer); diff --git a/src/Facades/Metamorphosis.php b/src/Facades/Metamorphosis.php index 70f903c8..c009a5f5 100644 --- a/src/Facades/Metamorphosis.php +++ b/src/Facades/Metamorphosis.php @@ -3,6 +3,7 @@ namespace Metamorphosis\Facades; use Illuminate\Support\Facades\Facade; +use Metamorphosis\TopicHandler\Producer\HandlerInterface; /** * @method static void produce(HandlerInterface $producerHandler) diff --git a/src/Producer.php b/src/Producer.php index ee277fdf..4fa9ee5b 100644 --- a/src/Producer.php +++ b/src/Producer.php @@ -35,7 +35,6 @@ public function build(HandlerInterface $producerHandler): Dispatcher $producerConfigOptions = $producerHandler->getConfigOptions(); $middlewares = $producerConfigOptions->getMiddlewares(); - foreach ($middlewares as &$middleware) { $middleware = is_string($middleware) ? app($middleware, ['producerConfigOptions' => $producerConfigOptions]) : $middleware; } diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index 9780d74c..ec43989b 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -77,6 +77,8 @@ protected function haveAConsumerPartitionConfigured(): void protected function runTheConsumer(): void { + config(['kafka.topics.default.topic_id' => $this->topicId]); + $this->artisan( 'kafka:consume', [ @@ -139,9 +141,13 @@ protected function runTheLowLevelConsumerSkippingTheFirstTwoMessagesAndLimitingT private function haveSomeRandomMessagesProduced(): void { $this->highLevelMessage = Str::random(10); - $producerConfigOptions = $this->createProducerConfigOptions('kafka-test'); -// $producer = app(MessageProducer::class, ['record' => $this->highLevelMessage, 'producer'=> $producerConfigOptions]); - $producer = new MessageProducer($this->highLevelMessage, $producerConfigOptions, 'recordId123'); + $this->topicId = 'kafka-test-'.Str::random(5); + $producerConfigOptions = $this->createProducerConfigOptions(); + $producer = app(MessageProducer::class, [ + 'record' => $this->highLevelMessage, + 'producer' => $producerConfigOptions, + 'key' => 'recordId123', + ]); Metamorphosis::produce($producer); Metamorphosis::produce($producer); @@ -150,7 +156,11 @@ private function haveSomeRandomMessagesProduced(): void private function produceRecordMessage(string $record): string { $producerConfigOptions = $this->createProducerConfigOptions('low_level'); - $producer = new MessageProducer($record, $producerConfigOptions, 'recordId123'); + $producer = app(MessageProducer::class, [ + 'record' => $record, + 'producer' => $producerConfigOptions, + 'key' => 'recordId123' + ]); Metamorphosis::produce($producer); Metamorphosis::produce($producer); @@ -190,15 +200,18 @@ private function haveFourProducedMessages(): void $this->produceRecordMessage($this->secondLowLevelMessage); } - private function createProducerConfigOptions(string $topicId = 'kafka-test'): ProducerConfigOptions + private function createProducerConfigOptions(): ProducerConfigOptions { $broker = new Broker('kafka:9092', new None()); return new ProducerConfigOptions( - $topicId, + $this->topicId, $broker, null, null, - [] + [], + 2000, + false, + true ); } } From 36042daec493552b9afddb5eff10b1d89e1c98e0 Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 10:21:58 -0300 Subject: [PATCH 25/75] fix: get and set options from consumer command --- src/Connectors/Consumer/Config.php | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index 4db8f76a..1b0b5c6e 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -56,7 +56,7 @@ public function make(array $options, array $arguments): Consumer $configName = $options['config_name'] ?? 'kafka'; $topicConfig = $this->getTopicConfig($configName, $arguments['topic']); $consumerGroupId = $this->getConsumerGroup($topicConfig, $arguments['consumer_group']); - $consumerConfig = $this->getConsumerConfig($topicConfig, $arguments, $consumerGroupId); + $consumerConfig = $this->getConsumerConfig($topicConfig, $options, $consumerGroupId); $brokerConfig = $this->getBrokerConfig($configName, $topicConfig['broker']); $schemaConfig = $this->getSchemaConfig($configName, $arguments['topic']); $override = array_merge($this->filterValues($options), $this->filterValues($arguments)); @@ -68,8 +68,19 @@ public function make(array $options, array $arguments): Consumer ); $this->validate(array_merge($config, $override)); - if (isset($topicConfig['consumer']['consumer_groups'][$consumerConfig['consumer_group']]['partition'])) { - $topicConfig['consumer']['consumer_groups'][$consumerConfig['consumer_group']]['partition'] = $consumerConfig['partition']; + + if (isset($topicConfig['consumer']['consumer_groups'][$consumerGroupId])) { + if (isset($options['partition'])) { + $topicConfig['consumer']['consumer_groups'][$consumerGroupId]['partition'] = $options['partition']; + } + + if (isset($options['offset'])) { + $topicConfig['consumer']['consumer_groups'][$consumerGroupId]['offset'] = $options['offset']; + } + + if (isset($options['timeout'])) { + $topicConfig['consumer']['consumer_groups'][$consumerGroupId]['timeout'] = $options['timeout']; + } } $topicConfig['consumer_group'] = $consumerGroupId; @@ -95,7 +106,7 @@ private function getTopicConfig(string $configName, string $topicId): array return $topicConfig; } - private function getConsumerConfig(array $topicConfig, array $arguments, string $consumerGroupId): array + private function getConsumerConfig(array $topicConfig, array $options, string $consumerGroupId): array { $consumerConfig = $topicConfig['consumer']['consumer_groups'][$consumerGroupId] ?? null; if (!$consumerConfig) { @@ -104,10 +115,6 @@ private function getConsumerConfig(array $topicConfig, array $arguments, string $consumerConfig['consumer_group'] = $consumerGroupId; - if (isset($arguments['partition'])) { - $consumerConfig['partition'] = $arguments['partition']; - } - return $consumerConfig; } From 2a02ecf727264b29504ef96c54fd49cb779de9b5 Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 10:23:16 -0300 Subject: [PATCH 26/75] chore: remove inutilized code --- src/Console/ConsumerCommand.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index bd4272e1..70f151e0 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -39,12 +39,6 @@ class ConsumerCommand extends BaseCommand public function handle(Config $config) { $consumer = $config->make($this->option(), $this->argument()); - - $middlewares = $consumer->getMiddlewares(); - foreach ($middlewares as &$middleware) { - $middleware = is_string($middleware) ? app($middleware, ['consumerConfigOptions' => $consumer]) : $middleware; - } - $this->writeStartingConsumer($consumer); $manager = Factory::make($consumer); From 75c1852113ebb179f6715d27eab7394d4afb07fd Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 10:26:34 -0300 Subject: [PATCH 27/75] chore: create public variable for message --- tests/Integration/ProducerTest.php | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index ec43989b..5a456a71 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -18,7 +18,22 @@ class ProducerTest extends LaravelTestCase protected string $firstLowLevelMessage; - protected string $secondLowLevelMessage; + /** + * @var string + */ + protected $secondLowLevelMessage; + + /** + * @var string + */ + protected $topicId; + + protected function setUp(): void + { + parent::setUp(); + $this->withoutAuthentication(); + $this->topicId = 'kafka-test-'.Str::random(5); + } /** * @group runProducer @@ -51,13 +66,6 @@ public function testShouldRunAProducerAndReceiveMessagesWithALowLevelConsumer(): $this->runTheLowLevelConsumerSkippingTheFirstTwoMessagesAndLimitingToTwoMessagesConsumed(); } - protected function setUp(): void - { - parent::setUp(); - - $this->withoutAuthentication(); - } - protected function withoutAuthentication(): void { config(['kafka.brokers.default.auth' => []]); @@ -141,8 +149,8 @@ protected function runTheLowLevelConsumerSkippingTheFirstTwoMessagesAndLimitingT private function haveSomeRandomMessagesProduced(): void { $this->highLevelMessage = Str::random(10); - $this->topicId = 'kafka-test-'.Str::random(5); - $producerConfigOptions = $this->createProducerConfigOptions(); + + $producerConfigOptions = $this->createProducerConfigOptions($this->topicId); $producer = app(MessageProducer::class, [ 'record' => $this->highLevelMessage, 'producer' => $producerConfigOptions, @@ -159,7 +167,7 @@ private function produceRecordMessage(string $record): string $producer = app(MessageProducer::class, [ 'record' => $record, 'producer' => $producerConfigOptions, - 'key' => 'recordId123' + 'key' => 'recordId123', ]); Metamorphosis::produce($producer); @@ -200,11 +208,11 @@ private function haveFourProducedMessages(): void $this->produceRecordMessage($this->secondLowLevelMessage); } - private function createProducerConfigOptions(): ProducerConfigOptions + private function createProducerConfigOptions(string $topicId): ProducerConfigOptions { $broker = new Broker('kafka:9092', new None()); return new ProducerConfigOptions( - $this->topicId, + $topicId, $broker, null, null, From 589f9a1be77164b215dafe7f20cd937e799a8ca3 Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 10:34:21 -0300 Subject: [PATCH 28/75] chore: create public variable for message --- tests/Integration/ProducerWithAvroTest.php | 65 ++++++++++++++++++---- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/tests/Integration/ProducerWithAvroTest.php b/tests/Integration/ProducerWithAvroTest.php index 449370da..014100ef 100644 --- a/tests/Integration/ProducerWithAvroTest.php +++ b/tests/Integration/ProducerWithAvroTest.php @@ -6,15 +6,30 @@ use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\HandlerStack; use GuzzleHttp\Psr7\Response; +use Illuminate\Support\Facades\Log; use Metamorphosis\Facades\Metamorphosis; use Metamorphosis\Middlewares\AvroSchemaDecoder; use Metamorphosis\Middlewares\AvroSchemaMixedEncoder; +use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; +use Metamorphosis\TopicHandler\ConfigOptions\Broker; +use Metamorphosis\TopicHandler\ConfigOptions\Producer as ProducerConfigOptions; use Tests\Integration\Dummies\MessageConsumer; use Tests\Integration\Dummies\MessageProducer; use Tests\LaravelTestCase; class ProducerWithAvroTest extends LaravelTestCase { + /** + * @var string[] + */ + protected $records; + + public function setUp(): void + { + parent::setUp(); + $this->records = ['saleOrderId' => 'SALE_ORDER_ID', 'productId' => 'PRODUCT_ID']; + } + public function testShouldRunAProducerMessagesWithAAvroSchema(): void { // Given That I @@ -22,7 +37,9 @@ public function testShouldRunAProducerMessagesWithAAvroSchema(): void // When I $this->haveSomeRandomMessagesProduced(); - $this->expectNotToPerformAssertions(); + + // I expect that + $this->myMessagesHaveBeenLogged(); } protected function haveAHandlerConfigured(): void @@ -93,14 +110,17 @@ protected function haveAHandlerConfigured(): void private function haveSomeRandomMessagesProduced(): void { - $saleOrderProducer = app( - MessageProducer::class, - ['record' => ['saleOrderId' => 'SALE_ORDER_ID'], 'topic' => 'sale_order'] - ); - $productProducer = app( - MessageProducer::class, - ['record' => ['productId' => 'PRODUCT_ID'], 'topic' => 'product'] - ); + $producerConfigOptionsSale = $this->createProducerConfigOptions('sale_order'); + $producerConfigOptionsProduct = $this->createProducerConfigOptions('product'); + + $saleOrderProducer = app(MessageProducer::class, [ + 'record' => ['saleOrderId' => 'SALE_ORDER_ID'], + 'producer' => $producerConfigOptionsSale, + ]); + $productProducer = app(MessageProducer::class, [ + 'record' => ['productId' => 'PRODUCT_ID'], + 'producer' => $producerConfigOptionsProduct, + ]); $saleOrderSchemaResponse = '{ "subject":"sale_order-value", @@ -129,7 +149,32 @@ private function haveSomeRandomMessagesProduced(): void $productDispatcher = Metamorphosis::build($productProducer); $productDispatcher->handle($productProducer->createRecord()); + } - $saleOrderDispatcher->handle($saleOrderProducer->createRecord()); + private function myMessagesHaveBeenLogged(): void + { + $this->setLogExpectationsFor($this->records['saleOrderId']); + $this->setLogExpectationsFor($this->records['productId']); + } + + private function setLogExpectationsFor(string $message): void + { + Log::shouldReceive('info') + ->with($message); + } + + private function createProducerConfigOptions(string $topicId): ProducerConfigOptions + { + $broker = new Broker('kafka:9092', new None()); + return new ProducerConfigOptions( + $topicId, + $broker, + null, + null, + [], + 2000, + false, + true + ); } } From 8569e1d5271e92fe4d8a5b9771b1618a61b96c3e Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 10:37:24 -0300 Subject: [PATCH 29/75] chore: create public variable for message --- tests/Integration/ProducerWithConfigOptionsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/ProducerWithConfigOptionsTest.php b/tests/Integration/ProducerWithConfigOptionsTest.php index 4e256a42..f4f58b94 100644 --- a/tests/Integration/ProducerWithConfigOptionsTest.php +++ b/tests/Integration/ProducerWithConfigOptionsTest.php @@ -88,7 +88,7 @@ private function haveSomeRandomMessageProduced(): void MessageProducerWithConfigOptions::class, [ 'record' => ['saleOrderId' => 'SALE_ORDER_ID'], - 'configOptions' => $this->producerConfigOptions, + 'producer' => $this->producerConfigOptions, 'key' => 1, ] ); From e67052ee2877c3d59bd15ef01eb1ac75d15f636e Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 10:38:44 -0300 Subject: [PATCH 30/75] fix: change parameter order --- tests/Unit/Connectors/Consumer/FactoryTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Connectors/Consumer/FactoryTest.php b/tests/Unit/Connectors/Consumer/FactoryTest.php index 50a158f2..ae3dedf6 100644 --- a/tests/Unit/Connectors/Consumer/FactoryTest.php +++ b/tests/Unit/Connectors/Consumer/FactoryTest.php @@ -58,11 +58,11 @@ public function testItMakesManagerWithLowLevelConsumer(): void $this->assertInstanceOf(LowLevel::class, $manager->getConsumer()); } - public function testItMakesManagerWithLowLevelConsumerWhenPartitionIsNotValid(): void + public function testItMakesManagerWithHighLevelConsumerWhenPartitionIsNotValid(): void { // Set $config = new Config(); - $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'with-partition', 'partition' => -1]); + $configConsumer = $config->make(['timeout' => 61, 'partition' => -1], ['topic' => 'topic_key', 'consumer_group' => 'with-partition']); $manager = Factory::make($configConsumer); // Assertions From 981526b6edf2b21ddc2e8d92ba5fe5c78ff49c07 Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 16:44:23 -0300 Subject: [PATCH 31/75] docs: add CHANGELOG file --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..0ecf5eae --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,40 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- + +### Fixed + +- + +### Removed +- Remove deprecated class AbstractHandler + +## [4.1.0] - 2022-03-23 + +### Added +- Added AvroSchemaMixedEncoderTest +- Added AvroSchemaDecoderTest +- Added ProducerWithConfigOptionsTest +- Added ConfigOptionsCommand to run commands with ConfigOptions class +- Added pt_BR contributing section +- Added setup-dev script on composer +- Added grumphp commit validation + +### Fixed +- Fixed parameters and options override on Consumer\Config class +- Update instructions on contribute section +- Update project install section + +### Changed +- Updated class from ConfigManager to ConfigOptions on unit tests +- Updated class from ConfigManager to ConfigOptions where any config request was made +- Consumer and Producer middlewares resolution From 5edaa00b8e524c668629527d3e954e8819a5162c Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 23 Mar 2022 17:12:50 -0300 Subject: [PATCH 32/75] docs: add CHANGELOG file --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ecf5eae..32abee8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - +### Changed + +- + ### Removed - Remove deprecated class AbstractHandler From 506731b2f61d6445c56f0f8df2540a5aa7193d78 Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 24 Mar 2022 11:50:50 -0300 Subject: [PATCH 33/75] chore: rename parameter from 'producer' to 'configOptions' This would be a breaking change, so it's better keep as 'configOptions' by now. --- src/TopicHandler/Producer/AbstractProducer.php | 4 ++-- tests/Integration/ConsumerTest.php | 2 +- tests/Integration/ProducerTest.php | 4 ++-- tests/Integration/ProducerWithAvroTest.php | 4 ++-- tests/Integration/ProducerWithConfigOptionsTest.php | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/TopicHandler/Producer/AbstractProducer.php b/src/TopicHandler/Producer/AbstractProducer.php index 946db3ce..694aedd0 100644 --- a/src/TopicHandler/Producer/AbstractProducer.php +++ b/src/TopicHandler/Producer/AbstractProducer.php @@ -20,11 +20,11 @@ class AbstractProducer implements HandlerInterface */ protected $producer; - public function __construct($record, Producer $producer, string $key = null) + public function __construct($record, Producer $configOptions, string $key = null) { $this->record = $record; $this->key = $key; - $this->producer = $producer; + $this->producer = $configOptions; } public function getConfigOptions(): Producer diff --git a/tests/Integration/ConsumerTest.php b/tests/Integration/ConsumerTest.php index 7088e46b..1d4397e8 100644 --- a/tests/Integration/ConsumerTest.php +++ b/tests/Integration/ConsumerTest.php @@ -51,7 +51,7 @@ public function testItShouldSetup(): void MessageProducerWithConfigOptions::class, [ 'record' => ['id' => 'MESSAGE_ID'], - 'producer' => $producerConfigOptions, + 'configOptions' => $producerConfigOptions, 'key' => 1, ] ); diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index 5a456a71..73852c4c 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -153,7 +153,7 @@ private function haveSomeRandomMessagesProduced(): void $producerConfigOptions = $this->createProducerConfigOptions($this->topicId); $producer = app(MessageProducer::class, [ 'record' => $this->highLevelMessage, - 'producer' => $producerConfigOptions, + 'configOptions' => $producerConfigOptions, 'key' => 'recordId123', ]); @@ -166,7 +166,7 @@ private function produceRecordMessage(string $record): string $producerConfigOptions = $this->createProducerConfigOptions('low_level'); $producer = app(MessageProducer::class, [ 'record' => $record, - 'producer' => $producerConfigOptions, + 'configOptions' => $producerConfigOptions, 'key' => 'recordId123', ]); diff --git a/tests/Integration/ProducerWithAvroTest.php b/tests/Integration/ProducerWithAvroTest.php index 014100ef..b0c801ad 100644 --- a/tests/Integration/ProducerWithAvroTest.php +++ b/tests/Integration/ProducerWithAvroTest.php @@ -115,11 +115,11 @@ private function haveSomeRandomMessagesProduced(): void $saleOrderProducer = app(MessageProducer::class, [ 'record' => ['saleOrderId' => 'SALE_ORDER_ID'], - 'producer' => $producerConfigOptionsSale, + 'configOptions' => $producerConfigOptionsSale, ]); $productProducer = app(MessageProducer::class, [ 'record' => ['productId' => 'PRODUCT_ID'], - 'producer' => $producerConfigOptionsProduct, + 'configOptions' => $producerConfigOptionsProduct, ]); $saleOrderSchemaResponse = '{ diff --git a/tests/Integration/ProducerWithConfigOptionsTest.php b/tests/Integration/ProducerWithConfigOptionsTest.php index f4f58b94..4e256a42 100644 --- a/tests/Integration/ProducerWithConfigOptionsTest.php +++ b/tests/Integration/ProducerWithConfigOptionsTest.php @@ -88,7 +88,7 @@ private function haveSomeRandomMessageProduced(): void MessageProducerWithConfigOptions::class, [ 'record' => ['saleOrderId' => 'SALE_ORDER_ID'], - 'producer' => $this->producerConfigOptions, + 'configOptions' => $this->producerConfigOptions, 'key' => 1, ] ); From ed2ec847cdf01512cf037529ce8641789c49d8a1 Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 24 Mar 2022 14:44:51 -0300 Subject: [PATCH 34/75] chore: remove annotation --- src/Facades/Metamorphosis.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Facades/Metamorphosis.php b/src/Facades/Metamorphosis.php index c009a5f5..b3c934ca 100644 --- a/src/Facades/Metamorphosis.php +++ b/src/Facades/Metamorphosis.php @@ -3,11 +3,7 @@ namespace Metamorphosis\Facades; use Illuminate\Support\Facades\Facade; -use Metamorphosis\TopicHandler\Producer\HandlerInterface; -/** - * @method static void produce(HandlerInterface $producerHandler) - */ class Metamorphosis extends Facade { protected static function getFacadeAccessor() From 52c5903244e84c766e24c7137ed9ac39ae8bd887 Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 24 Mar 2022 20:42:10 -0300 Subject: [PATCH 35/75] chore: update middleware resolution on consumerCommand --- src/Console/ConsumerCommand.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index 70f151e0..bd4272e1 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -39,6 +39,12 @@ class ConsumerCommand extends BaseCommand public function handle(Config $config) { $consumer = $config->make($this->option(), $this->argument()); + + $middlewares = $consumer->getMiddlewares(); + foreach ($middlewares as &$middleware) { + $middleware = is_string($middleware) ? app($middleware, ['consumerConfigOptions' => $consumer]) : $middleware; + } + $this->writeStartingConsumer($consumer); $manager = Factory::make($consumer); From c2b2c085e7fbf249b38ca8010711b06ed4188442 Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 24 Mar 2022 21:43:32 -0300 Subject: [PATCH 36/75] chore: remove ManageTest --- tests/Unit/ManagerTest.php | 66 -------------------------------------- 1 file changed, 66 deletions(-) diff --git a/tests/Unit/ManagerTest.php b/tests/Unit/ManagerTest.php index 846db3f5..e69de29b 100644 --- a/tests/Unit/ManagerTest.php +++ b/tests/Unit/ManagerTest.php @@ -1,66 +0,0 @@ -set([ - 'topic' => 'products', - 'middlewares' => [ - Log::class, - app(JsonDecode::class), - ], - 'other' => 'config', - ]); - - // Actions - $other = $manager->get('other'); - $middlewares = $manager->middlewares(); - - // Assertions - $this->assertSame('config', $other); - $this->assertInstanceOf(Log::class, $middlewares[0]); - $this->assertInstanceOf(JsonDecode::class, $middlewares[1]); - } - - public function testShouldRemoveOldMiddlewareBeforeAddOthers(): void - { - // Set - $manager = new ConsumerConfigManager(); - $firstConfig = [ - 'topic' => 'products', - 'middlewares' => [ - Log::class, - app(JsonDecode::class), - ], - 'other' => 'config', - ]; - $secondConfig = [ - 'topic' => 'products', - 'middlewares' => [ - JsonDecode::class, - ], - 'other' => 'config', - ]; - - // Actions - $manager->set($firstConfig); - $manager->set($secondConfig); - $other = $manager->get('other'); - $middlewares = $manager->middlewares(); - - // Assertions - $this->assertSame('config', $other); - $this->assertInstanceOf(JsonDecode::class, $middlewares[0]); - $this->assertCount(1, $middlewares); - } -} From d2b71993eca2ca43c8a77a863fe1d5cd33e045ae Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 24 Mar 2022 21:47:10 -0300 Subject: [PATCH 37/75] chore: remove occurrences of ConsumerConfigManager --- src/Consumer.php | 4 +--- tests/Unit/Connectors/Consumer/ManagerTest.php | 2 -- tests/Unit/Consumers/LowLevelTest.php | 3 --- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Consumer.php b/src/Consumer.php index 1d35a0c1..367556fa 100644 --- a/src/Consumer.php +++ b/src/Consumer.php @@ -15,10 +15,8 @@ class Consumer private Dispatcher $dispatcher; - public function __construct(ConsumerConfigManager $configManager, ConsumerConfigOptions $configOptions) + public function __construct(ConsumerConfigOptions $configOptions) { - $configManager->set($configOptions->toArray()); - $this->consumer = Factory::getConsumer(true, $configOptions); $this->dispatcher = new Dispatcher($configOptions->getMiddlewares()); } diff --git a/tests/Unit/Connectors/Consumer/ManagerTest.php b/tests/Unit/Connectors/Consumer/ManagerTest.php index d69d72eb..230513b2 100644 --- a/tests/Unit/Connectors/Consumer/ManagerTest.php +++ b/tests/Unit/Connectors/Consumer/ManagerTest.php @@ -4,7 +4,6 @@ use Exception; use Metamorphosis\Connectors\Consumer\Manager; -use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Consumers\ConsumerInterface; use Metamorphosis\Exceptions\ResponseTimeoutException; use Metamorphosis\Exceptions\ResponseWarningException; @@ -14,7 +13,6 @@ use Mockery as m; use RdKafka\Message as KafkaMessage; use Tests\LaravelTestCase; -use Tests\Unit\Dummies\ConsumerHandlerDummy; class ManagerTest extends LaravelTestCase { diff --git a/tests/Unit/Consumers/LowLevelTest.php b/tests/Unit/Consumers/LowLevelTest.php index cc8bb988..b39ac2aa 100644 --- a/tests/Unit/Consumers/LowLevelTest.php +++ b/tests/Unit/Consumers/LowLevelTest.php @@ -2,7 +2,6 @@ namespace Tests\Unit\Consumers; -use Metamorphosis\ConsumerConfigManager; use Metamorphosis\Consumers\LowLevel; use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema as AvroSchemaConfigOptions; @@ -20,8 +19,6 @@ public function testItShouldConsume(): void // Set $timeout = 2; $partition = 3; - $configManager = new ConsumerConfigManager(); - $configManager->set(compact('timeout', 'partition')); $brokerOptions = new Broker('kafka:9092', new None()); $consumerConfigOptions = new ConsumerConfigOptions( From b5eeb205aecfc7822d5d2509ebfd1e57cd6fc9ca Mon Sep 17 00:00:00 2001 From: hcdias Date: Thu, 24 Mar 2022 21:47:56 -0300 Subject: [PATCH 38/75] chore: remove TODO comment --- src/Connectors/Consumer/Factory.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Connectors/Consumer/Factory.php b/src/Connectors/Consumer/Factory.php index 0da13cac..c82c4ad2 100644 --- a/src/Connectors/Consumer/Factory.php +++ b/src/Connectors/Consumer/Factory.php @@ -13,9 +13,6 @@ * means that we will use the low level approach. */ -/** - * TODO Rename this class to ConsumerFactory, it will improve semantics - */ class Factory { public static function make(ConsumerConfigOptions $configOptions): Manager From 7ad9a61cb05289c2b064ad40b8d752c0e0ee393e Mon Sep 17 00:00:00 2001 From: hcdias Date: Fri, 25 Mar 2022 10:20:06 -0300 Subject: [PATCH 39/75] chore: remove ProducerConfigManager occurences --- src/ConsumerConfigManager.php | 54 ------------------- .../Unit/Middlewares/Handler/ProducerTest.php | 1 - tests/Unit/Producer/PollTest.php | 12 ----- 3 files changed, 67 deletions(-) delete mode 100644 src/ConsumerConfigManager.php diff --git a/src/ConsumerConfigManager.php b/src/ConsumerConfigManager.php deleted file mode 100644 index 88207c97..00000000 --- a/src/ConsumerConfigManager.php +++ /dev/null @@ -1,54 +0,0 @@ -setConfig($config, $consumerHandler); - $this->setCommandConfig($commandConfig); - - $middlewares = $this->get('middlewares', []); - $this->middlewares = []; - $this->remove('middlewares'); - - foreach ($middlewares as $middleware) { - $this->middlewares[] = is_string($middleware) ? app($middleware) : $middleware; - } - - if (!$consumerHandler) { - return; - } - - $this->middlewares[] = new ConsumerMiddleware($consumerHandler); - } - - private function setCommandConfig(?array $commandConfig): void - { - if (!$commandConfig) { - return; - } - - $this->setting = array_merge($this->setting, $commandConfig); - } - - private function setConfig(array $config, ?AbstractHandler $handler): void - { - if (!$handler || !$overrideConfig = $handler->getConfigOptions()) { - $this->setting = $config; - - return; - } - - $this->setting = $overrideConfig->toArray(); - } -} diff --git a/tests/Unit/Middlewares/Handler/ProducerTest.php b/tests/Unit/Middlewares/Handler/ProducerTest.php index 3a7bbc70..df2750e6 100644 --- a/tests/Unit/Middlewares/Handler/ProducerTest.php +++ b/tests/Unit/Middlewares/Handler/ProducerTest.php @@ -5,7 +5,6 @@ use Closure; use Metamorphosis\Middlewares\Handler\Producer; use Metamorphosis\Producer\Poll; -use Metamorphosis\ProducerConfigManager; use Metamorphosis\Record\ProducerRecord; use Mockery as m; use RdKafka\ProducerTopic as KafkaTopicProducer; diff --git a/tests/Unit/Producer/PollTest.php b/tests/Unit/Producer/PollTest.php index 3ef21c96..0576cd6c 100644 --- a/tests/Unit/Producer/PollTest.php +++ b/tests/Unit/Producer/PollTest.php @@ -3,7 +3,6 @@ namespace Tests\Unit\Producer; use Metamorphosis\Producer\Poll; -use Metamorphosis\ProducerConfigManager; use Metamorphosis\TopicHandler\ConfigOptions\Auth\None; use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema as AvroSchemaConfigOptions; use Metamorphosis\TopicHandler\ConfigOptions\Broker; @@ -48,17 +47,6 @@ public function testItShouldHandleMessageWithoutAcknowledgment(): void public function testShouldThrowExceptionWhenFlushFailed(): void { // Set - $configManager = new ProducerConfigManager(); - $configManager->set([ - 'topic_id' => 'topic_name', - 'timeout' => 1000, - 'is_async' => false, - 'max_poll_records' => 500, - 'flush_attempts' => 3, - 'required_acknowledgment' => true, - 'partition' => 0, - ]); - $broker = new Broker('kafka:9092', new None()); $producerConfigOptions = new ProducerConfigOptions( 'topic_name', From 430148df60c16b0a323993ec98018339481f308a Mon Sep 17 00:00:00 2001 From: hcdias Date: Tue, 19 Apr 2022 16:10:10 -0300 Subject: [PATCH 40/75] chore: remove unecessary interface --- src/Avro/AvroClientInterface.php | 6 ------ src/Avro/CachedSchemaRegistryClientInterface.php | 7 ------- 2 files changed, 13 deletions(-) delete mode 100644 src/Avro/AvroClientInterface.php delete mode 100644 src/Avro/CachedSchemaRegistryClientInterface.php diff --git a/src/Avro/AvroClientInterface.php b/src/Avro/AvroClientInterface.php deleted file mode 100644 index d7617023..00000000 --- a/src/Avro/AvroClientInterface.php +++ /dev/null @@ -1,6 +0,0 @@ - Date: Tue, 19 Apr 2022 16:12:26 -0300 Subject: [PATCH 41/75] chore: remove unecessary code block --- src/Console/ConsumerCommand.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index bd4272e1..5c233db4 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -40,11 +40,6 @@ public function handle(Config $config) { $consumer = $config->make($this->option(), $this->argument()); - $middlewares = $consumer->getMiddlewares(); - foreach ($middlewares as &$middleware) { - $middleware = is_string($middleware) ? app($middleware, ['consumerConfigOptions' => $consumer]) : $middleware; - } - $this->writeStartingConsumer($consumer); $manager = Factory::make($consumer); From f1598e2d57bfdd111ad8644e122168bf1bec2be3 Mon Sep 17 00:00:00 2001 From: hcdias Date: Tue, 19 Apr 2022 16:13:45 -0300 Subject: [PATCH 42/75] chore: define constant visibility --- src/Avro/ClientFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avro/ClientFactory.php b/src/Avro/ClientFactory.php index b30d0c1b..388a8fed 100644 --- a/src/Avro/ClientFactory.php +++ b/src/Avro/ClientFactory.php @@ -7,7 +7,7 @@ class ClientFactory { - const REQUEST_TIMEOUT = 2000; + protected const REQUEST_TIMEOUT = 2000; public function make(AvroSchema $avroSchema): CachedSchemaRegistryClient { From f7bc97024204919d9e64cb6485f44f43c42c01a3 Mon Sep 17 00:00:00 2001 From: hcdias Date: Fri, 1 Apr 2022 15:59:18 -0300 Subject: [PATCH 43/75] chore: change config file format --- config/kafka.php | 172 ++++-------------- config/service.php | 28 +++ src/Connectors/AbstractConfig.php | 24 +-- src/Connectors/Consumer/Config.php | 56 +----- src/Connectors/Producer/Config.php | 12 +- src/MetamorphosisServiceProvider.php | 6 +- .../Factories/ConsumerFactory.php | 6 +- 7 files changed, 86 insertions(+), 218 deletions(-) create mode 100644 config/service.php diff --git a/config/kafka.php b/config/kafka.php index 00912858..9e74693b 100644 --- a/config/kafka.php +++ b/config/kafka.php @@ -1,128 +1,46 @@ [ - 'default' => [ - 'url' => '', - // Disable SSL verification on schema request. - 'ssl_verify' => true, - // This option will be put directly into a Guzzle http request - // Use this to do authorizations or send any headers you want. - // Here is a example of basic authentication on AVRO schema. - 'request_options' => [ - 'headers' => [ - 'Authorization' => [ - 'Basic ' . base64_encode( - env('AVRO_SCHEMA_USERNAME') - . ':' - . env('AVRO_SCHEMA_PASSWORD') - ), - ], - ], - ], - ], - ], - - /* - |-------------------------------------------------------------------------- - | Brokers - |-------------------------------------------------------------------------- - | - | Here you may specify the connections details for each broker configured - | on topic's broker key. - | - */ - - 'brokers' => [ - 'default' => [ - 'connections' => env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'), - - // If your broker doest not have authentication, you can - // remove this configuration, or set as empty. - // The Authentication types may be "ssl" or "none" - 'auth' => [ - 'type' => 'ssl', // ssl and none - 'ca' => storage_path('ca.pem'), - 'certificate' => storage_path('kafka.cert'), - 'key' => storage_path('kafka.key'), - ], - ], - ], - 'topics' => [ - // This is your topic "keyword" where you will put all configurations needed - // on this specific topic. 'default' => [ - // The topic id is where you want to send or consume - // your messages from kafka. 'topic_id' => 'kafka-test', - - // Here you may point the key of the broker configured above. - 'broker' => 'default', - - // Configurations specific for consumer 'consumer' => [ - // You may define more than one consumer group per topic. - // If there is just one defined, it will be used by default, - // otherwise, you may pass which consumer group should be used - // when using the consumer command. - 'consumer_groups' => [ - 'test-consumer-group' => [ - - // Action to take when there is no initial - // offset in offset store or the desired offset is out of range. - // This config will be passed to 'auto.offset.reset'. - // The valid options are: smallest, earliest, beginning, largest, latest, end, error. - 'offset_reset' => 'earliest', - - // The offset at which to start consumption. This only applies if partition is set. - // You can use a positive integer or any of the constants: RD_KAFKA_OFFSET_BEGINNING, - // RD_KAFKA_OFFSET_END, RD_KAFKA_OFFSET_STORED. - 'offset' => 0, - - // The partition to consume. It can be null, - // if you don't wish do specify one. - 'partition' => 0, - - // A consumer class that implements ConsumerTopicHandler - 'handler' => '\App\Kafka\Consumers\ConsumerExample', - - // A Timeout to listen to a message. That means: how much - // time we need to wait until receiving a message? - 'timeout' => 20000, - - // A max interval for consumer to make poll calls. That means: how much - // time we need to wait for poll calls until consider the consumer has inactive. - 'max_poll_interval_ms' => 300000, - - // Once you've enabled this, the Kafka consumer will commit the - // offset of the last message received in response to its poll() call - 'auto_commit' => true, - - // If commit_async is false process block until offsets are committed or the commit fails. - // Only works when auto_commit is false - 'commit_async' => false, - - // An array of middlewares applied only for this consumer_group - 'middlewares' => [], - ], - ], + 'consumer_group' => 'test-consumer-group', + // Action to take when there is no initial + // offset in offset store or the desired offset is out of range. + // This config will be passed to 'auto.offset.reset'. + // The valid options are: smallest, earliest, beginning, largest, latest, end, error. + 'offset_reset' => 'earliest', + + // The offset at which to start consumption. This only applies if partition is set. + // You can use a positive integer or any of the constants: RD_KAFKA_OFFSET_BEGINNING, + // RD_KAFKA_OFFSET_END, RD_KAFKA_OFFSET_STORED. + 'offset' => 0, + + // The partition to consume. It can be null, + // if you don't wish do specify one. + 'partition' => 0, + + // A consumer class that implements ConsumerTopicHandler + 'handler' => '\App\Kafka\Consumers\ConsumerExample', + + // A Timeout to listen to a message. That means: how much + // time we need to wait until receiving a message? + 'timeout' => 20000, + + // Once you've enabled this, the Kafka consumer will commit the + // offset of the last message received in response to its poll() call + 'auto_commit' => true, + + // If commit_async is false process block until offsets are committed or the commit fails. + // Only works when auto_commit is false + 'commit_async' => false, + + // An array of middlewares applied only for this consumer_group + 'middlewares' => [], ], - // Configurations specific for producer 'producer' => [ - // Sets to true if you want to know if a message was successfully posted. 'required_acknowledgment' => true, @@ -153,28 +71,4 @@ ], ], ], - - /* - |-------------------------------------------------------------------------- - | Global Middlewares - |-------------------------------------------------------------------------- - | - | Here you may specify the global middlewares that will be applied for every - | consumed topic. Middlewares work between the received data from broker and - | before being passed into consumers. - | Available middlewares: log, avro-decode - | - */ - - 'middlewares' => [ - 'consumer' => [ - \Metamorphosis\Middlewares\Log::class, - ], - 'producer' => [ - \Metamorphosis\Middlewares\Log::class, - ], - 'global' => [ - \Metamorphosis\Middlewares\Log::class, - ], - ], ]; diff --git a/config/service.php b/config/service.php new file mode 100644 index 00000000..82cb1299 --- /dev/null +++ b/config/service.php @@ -0,0 +1,28 @@ + [ + 'url' => '', + 'request_options' => [ + 'headers' => [ + 'Authorization' => [ + 'Basic '.base64_encode( + env('AVRO_SCHEMA_USERNAME').':'.env('AVRO_SCHEMA_PASSWORD') + ), + ], + ], + ], + 'ssl_verify' => true, + 'username' => 'USERNAME', + 'password' => 'PASSWORD', + ], + 'broker' => [ + 'connections' => 'kafka:9092', + 'auth' => [ + 'type' => 'ssl', // ssl and none + 'ca' => storage_path('ca.pem'), + 'certificate' => storage_path('kafka.cert'), + 'key' => storage_path('kafka.key'), + ], + ], +]; diff --git a/src/Connectors/AbstractConfig.php b/src/Connectors/AbstractConfig.php index 9942dc2e..fa8b8ac1 100644 --- a/src/Connectors/AbstractConfig.php +++ b/src/Connectors/AbstractConfig.php @@ -7,20 +7,17 @@ abstract class AbstractConfig { - /** - * @var mixed[] - */ - protected array $rules = []; - - protected function getBrokerConfig(string $configName, string $brokerId): array + protected function getBrokerConfig(string $servicesFile): array { - if (!$brokerConfig = config("{$configName}.brokers.{$brokerId}")) { - throw new ConfigurationException( - "Broker '{$brokerId}' configuration not found" - ); + if (!$brokerConfig = config($servicesFile.'.broker')) { + throw new ConfigurationException("Broker configuration not found on '{$servicesFile}'"); } + return $brokerConfig; + } - return (array) $brokerConfig; + protected function getSchemaConfig(string $servicesFile): array + { + return config($servicesFile.'.avro_schema', []); } protected function validate(array $config): void @@ -31,9 +28,4 @@ protected function validate(array $config): void throw new ConfigurationException($validator->errors()->toJson()); } } - - protected function getSchemaConfig(string $configName, string $topicId): array - { - return config($configName . '.avro_schemas.' . $topicId, []); - } } diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index 1b0b5c6e..aabcfd8b 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -54,37 +54,26 @@ public function makeWithConfigOptions(string $handlerClass, ?int $times = null): public function make(array $options, array $arguments): Consumer { $configName = $options['config_name'] ?? 'kafka'; - $topicConfig = $this->getTopicConfig($configName, $arguments['topic']); - $consumerGroupId = $this->getConsumerGroup($topicConfig, $arguments['consumer_group']); - $consumerConfig = $this->getConsumerConfig($topicConfig, $options, $consumerGroupId); - $brokerConfig = $this->getBrokerConfig($configName, $topicConfig['broker']); - $schemaConfig = $this->getSchemaConfig($configName, $arguments['topic']); - $override = array_merge($this->filterValues($options), $this->filterValues($arguments)); - $config = array_merge( - $topicConfig, - $brokerConfig, - $consumerConfig, - $schemaConfig - ); + $service = $options['service'] ?? 'service'; - $this->validate(array_merge($config, $override)); + $topicConfig = $this->getTopicConfig($configName, $arguments['topic']); + $brokerConfig = $this->getBrokerConfig($service); + $schemaConfig = $this->getSchemaConfig($service); - if (isset($topicConfig['consumer']['consumer_groups'][$consumerGroupId])) { + if (isset($topicConfig['consumer'])) { if (isset($options['partition'])) { - $topicConfig['consumer']['consumer_groups'][$consumerGroupId]['partition'] = $options['partition']; + $topicConfig['consumer']['partition'] = $options['partition']; } if (isset($options['offset'])) { - $topicConfig['consumer']['consumer_groups'][$consumerGroupId]['offset'] = $options['offset']; + $topicConfig['consumer']['offset'] = $options['offset']; } if (isset($options['timeout'])) { - $topicConfig['consumer']['consumer_groups'][$consumerGroupId]['timeout'] = $options['timeout']; + $topicConfig['consumer']['timeout'] = $options['timeout']; } } - $topicConfig['consumer_group'] = $consumerGroupId; - return ConsumerFactory::make($brokerConfig, $topicConfig, $schemaConfig); } @@ -106,35 +95,6 @@ private function getTopicConfig(string $configName, string $topicId): array return $topicConfig; } - private function getConsumerConfig(array $topicConfig, array $options, string $consumerGroupId): array - { - $consumerConfig = $topicConfig['consumer']['consumer_groups'][$consumerGroupId] ?? null; - if (!$consumerConfig) { - throw new ConfigurationException("Consumer group '{$consumerGroupId}' not found"); - } - - $consumerConfig['consumer_group'] = $consumerGroupId; - - return $consumerConfig; - } - - private function getConsumerGroup(array $topicConfig, ?string $consumerGroupId): string - { - if (!$consumerGroupId && 1 === count($topicConfig['consumer']['consumer_groups'])) { - $consumerGroupId = current(array_keys($topicConfig['consumer']['consumer_groups'])); - } - - return $consumerGroupId ?? 'default'; - } - - private function getMiddlewares(string $configName, array $topicConfig): array - { - return array_merge( - config($configName . '.middlewares.consumer', []), - $topicConfig['consumer']['middlewares'] ?? [] - ); - } - /** * Sometimes that user may pass `--partition=0` as argument. * So if we just use array_filter here, this option will diff --git a/src/Connectors/Producer/Config.php b/src/Connectors/Producer/Config.php index 90a9cd1d..e3cf8e80 100644 --- a/src/Connectors/Producer/Config.php +++ b/src/Connectors/Producer/Config.php @@ -50,15 +50,9 @@ public function make(ProducerConfigOptions $configOptions): AbstractConfigManage public function makeByTopic(string $topicId): AbstractConfigManager { $topicConfig = $this->getTopicConfig($topicId); - $topicConfig['middlewares'] = array_merge( - config('kafka.middlewares.producer', []), - $topicConfig['producer']['middlewares'] ?? [] - ); - $brokerConfig = $this->getBrokerConfig( - 'kafka', - $topicConfig['broker'] - ); - $schemaConfig = $this->getSchemaConfig('kafka', $topicId); + $topicConfig['middlewares'] = $topicConfig['producer']['middlewares'] ?? []; + $brokerConfig = $this->getBrokerConfig('service'); + $schemaConfig = $this->getSchemaConfig('service'); $config = array_merge($topicConfig, $brokerConfig, $schemaConfig); $this->validate($config); diff --git a/src/MetamorphosisServiceProvider.php b/src/MetamorphosisServiceProvider.php index 4938fbac..36dffdf5 100644 --- a/src/MetamorphosisServiceProvider.php +++ b/src/MetamorphosisServiceProvider.php @@ -14,10 +14,12 @@ class MetamorphosisServiceProvider extends ServiceProvider public function boot() { $this->publishes([ - __DIR__ . '/../config/kafka.php' => config_path('kafka.php'), + __DIR__.'/../config/kafka.php' => config_path('kafka.php'), + __DIR__.'/../config/service.php' => config_path('service.php'), ], 'config'); - $this->mergeConfigFrom(__DIR__ . '/../config/kafka.php', 'kafka'); + $this->mergeConfigFrom(__DIR__.'/../config/kafka.php', 'kafka'); + $this->mergeConfigFrom(__DIR__.'/../config/service.php', 'service'); } public function register() diff --git a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php index 7bd58c93..4dd62736 100644 --- a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php +++ b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php @@ -22,10 +22,8 @@ public static function make( private static function getConsumerGroupConfig(array $topicData): array { $topicData['topicId'] = $topicData['topic_id']; - $topicData['consumerGroup'] = $topicData['consumer_group']; - - $consumerGroup = $topicData['consumerGroup']; - $consumer = current($topicData['consumer'])[$consumerGroup]; + $consumer = $topicData['consumer']; + $topicData['consumerGroup'] = $consumer['consumer_group']; return array_merge_recursive($topicData, self::convertConfigAttributes($consumer)); } From cc0d3ec4a6e64c5b2eb7810ccbc9ffa1536a4691 Mon Sep 17 00:00:00 2001 From: hcdias Date: Fri, 1 Apr 2022 16:09:05 -0300 Subject: [PATCH 44/75] chore: adjust tests to match new config file format --- tests/Integration/ProducerTest.php | 23 +++---- tests/Unit/Connectors/Consumer/ConfigTest.php | 7 ++- .../Unit/Connectors/Consumer/FactoryTest.php | 52 ++++++++++++++++ tests/Unit/Connectors/Producer/ConfigTest.php | 2 - tests/Unit/Console/ConsumerCommandTest.php | 61 ++++++++----------- .../Factories/ConsumerFactoryTest.php | 22 +++---- 6 files changed, 102 insertions(+), 65 deletions(-) diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index 73852c4c..94ab5626 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -68,19 +68,17 @@ public function testShouldRunAProducerAndReceiveMessagesWithALowLevelConsumer(): protected function withoutAuthentication(): void { - config(['kafka.brokers.default.auth' => []]); + config(['service.broker.auth' => []]); } protected function haveAConsumerHandlerConfigured(): void { - config( - ['kafka.topics.default.consumer.consumer_groups.test-consumer-group.handler' => MessageConsumer::class] - ); + config(['kafka.topics.default.consumer.handler' => MessageConsumer::class]); } protected function haveAConsumerPartitionConfigured(): void { - config(['kafka.topics.default.consumer.consumer_groups.test-consumer-group.partition' => -1]); + config(['kafka.topics.default.consumer.partition' => -1]); } protected function runTheConsumer(): void @@ -107,15 +105,12 @@ protected function haveALowLevelConsumerConfigured(): void 'topic_id' => 'low_level', 'broker' => 'default', 'consumer' => [ - 'consumer_groups' => [ - 'test-consumer-group' => [ - 'offset_reset' => 'earliest', - 'offset' => 0, - 'handler' => MessageConsumer::class, - 'timeout' => 20000, - 'middlewares' => [], - ], - ], + 'consumer_group' => 'test-consumer-group', + 'offset_reset' => 'earliest', + 'offset' => 0, + 'handler' => MessageConsumer::class, + 'timeout' => 20000, + 'middlewares' => [], ], 'producer' => [ 'required_acknowledgment' => true, diff --git a/tests/Unit/Connectors/Consumer/ConfigTest.php b/tests/Unit/Connectors/Consumer/ConfigTest.php index 539b6ea0..ffeaf5cd 100644 --- a/tests/Unit/Connectors/Consumer/ConfigTest.php +++ b/tests/Unit/Connectors/Consumer/ConfigTest.php @@ -8,6 +8,7 @@ use Mockery as m; use Tests\LaravelTestCase; use Tests\Unit\Dummies\ConsumerHandlerDummy; +use TypeError; class ConfigTest extends LaravelTestCase { @@ -104,8 +105,10 @@ public function testShouldNotSetRuntimeConfigWhenOptionsIsInvalid(): void 'consumer_group' => 'default', ]; + // Expectations + $this->expectException(TypeError::class); + // Actions - $this->expectException(ConfigurationException::class); $configManager = $config->make($options, $arguments); // Assertions @@ -115,7 +118,7 @@ public function testShouldNotSetRuntimeConfigWhenOptionsIsInvalid(): void public function testShouldNotSetRuntimeConfigWhenKafkaConfigIsInvalid(): void { // Set - config(['kafka.brokers.default.connections' => null]); + config(['service.broker' => null]); $config = new Config(); $options = [ 'partition' => 0, diff --git a/tests/Unit/Connectors/Consumer/FactoryTest.php b/tests/Unit/Connectors/Consumer/FactoryTest.php index ae3dedf6..2ccb9cd9 100644 --- a/tests/Unit/Connectors/Consumer/FactoryTest.php +++ b/tests/Unit/Connectors/Consumer/FactoryTest.php @@ -50,6 +50,8 @@ protected function setUp(): void public function testItMakesManagerWithLowLevelConsumer(): void { // Set + $this->haveAConsumerWithPartitionConfigured(); + $config = new Config(); $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'with-partition']); $manager = Factory::make($configConsumer); @@ -61,6 +63,7 @@ public function testItMakesManagerWithLowLevelConsumer(): void public function testItMakesManagerWithHighLevelConsumerWhenPartitionIsNotValid(): void { // Set + $this->haveAConsumerWithoutPartitionConfigured(); $config = new Config(); $configConsumer = $config->make(['timeout' => 61, 'partition' => -1], ['topic' => 'topic_key', 'consumer_group' => 'with-partition']); $manager = Factory::make($configConsumer); @@ -72,6 +75,7 @@ public function testItMakesManagerWithHighLevelConsumerWhenPartitionIsNotValid() public function testItMakesHighLevelClass(): void { // Set + $this->haveAConsumerWithoutPartitionConfigured(); $config = new Config(); $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'without-partition']); $manager = Factory::make($configConsumer); @@ -79,4 +83,52 @@ public function testItMakesHighLevelClass(): void // Assertions $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); } + + private function haveAConsumerWithPartitionConfigured() + { + config([ + 'kafka' => [ + 'topics' => [ + 'topic_key' => [ + 'topic_id' => 'topic_name', + 'consumer' => [ + 'consumer_group' => 'with-partition', + 'offset_reset' => 'earliest', + 'offset' => 0, + 'partition' => 0, + 'handler' => ConsumerHandlerDummy::class, + ], + ], + ], + ], + 'service' => [ + 'broker' => [ + 'connections' => 'kafka:123', + ], + ], + ]); + } + + private function haveAConsumerWithoutPartitionConfigured() + { + config([ + 'kafka' => [ + 'topics' => [ + 'topic_key' => [ + 'topic_id' => 'topic_name', + 'consumer' => [ + 'consumer_group' => 'without-partition', + 'offset_reset' => 'earliest', + 'handler' => ConsumerHandlerDummy::class, + ], + ], + ], + ], + 'service' => [ + 'broker' => [ + 'connections' => 'kafka:123', + ], + ], + ]); + } } diff --git a/tests/Unit/Connectors/Producer/ConfigTest.php b/tests/Unit/Connectors/Producer/ConfigTest.php index 82adae08..d60567e1 100644 --- a/tests/Unit/Connectors/Producer/ConfigTest.php +++ b/tests/Unit/Connectors/Producer/ConfigTest.php @@ -24,7 +24,6 @@ public function testShouldValidateProducerConfig(): void 'max_poll_records' => 500, 'flush_attempts' => 10, 'partition' => -1, - 'broker' => 'default', 'topic' => 'default', 'connections' => env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'), 'auth' => [ @@ -70,7 +69,6 @@ public function testShouldNotOverrideDefaultParametersWhenConfigIsSet(): void 'required_acknowledgment' => true, 'max_poll_records' => 3000, 'flush_attempts' => 10, - 'broker' => 'default', 'topic' => 'default', 'connections' => env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'), 'auth' => [ diff --git a/tests/Unit/Console/ConsumerCommandTest.php b/tests/Unit/Console/ConsumerCommandTest.php index 26132745..5a5a8fcf 100644 --- a/tests/Unit/Console/ConsumerCommandTest.php +++ b/tests/Unit/Console/ConsumerCommandTest.php @@ -10,6 +10,33 @@ class ConsumerCommandTest extends LaravelTestCase { + protected function setUp(): void + { + parent::setUp(); + + config([ + 'kafka' => [ + 'topics' => [ + 'topic_key' => [ + 'topic_id' => 'topic_name', + 'consumer' => [ + 'consumer_group' => 'default', + 'offset_reset' => 'earliest', + 'handler' => ConsumerHandlerDummy::class, + 'timeout' => 123, + ], + ], + ], + ], + 'service' => [ + 'broker' => [ + 'connections' => 'test_kafka:6680', + 'auth' => [], + ], + ], + ]); + } + public function testItCallsCommandWithInvalidTopic(): void { // Set @@ -131,38 +158,4 @@ public function testItOverridesBrokerConnectionWhenCallingCommand(): void $this->artisan($command, $parameters); } - - protected function setUp(): void - { - parent::setUp(); - - config([ - 'kafka' => [ - 'brokers' => [ - 'default' => [ - 'connections' => env( - 'KAFKA_BROKER_CONNECTIONS', - 'kafka:9092' - ), - 'auth' => [], - ], - ], - 'topics' => [ - 'topic_key' => [ - 'topic_id' => 'topic_name', - 'broker' => 'default', - 'consumer' => [ - 'consumer_groups' => [ - 'default' => [ - 'offset_reset' => 'earliest', - 'handler' => ConsumerHandlerDummy::class, - 'timeout' => 123, - ], - ], - ], - ], - ], - ], - ]); - } } diff --git a/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php b/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php index f5c07f80..02aa3368 100644 --- a/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php +++ b/tests/Unit/TopicHandler/ConfigOptions/Factories/ConsumerFactoryTest.php @@ -33,20 +33,16 @@ public function testShouldMakeConfigOptionWithAvroSchema(): void ]; $topicData = [ 'topic_id' => 'kafka-test', - 'consumer_group' => 'test-consumer-group', 'consumer' => [ - 'consumer_groups' => [ - 'test-consumer-group' => [ - 'middlewares' => [], - 'auto_commit' => true, - 'commit_async' => true, - 'offset_reset' => 'earliest', - 'handler' => '\App\Kafka\Consumers\ConsumerExample', - 'partition' => 0, - 'offset' => 0, - 'timeout' => 20000, - ], - ], + 'consumer_group' => 'test-consumer-group', + 'middlewares' => [], + 'auto_commit' => true, + 'commit_async' => true, + 'offset_reset' => 'earliest', + 'handler' => '\App\Kafka\Consumers\ConsumerExample', + 'partition' => 0, + 'offset' => 0, + 'timeout' => 20000, ], ]; $expected = [ From 4c1e0a432f6c04aa42e6e563303353c5ee6ac454 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 15:51:49 -0300 Subject: [PATCH 45/75] chore: update docs --- CHANGELOG.md | 25 ++----- docs/advanced.md | 35 ++++++--- docs/quick-usage.md | 179 +++++++++++++++++++++++--------------------- 3 files changed, 124 insertions(+), 115 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32abee8f..009e3b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,36 +9,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- - -### Fixed - -- - -### Changed - -- - -### Removed -- Remove deprecated class AbstractHandler - -## [4.1.0] - 2022-03-23 - -### Added +- Added file `config/service.php` to configure broker and authentication - Added AvroSchemaMixedEncoderTest - Added AvroSchemaDecoderTest - Added ProducerWithConfigOptionsTest - Added ConfigOptionsCommand to run commands with ConfigOptions class - Added pt_BR contributing section - Added setup-dev script on composer -- Added grumphp commit validation +- Added grumphp commit validation + +### Fixed -### Fixed - Fixed parameters and options override on Consumer\Config class - Update instructions on contribute section - Update project install section ### Changed + - Updated class from ConfigManager to ConfigOptions on unit tests - Updated class from ConfigManager to ConfigOptions where any config request was made - Consumer and Producer middlewares resolution + +### Removed diff --git a/docs/advanced.md b/docs/advanced.md index f290b06c..acca8234 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -275,29 +275,42 @@ stdout_logfile=/var/log/default/kafka-consumer-price-update.log Although you can run this simple command, it provides some options you can pass to make it more flexible to your needs. -- `--broker=` - - Sometimes, you may want to change which broker the consumer should connect to (maybe for testing/debug purposes). - For that, you just nedd to call the `--broker` option with another broker connection key already set in the `config/kafka.php` file. - - `$ php artisan kafka:consume price-update --broker='some-other-broker'` - `--offset=` And if you need to start the consumption of a topic in a specific offset (it can be useful for debug purposes) you can pass the `--offset=` option, but for this, it will be required to specify the partition too. - `$ php artisan kafka:consume price-update --partition=2 --offset=34` + + $ php artisan kafka:consume price-update --partition=2 --offset=34 + - `--partition=` - If you wish do specify in which partition the consumer must be attached, you can set the option `--partition=`. + Set in which partition the consumer must be attached. + + + $ php artisan kafka:consume price-update --partition=2 --offset=34 - `$ php artisan kafka:consume price-update --partition=2 --offset=34` - `--timeout=` - You can specify what would be the timeout for the consumer, by using the `--timeout=` option, the time is in milliseconds. + Set the timeout for the consumer in milliseconds. + + + $ php artisan kafka:consume price-update --timeout=23000 + + +- `--config_name=` + + Specify from what file topics configuration should be read. + + + $ php artisan kafka:consume topic-name --config_name=config.file + + +- `--service_name=` - `$ php artisan kafka:consume price-update --timeout=23000` + Specify from what file services configurations should be read. + `$ php artisan kafka:consume price-update --service_name=config.file` diff --git a/docs/quick-usage.md b/docs/quick-usage.md index 3d003da4..7fd95905 100644 --- a/docs/quick-usage.md +++ b/docs/quick-usage.md @@ -8,76 +8,104 @@ - [Produce Message](#produce-message) -### Config file: `config/kafka.php` - -The config file holds all information about brokers, topics, consumer groups and middlewares. - -To quickly start using, we can focus in two sections: -- Brokers - - An array of brokers, with connection and authentication configurations: - - - `connections`: *required*. can be a `string` with multiple connections separated by comma or an `array` of connections (as `string`) - - - `auth`: *optional*. out of the box, the package can connect with SSL Authentication only or without any authentication - - ```php - 'brokers' => [ - 'price_brokers' => [ - 'connections' => 'localhost:8091,localhost:8092', - 'auth' => [ - 'type' => 'ssl', - 'ca' => storage_path('ca.pem'), - 'certificate' => storage_path('kafka.cert'), - 'key' => storage_path('kafka.key'), - ], - ], - 'stock_brokers' => [ - 'connections' => ['localhost:8091', 'localhost:8092'], - 'auth' => [], // can be an empty array or even don't have this key in the broker config - ], - ], - ``` - -- Topics - - An array of topics configuration, such as the topic name, which broker connection should use, consumer groups and middlewares. - - Here we can specify the group consumers, each topic can have multiple groups, - and each group holds the configuration for which consumer, offset_reset (for setting initial offset) and middleware it must use. - - ```php - 'topics' => [ - 'price_update' => [ - 'topic' => 'products.price.update', - 'broker' => 'price_brokers', - 'consumer_groups' => [ - 'default' => [ - 'offset_reset' => 'smallest', - 'handler' => '\App\Kafka\Consumers\PriceUpdateConsumer', - ], - ], - ], - ], - ``` +### Configure using files + +To get started using configuration files, at least two files are needed. A file to keep the topics +configuration and a file to keep the broker and schema configuration. In this example, we will use the files `config/kafka.php` and `config/service.php`. + +### File `config/kafka.php`: + +This file keeps configurations about topics, consumers and producers. +It should return an array of topics containing the topic name, topic_id, consumer, producer and the settings for each one of them: + + +```php + [ + 'this_is_your_topic_name' => [ + 'topic_id' => "this_is_your_topic_id", + 'consumer' => [ + 'consumer_group' => 'your-consumer-group', + 'offset_reset' => 'earliest', + 'offset' => 0, + 'partition' => 0, + 'handler' => '\App\Kafka\Consumers\ConsumerExample', + 'timeout' => 20000, + 'auto_commit' => true, + 'commit_async' => false, + 'middlewares' => [], + ], + + 'producer' => [ + 'required_acknowledgment' => true, + 'is_async' => true, + 'max_poll_records' => 500, + 'flush_attempts' => 10, + 'middlewares' => [], + 'timeout' => 10000, + 'partition' => constant('RD_KAFKA_PARTITION_UA') ?? -1, + ], + ] + ], +]; +``` + +### File `config/service.php` + +This file keeps configurations about **broker** and **schema** utilized. + + +```php + [ + 'url' => '', + 'request_options' => [ + 'headers' => [ + 'Authorization' => [ + 'Basic ' . base64_encode( + env('AVRO_SCHEMA_USERNAME').':'.env('AVRO_SCHEMA_PASSWORD') + ), + ], + ], + ], + + 'ssl_verify' => true, + 'username' => 'USERNAME', + 'password' => 'PASSWORD', + ], + + 'broker' => [ + 'connections' => 'kafka:9092', + 'auth' => [ + 'type' => 'ssl', + 'ca' => storage_path('ca.pem'), + 'certificate' => storage_path('kafka.cert'), + 'key' => storage_path('kafka.key'), + ], + ], +]; +``` + ### Consumer -After setting up the required configs, you need to create the consumer, which will handle all records received -from the topic specified in the config. +After setting up the required configuration, you must create a consumer to handle records received +from the specified topic in your configuration. -#### Creating Consumer +#### Creating a Consumer -Creating the consumer is easy as running the following command: +To create a consumer run the following command: ```bash $ php artisan make:kafka-consumer PriceUpdateConsumer ``` -This will create a KafkaConsumer class inside the application, on the app/Kafka/Consumers/ directory - -There, you'll have a handler method, which will send all records from the topic to the Consumer, -also, methods will be available for handling exceptions +This will create a KafkaConsumer class on the app/Kafka/Consumers/ directory with the following +content: ```php use App\Kafka\Consumers\PriceUpdateConsumer; @@ -109,20 +137,19 @@ class PriceUpdateConsumer extends AbstractHandler ``` -#### Running consumer +#### Running the consumer -Now you just need to start consuming the topic. +To start consuming the topic, the simplest way to see it working is by running the kafka:consume command along with the topic name, topic configuration file and service configuration file: -The simplest way to see it working is by running the kafka:consume command along with the topic name -declared in the topics config key: ```bash -$ php artisan kafka:consume price-update +$ php artisan kafka:consume this_is_your_topic_name --config_name=config.file --service_name=service.file ``` This command will run in a `while true`, that means, it will never stop running. But, errors can happen, so we strongly advice you to run this command along with [supervisor](http://supervisord.org/running.html), like this example below: + ```bash [program:kafka-consumer-price-update] process_name=%(program_name)s_%(process_num)02d @@ -137,30 +164,10 @@ stdout_logfile=/var/log/default/kafka-consumer-price-update.log That's it. For more information about usage, middlewares, broker authentication, consumer groups and other advanced topics, please have a look at our [Advanced Usage Guide](advanced.md). - -### Producer - -Producer also required configs, which will produce all records using parameters specified in the config. - -```php - 'brokers' => [ - 'local-dev' => [ - 'connections' => 'kafka:9092', - ], - ], - 'topics' => [ - 'product-updated' => [ - 'topic_id' => 'product_updated', - 'broker' => 'local-dev', - ], - ], -``` ### Produce Message -Creating Producer handler. - -The Producer must extends AbstractHandler class and can be empty. +To create a producer handler, create a class that extends `Metamorphosis\TopicHandler\Producer\AbstractHandler` class: ```php Date: Mon, 4 Apr 2022 15:53:44 -0300 Subject: [PATCH 46/75] chore: update console parameters Added a new option to specify the service file --- src/Connectors/Consumer/Config.php | 2 +- src/Console/ConsumerCommand.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index aabcfd8b..81ba46a6 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -54,7 +54,7 @@ public function makeWithConfigOptions(string $handlerClass, ?int $times = null): public function make(array $options, array $arguments): Consumer { $configName = $options['config_name'] ?? 'kafka'; - $service = $options['service'] ?? 'service'; + $service = $options['service_name'] ?? 'service'; $topicConfig = $this->getTopicConfig($configName, $arguments['topic']); $brokerConfig = $this->getBrokerConfig($service); diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index 5c233db4..93420418 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -34,7 +34,8 @@ class ConsumerCommand extends BaseCommand {--broker= : Override broker connection from config.} {--timeout= : Sets timeout for consumer.} {--times= : Amount of messages to be consumed.} - {--config_name= : Change default name for laravel config file.}'; + {--config_name= : Change default name for laravel config file.} + {--service_name= : Change default name for services config file.}'; public function handle(Config $config) { From c00a633fdabacca084a28ca98ee3cf9cafe2d65c Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 16:10:57 -0300 Subject: [PATCH 47/75] chore: remove unused method --- src/Connectors/Consumer/Config.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index 81ba46a6..33673cae 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -94,18 +94,4 @@ private function getTopicConfig(string $configName, string $topicId): array return $topicConfig; } - - /** - * Sometimes that user may pass `--partition=0` as argument. - * So if we just use array_filter here, this option will - * be removed. - * - * This code makes sure that only null values will be removed. - */ - private function filterValues(array $options = []): array - { - return array_filter($options, function ($value) { - return !is_null($value); - }); - } } From da8228e85aa66afa5ea309f6af7a1551564271de Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 16:46:50 -0300 Subject: [PATCH 48/75] chore: add how to use data objects --- docs/quick-usage.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/quick-usage.md b/docs/quick-usage.md index 7fd95905..f306cba2 100644 --- a/docs/quick-usage.md +++ b/docs/quick-usage.md @@ -1,6 +1,7 @@ ## Quick Usage Guide -- [Config file](#config) +- [Configure with files](#config) +- [Configure using data objects](#config-dto) - [Consumer](#consumer) - [Creating Consumer](#creating-consumer) - [Running](#running-consumer) @@ -90,7 +91,6 @@ return [ ]; ``` - ### Consumer @@ -144,7 +144,7 @@ To start consuming the topic, the simplest way to see it working is by running t ```bash $ php artisan kafka:consume this_is_your_topic_name --config_name=config.file --service_name=service.file -``` +``` This command will run in a `while true`, that means, it will never stop running. But, errors can happen, so we strongly advice you to run this command along with [supervisor](http://supervisord.org/running.html), @@ -162,6 +162,27 @@ redirect_stderr=true stdout_logfile=/var/log/default/kafka-consumer-price-update.log ``` +### Using data objects + +To configure and consume using classes: + +```php + use Metamorphosis\Consumer; + use Metamorphosis\TopicHandler\ConfigOptions\Factories\ConsumerFactory; + + $topic = config('yourConfig.topics.topic-id'); + $broker = config('yourService.broker'); + $avro = config('yourService.avro_schema'); + + $consumerConfiguration = ConsumerFactory::make($broker, $topic, $avro); + $consumer = app(Consumer::class, ['configOptions' => $consumerConfiguration]); + + $consumer->consume(); +``` + + + + That's it. For more information about usage, middlewares, broker authentication, consumer groups and other advanced topics, please have a look at our [Advanced Usage Guide](advanced.md). From fbb9168d057ecf804a7a264bbb52003e53258a43 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 16:48:54 -0300 Subject: [PATCH 49/75] chore: remove blank spaces --- docs/quick-usage.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/quick-usage.md b/docs/quick-usage.md index f306cba2..5178a312 100644 --- a/docs/quick-usage.md +++ b/docs/quick-usage.md @@ -180,9 +180,6 @@ To configure and consume using classes: $consumer->consume(); ``` - - - That's it. For more information about usage, middlewares, broker authentication, consumer groups and other advanced topics, please have a look at our [Advanced Usage Guide](advanced.md). From dba78f53d8eb961821fd7681f9dd04b5086af0d9 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 16:56:07 -0300 Subject: [PATCH 50/75] chore: fix codacy warnings --- CHANGELOG.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 009e3b39..b282caa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,14 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Added file `config/service.php` to configure broker and authentication -- Added AvroSchemaMixedEncoderTest -- Added AvroSchemaDecoderTest -- Added ProducerWithConfigOptionsTest -- Added ConfigOptionsCommand to run commands with ConfigOptions class -- Added pt_BR contributing section -- Added setup-dev script on composer -- Added grumphp commit validation +- Added file `config/service.php` to configure broker and authentication +- Added AvroSchemaMixedEncoderTest +- Added AvroSchemaDecoderTest +- Added ProducerWithConfigOptionsTest +- Added ConfigOptionsCommand to run commands with ConfigOptions class +- Added pt_BR contributing section +- Added setup-dev script on composer +- Added grumphp commit validation ### Fixed From e21ebbd1ab1a59787df49aaaccd77973942a6758 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 17:00:33 -0300 Subject: [PATCH 51/75] chore: fix codacy warnings --- CHANGELOG.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b282caa2..b237f25e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,14 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Added file `config/service.php` to configure broker and authentication -- Added AvroSchemaMixedEncoderTest -- Added AvroSchemaDecoderTest -- Added ProducerWithConfigOptionsTest -- Added ConfigOptionsCommand to run commands with ConfigOptions class -- Added pt_BR contributing section -- Added setup-dev script on composer -- Added grumphp commit validation +- Added AvroSchemaMixedEncoderTest +- Added AvroSchemaDecoderTest +- Added ProducerWithConfigOptionsTest +- Added ConfigOptionsCommand to run commands with ConfigOptions class +- Added pt_BR contributing section +- Added setup-dev script on composer +- Added grumphp commit validation +- Added file `config/service.php` to configure broker and authentication ### Fixed From 3634104c99358d9151d22c775e0e55763e4ed75f Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 17:39:32 -0300 Subject: [PATCH 52/75] docs: add commens explaining parameters --- config/kafka.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/kafka.php b/config/kafka.php index 9e74693b..3e7f0764 100644 --- a/config/kafka.php +++ b/config/kafka.php @@ -2,8 +2,14 @@ return [ 'topics' => [ + // This is your topic "keyword" where you will put all configurations needed + // on this specific topic. 'default' => [ + // The topic id is where you want to send or consume + // your messages from kafka. 'topic_id' => 'kafka-test', + + //your consumer configurations 'consumer' => [ 'consumer_group' => 'test-consumer-group', // Action to take when there is no initial From 472b0c92e78e025aec1a702542dcfb6db9f2144e Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 17:41:06 -0300 Subject: [PATCH 53/75] docs: document finished method --- docs/advanced.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/advanced.md b/docs/advanced.md index acca8234..14e40d1e 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -181,10 +181,17 @@ $ php artisan make:kafka-consumer PriceUpdateHandler This will create a KafkaConsumer class inside the application, on the `app/Kafka/Consumers/` directory. There, you'll have a `handler` method, which will send all records from the topic to the Consumer. -Methods will be available for handling exceptions: + +Available methods: + - `warning` method will be call whenever something not critical is received from the topic. Like a message informing that there's no more records to consume. - - `failure` method will be call whenever something critical happens, like an error to decode the record. + + + - `failure` will be call whenever something critical happens, like an error to decode the record. + + + - `finished` will be call when queue finishes ```php use App\Repository; @@ -230,6 +237,11 @@ class PriceUpdateHandler extends AbstractHandler { // handle failure exception } + + public function finished(): void + { + //handle queue end + } } ``` From cf3c17a21f66fad7529b3ee5c5f96a74d47404c7 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 4 Apr 2022 17:41:52 -0300 Subject: [PATCH 54/75] docs: add anchor to section --- docs/quick-usage.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/quick-usage.md b/docs/quick-usage.md index 5178a312..b2cf9a92 100644 --- a/docs/quick-usage.md +++ b/docs/quick-usage.md @@ -162,7 +162,8 @@ redirect_stderr=true stdout_logfile=/var/log/default/kafka-consumer-price-update.log ``` -### Using data objects + +#### Using data objects To configure and consume using classes: From 984d80ba600d30314f5465e4d0c9c86a615fac3f Mon Sep 17 00:00:00 2001 From: hcdias Date: Tue, 5 Apr 2022 14:34:32 -0300 Subject: [PATCH 55/75] chore: remove blank spaces on docs --- CHANGELOG.md | 2 +- docs/advanced.md | 10 ++++------ docs/quick-usage.md | 2 -- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b237f25e..47140732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added ConfigOptionsCommand to run commands with ConfigOptions class - Added pt_BR contributing section - Added setup-dev script on composer -- Added grumphp commit validation +- Added grumphp commit validation - Added file `config/service.php` to configure broker and authentication ### Fixed diff --git a/docs/advanced.md b/docs/advanced.md index 14e40d1e..686d80ef 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -136,8 +136,7 @@ If you wish, you may set a middleware to run of a topic level or a consumer grou ], ``` -The order matters here, they'll be execute as queue, from the most global scope to the most specific (global scope > topic scope > group_consumers scope). - +The order matters here, they'll execute as queue, from the most global scope to the most specific (global scope > topic scope > group_consumers scope). ### Schemas @@ -245,7 +244,6 @@ class PriceUpdateHandler extends AbstractHandler } ``` - #### Creating Middleware You can create a middleware class, that works between the received data from broker and before being passed into consumers, using the follow command: @@ -287,7 +285,6 @@ stdout_logfile=/var/log/default/kafka-consumer-price-update.log Although you can run this simple command, it provides some options you can pass to make it more flexible to your needs. - - `--offset=` And if you need to start the consumption of a topic in a specific offset (it can be useful for debug purposes) @@ -323,6 +320,7 @@ Although you can run this simple command, it provides some options you can pass - `--service_name=` - Specify from what file services configurations should be read. + Specify from what file services configurations should be read. + - `$ php artisan kafka:consume price-update --service_name=config.file` + $ php artisan kafka:consume price-update --service_name=config.file diff --git a/docs/quick-usage.md b/docs/quick-usage.md index b2cf9a92..88488205 100644 --- a/docs/quick-usage.md +++ b/docs/quick-usage.md @@ -19,7 +19,6 @@ configuration and a file to keep the broker and schema configuration. In this ex This file keeps configurations about topics, consumers and producers. It should return an array of topics containing the topic name, topic_id, consumer, producer and the settings for each one of them: - ```php Date: Tue, 5 Apr 2022 14:50:42 -0300 Subject: [PATCH 56/75] chore: fix codacy --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47140732..101df70f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added pt_BR contributing section - Added setup-dev script on composer - Added grumphp commit validation -- Added file `config/service.php` to configure broker and authentication ### Fixed From f4d12b9d1bd95317f4a790f6341f3e43a3905288 Mon Sep 17 00:00:00 2001 From: Hugo Carvalho Date: Thu, 7 Apr 2022 11:03:20 -0300 Subject: [PATCH 57/75] Update docs/quick-usage.md Apply suggested changes Co-authored-by: Diego Felix --- docs/quick-usage.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/quick-usage.md b/docs/quick-usage.md index 88488205..d6a143c8 100644 --- a/docs/quick-usage.md +++ b/docs/quick-usage.md @@ -12,7 +12,8 @@ ### Configure using files To get started using configuration files, at least two files are needed. A file to keep the topics -configuration and a file to keep the broker and schema configuration. In this example, we will use the files `config/kafka.php` and `config/service.php`. +configuration and a file to keep the broker and schema configuration. In this example, we will use the files +`config/kafka.php` and `config/service.php`. ### File `config/kafka.php`: From dd50c5f6437976c4aa67856970cd07c676f9c049 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 25 Apr 2022 11:10:53 -0300 Subject: [PATCH 58/75] fix(codacy): fix codacy warnings --- CHANGELOG.md | 30 +++-- docs/quick-usage.pt.md | 154 ++++++++++++++++---------- readme.md | 1 + src/Connectors/Consumer/Config.php | 2 +- src/Console/ConfigOptionsCommand.php | 3 +- src/Middlewares/AvroSchemaDecoder.php | 6 - 6 files changed, 109 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 101df70f..342b1ef1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,28 +5,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] - ### Added -- Added AvroSchemaMixedEncoderTest -- Added AvroSchemaDecoderTest -- Added ProducerWithConfigOptionsTest -- Added ConfigOptionsCommand to run commands with ConfigOptions class -- Added pt_BR contributing section -- Added setup-dev script on composer -- Added grumphp commit validation +- Added AvroSchemaMixedEncoderTest +- Added AvroSchemaDecoderTest +- Added ProducerWithConfigOptionsTest +- Added ConfigOptionsCommand to run commands with ConfigOptions class +- Added pt_BR contributing section +- Added setup-dev script on composer +- Added grumphp commit validation ### Fixed -- Fixed parameters and options override on Consumer\Config class -- Update instructions on contribute section -- Update project install section +- Fixed parameters and options override on Consumer\Config class +- Update instructions on contribute section +- Update project install section ### Changed -- Updated class from ConfigManager to ConfigOptions on unit tests -- Updated class from ConfigManager to ConfigOptions where any config request was made -- Consumer and Producer middlewares resolution - -### Removed +- Updated class from ConfigManager to ConfigOptions on unit tests +- Updated class from ConfigManager to ConfigOptions where any config request was made +- Consumer and Producer middlewares resolution diff --git a/docs/quick-usage.pt.md b/docs/quick-usage.pt.md index daf4dbfd..c3e14753 100644 --- a/docs/quick-usage.pt.md +++ b/docs/quick-usage.pt.md @@ -1,64 +1,96 @@ -## Guia rápido +## Quick Usage Guide -- [Arquivo de configuração](#config) -- [Consumer](#consumer) - - [Criando um Consumer](#creating-consumer) - - [Rodando o Consumer](#running-consumer) +- [Configurar usando arquivos](#config) +- [Configurar usando objetos](#config-dto) +- [Consumidor](#consumer) + - [Criando um consumidor](#creating-consumer) + - [Executando um consumidor](#running-consumer) +- [Produtor](#producer) + - [Produzindo mensagens](#produce-message) -### Arquivo de configuração: `config/kafka.php` - -Esse arquivo contém todas as informações sobre *brokers*, tópicos, *consumer groups* e *middlewares*. - -Para começar a usar, podemos focar em duas seções: - -- Brokers - - Uma lista de *brokers*, com configurações de conexão e autenticação. - - - `connections`: *obrigatório*. Pode ser uma `string` com múltiplas conexões separadas por vírgula ou uma `array` de conexões. - - - `auth`: *opcional*. É possivel se conectar sem autenticação ou usando autenticação SSL. - - ```php - 'brokers' => [ - 'price_brokers' => [ - 'connections' => 'localhost:8091,localhost:8092', - 'auth' => [ - 'type' => 'ssl', - 'ca' => storage_path('ca.pem'), - 'certificate' => storage_path('kafka.cert'), - 'key' => storage_path('kafka.key'), - ], - ], - 'stock_brokers' => [ - 'connections' => ['localhost:8091', 'localhost:8092'], - 'auth' => [], // pode ser uma array vazia ou até mesmo não ter essa chave aqui. - ], - ], - ``` - -- Tópicos - - Uma lista de configuração de tópicos, como nome, qual *broker* usar, *consumer group* e *middlewares*. - - Aqui você pode especificar os *consumer groups*. Cada tópico pode ter vários grupos, - e cada grupo tem a sua configuração para cada *consumer*, *offset_reset* (para definir um *offset* inicial) e *middlewares* que devem ser usados. - - ```php - 'topics' => [ - 'price_update' => [ - 'topic' => 'products.price.update', - 'broker' => 'price_brokers', - 'consumer_groups' => [ - 'default' => [ - 'offset_reset' => 'smallest', - 'handler' => '\App\Kafka\Consumers\PriceUpdateConsumer', - ], - ], - ], - ], - ``` +### Configurar usando arquivos + +Para começar a usar arquivos de configuração, são necessários pelo menos dois arquivos. Um arquivo para manter os tópicos +configuração e um arquivo para manter a configuração do broker e do esquema. Neste exemplo, usaremos os arquivos +`config/kafka.php` e `config/service.php`. + + +### Arquivo `config/kafka.php`: + +Este arquivo mantém configurações sobre tópicos, consumidores e produtores. +Deve retornar um array de tópicos contendo o nome do tópico, topic_id, consumidor, produtor e as configurações de cada um deles: + + +```php + [ + 'this_is_your_topic_name' => [ + 'topic_id' => "this_is_your_topic_id", + 'consumer' => [ + 'consumer_group' => 'your-consumer-group', + 'offset_reset' => 'earliest', + 'offset' => 0, + 'partition' => 0, + 'handler' => '\App\Kafka\Consumers\ConsumerExample', + 'timeout' => 20000, + 'auto_commit' => true, + 'commit_async' => false, + 'middlewares' => [], + ], + + 'producer' => [ + 'required_acknowledgment' => true, + 'is_async' => true, + 'max_poll_records' => 500, + 'flush_attempts' => 10, + 'middlewares' => [], + 'timeout' => 10000, + 'partition' => constant('RD_KAFKA_PARTITION_UA') ?? -1, + ], + ] + ], +]; +``` + +### File `config/service.php` + +Esse arquivo possui as configurações de **broker** e **schema** utilizados. + +```php + [ + 'url' => '', + 'request_options' => [ + 'headers' => [ + 'Authorization' => [ + 'Basic ' . base64_encode( + env('AVRO_SCHEMA_USERNAME').':'.env('AVRO_SCHEMA_PASSWORD') + ), + ], + ], + ], + + 'ssl_verify' => true, + 'username' => 'USERNAME', + 'password' => 'PASSWORD', + ], + + 'broker' => [ + 'connections' => 'kafka:9092', + 'auth' => [ + 'type' => 'ssl', + 'ca' => storage_path('ca.pem'), + 'certificate' => storage_path('kafka.cert'), + 'key' => storage_path('kafka.key'), + ], + ], +]; +``` ### Consumer @@ -113,11 +145,11 @@ class PriceUpdateConsumer extends AbstractHandler Agora é só consumir o tópico. -A forma mais simples de ver tudo isso funcionando é rodando o comando `kafka:consume` com o nome do tópico que foi configurado: +Para começar a consumir o tópico, a maneira mais simples de vê-lo funcionando é executando o comando kafka:consume junto com o nome do tópico, arquivo de configuração do tópico e arquivo de configuração do serviço: ```bash -$ php artisan kafka:consume price-update -``` +$ php artisan kafka:consume this_is_your_topic_name --config_name=config.file --service_name=service.file +``` Esse comando rodará em um laço infinito (while true), isso significa que ele nunca irá parar de rodar por conta própria. Mas erros podem acontecer, então, recomendamos fortemente que você execute este comando com o auxílio de um [supervisor](http://supervisord.org/running.html), como no exemplo abaixo: diff --git a/readme.md b/readme.md index 76b81013..9206ab91 100644 --- a/readme.md +++ b/readme.md @@ -15,6 +15,7 @@ - [Installation](#installation) - [Quick Usage Guide](docs/quick-usage.md) - [Advanced Usage Guide](docs/advanced.md) +- [Upgrade Guide](docs/upgrade.md) - [Contributing](docs/CONTRIBUTING.md) - [License](#license) diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index 33673cae..fd74f86c 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -40,7 +40,7 @@ class Config extends AbstractConfig 'middlewares' => 'array', ]; - public function makeWithConfigOptions(string $handlerClass, ?int $times = null): ?Consumer + public function makeWithConfigOptions(string $handlerClass): ?Consumer { $handler = app($handlerClass); $configOptions = $handler->getConfigOptions(); diff --git a/src/Console/ConfigOptionsCommand.php b/src/Console/ConfigOptionsCommand.php index eb4c1071..c65bf454 100644 --- a/src/Console/ConfigOptionsCommand.php +++ b/src/Console/ConfigOptionsCommand.php @@ -2,7 +2,6 @@ namespace Metamorphosis\Console; use Illuminate\Console\Command as BaseCommand; -use Metamorphosis\Connectors\Consumer\Config; use Metamorphosis\Connectors\Consumer\Factory; use Metamorphosis\Consumers\Runner; use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConfigOptions; @@ -26,7 +25,7 @@ class ConfigOptionsCommand extends BaseCommand {handler : handler.} {--times= : Amount of messages to be consumed.}'; - public function handle(Config $config) + public function handle() { $consumerHandler = app($this->argument('handler')); diff --git a/src/Middlewares/AvroSchemaDecoder.php b/src/Middlewares/AvroSchemaDecoder.php index 1aeffcff..d7a39f90 100644 --- a/src/Middlewares/AvroSchemaDecoder.php +++ b/src/Middlewares/AvroSchemaDecoder.php @@ -7,18 +7,12 @@ use Metamorphosis\Avro\Serializer\MessageDecoder; use Metamorphosis\Exceptions\ConfigurationException; use Metamorphosis\Record\RecordInterface; -use Metamorphosis\TopicHandler\ConfigOptions\AvroSchema; use Metamorphosis\TopicHandler\ConfigOptions\Consumer as ConsumerConfigOptions; class AvroSchemaDecoder implements MiddlewareInterface { private MessageDecoder $decoder; - /** - * @var AvroSchema - */ - private $avroSchema; - public function __construct(ClientFactory $factory, ConsumerConfigOptions $consumerConfigOptions) { if (!$consumerConfigOptions->getAvroSchema()->getUrl()) { From 4b6b0bab0ff0f01e338de82e1c1f964ebac242ed Mon Sep 17 00:00:00 2001 From: hcdias Date: Tue, 3 May 2022 16:12:16 -0300 Subject: [PATCH 59/75] docs: add upgrade guide --- docs/upgrade.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 docs/upgrade.md diff --git a/docs/upgrade.md b/docs/upgrade.md new file mode 100644 index 00000000..5c4ef6fe --- /dev/null +++ b/docs/upgrade.md @@ -0,0 +1,76 @@ + +## Upgrade guide + +To upgrade from version X.x to version X.y: + +Move your `avroschema` and `broker` section from old `config/kafka.php` file into a new file: + + +```php + [ + 'this_is_your_topic_name' => [ + 'topic_id' => "this_is_your_topic_id", + 'consumer' => [ + 'consumer_group' => 'your-consumer-group', + 'offset_reset' => 'earliest', + 'offset' => 0, + 'partition' => 0, + 'handler' => '\App\Kafka\Consumers\ConsumerExample', + 'timeout' => 20000, + 'auto_commit' => true, + 'commit_async' => false, + 'middlewares' => [], + ], + + 'producer' => [ + 'required_acknowledgment' => true, + 'is_async' => true, + 'max_poll_records' => 500, + 'flush_attempts' => 10, + 'middlewares' => [], + 'timeout' => 10000, + 'partition' => constant('RD_KAFKA_PARTITION_UA') ?? -1, + ], + ] + ], +]; +``` + +Upgrade your topic configuration files: + +```php + [ + 'this_is_your_topic_name' => [ + 'topic_id' => "this_is_your_topic_id", + 'consumer' => [ + 'consumer_group' => 'your-consumer-group', + 'offset_reset' => 'earliest', + 'offset' => 0, + 'partition' => 0, + 'handler' => '\App\Kafka\Consumers\ConsumerExample', + 'timeout' => 20000, + 'auto_commit' => true, + 'commit_async' => false, + 'middlewares' => [], + ], + + 'producer' => [ + 'required_acknowledgment' => true, + 'is_async' => true, + 'max_poll_records' => 500, + 'flush_attempts' => 10, + 'middlewares' => [], + 'timeout' => 10000, + 'partition' => constant('RD_KAFKA_PARTITION_UA') ?? -1, + ], + ] + ], +]; +``` + From c1ca85a9054e04abd0c6ec2cebb22c6097ae9b8e Mon Sep 17 00:00:00 2001 From: hcdias Date: Wed, 5 Apr 2023 18:48:45 -0300 Subject: [PATCH 60/75] fix: add handleMiddlewares method --- src/Connectors/Consumer/Config.php | 8 ++++++++ tests/Unit/AbstractConfigManagerTest.php | 0 2 files changed, 8 insertions(+) delete mode 100644 tests/Unit/AbstractConfigManagerTest.php diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index fd74f86c..f868a2cb 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -94,4 +94,12 @@ private function getTopicConfig(string $configName, string $topicId): array return $topicConfig; } + + private function getMiddlewares(string $configName, array $topicConfig): array + { + return array_merge( + config($configName . '.middlewares.consumer', []), + $topicConfig['consumer']['middlewares'] ?? [] + ); + } } diff --git a/tests/Unit/AbstractConfigManagerTest.php b/tests/Unit/AbstractConfigManagerTest.php deleted file mode 100644 index e69de29b..00000000 From ba3a99c3f5acea1fcff65548c31592df9adbfc4e Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 14:01:28 -0300 Subject: [PATCH 61/75] style: fix coding standard violations Signed-off-by: hcdias --- config/service.php | 6 ++- src/Authentication/Factory.php | 10 ++++- src/Authentication/SASLAuthentication.php | 10 ++--- src/Authentication/SSLAuthentication.php | 10 ++--- src/Connectors/AbstractConfig.php | 9 +++-- src/Connectors/Consumer/Config.php | 6 ++- src/Connectors/Consumer/Factory.php | 39 +++++++++++++------ src/Connectors/Consumer/LowLevel.php | 15 +++++-- src/Connectors/Producer/Connector.php | 6 ++- src/Console/ConfigOptionsCommand.php | 7 ++-- src/Console/ConsumerCommand.php | 6 +-- src/MetamorphosisServiceProvider.php | 8 ++-- src/Middlewares/AvroSchemaDecoder.php | 8 +++- src/Middlewares/AvroSchemaMixedEncoder.php | 25 +++++++----- src/Producer.php | 28 ++++++++++--- .../Factories/ConsumerFactory.php | 5 ++- .../Producer/AbstractProducer.php | 2 +- 17 files changed, 137 insertions(+), 63 deletions(-) diff --git a/config/service.php b/config/service.php index 82cb1299..64f81077 100644 --- a/config/service.php +++ b/config/service.php @@ -6,8 +6,10 @@ 'request_options' => [ 'headers' => [ 'Authorization' => [ - 'Basic '.base64_encode( - env('AVRO_SCHEMA_USERNAME').':'.env('AVRO_SCHEMA_PASSWORD') + 'Basic' . base64_encode( + env('AVRO_SCHEMA_USERNAME') . ':' . env( + 'AVRO_SCHEMA_PASSWORD' + ) ), ], ], diff --git a/src/Authentication/Factory.php b/src/Authentication/Factory.php index c8a8f38a..55fb7053 100644 --- a/src/Authentication/Factory.php +++ b/src/Authentication/Factory.php @@ -24,11 +24,17 @@ public static function authenticate(Conf $conf, AuthInterface $configOptions): v break; case self::TYPE_SSL: - app(SSLAuthentication::class, compact('conf', 'configOptions')); + app( + SSLAuthentication::class, + compact('conf', 'configOptions') + ); break; case self::TYPE_SASL_SSL: - app(SASLAuthentication::class, compact('conf', 'configOptions')); + app( + SASLAuthentication::class, + compact('conf', 'configOptions') + ); break; default: diff --git a/src/Authentication/SASLAuthentication.php b/src/Authentication/SASLAuthentication.php index 3918558d..f4a0e3b0 100644 --- a/src/Authentication/SASLAuthentication.php +++ b/src/Authentication/SASLAuthentication.php @@ -9,10 +9,7 @@ class SASLAuthentication implements AuthenticationInterface { private Conf $conf; - /** - * @var SaslSsl - */ - private $configOptions; + private SaslSsl $configOptions; public function __construct(Conf $conf, SaslSsl $configOptions) { @@ -29,7 +26,10 @@ private function authenticate(): void // The mechanisms key is optional when configuring this kind of authentication // If the user does not specify the mechanism, the default will be 'PLAIN'. // But, to make config more clear, we are asking the user every time. - $this->conf->set('sasl.mechanisms', $this->configOptions->getMechanisms()); + $this->conf->set( + 'sasl.mechanisms', + $this->configOptions->getMechanisms() + ); $this->conf->set('sasl.username', $this->configOptions->getUsername()); $this->conf->set('sasl.password', $this->configOptions->getPassword()); } diff --git a/src/Authentication/SSLAuthentication.php b/src/Authentication/SSLAuthentication.php index 5dfc06e4..e698dfe5 100644 --- a/src/Authentication/SSLAuthentication.php +++ b/src/Authentication/SSLAuthentication.php @@ -9,10 +9,7 @@ class SSLAuthentication implements AuthenticationInterface { private Conf $conf; - /** - * @var Ssl - */ - private $configOptions; + private Ssl $configOptions; public function __construct(Conf $conf, Ssl $configOptions) { @@ -26,7 +23,10 @@ private function authenticate(): void { $this->conf->set('security.protocol', $this->configOptions->getType()); $this->conf->set('ssl.ca.location', $this->configOptions->getCa()); - $this->conf->set('ssl.certificate.location', $this->configOptions->getCertificate()); + $this->conf->set( + 'ssl.certificate.location', + $this->configOptions->getCertificate() + ); $this->conf->set('ssl.key.location', $this->configOptions->getKey()); } } diff --git a/src/Connectors/AbstractConfig.php b/src/Connectors/AbstractConfig.php index fa8b8ac1..b71c683c 100644 --- a/src/Connectors/AbstractConfig.php +++ b/src/Connectors/AbstractConfig.php @@ -9,15 +9,18 @@ abstract class AbstractConfig { protected function getBrokerConfig(string $servicesFile): array { - if (!$brokerConfig = config($servicesFile.'.broker')) { - throw new ConfigurationException("Broker configuration not found on '{$servicesFile}'"); + if (!$brokerConfig = config($servicesFile . '.broker')) { + throw new ConfigurationException( + "Broker configuration not found on '{$servicesFile}'" + ); } + return $brokerConfig; } protected function getSchemaConfig(string $servicesFile): array { - return config($servicesFile.'.avro_schema', []); + return config($servicesFile . '.avro_schema', []); } protected function validate(array $config): void diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index f868a2cb..d13976be 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -74,7 +74,11 @@ public function make(array $options, array $arguments): Consumer } } - return ConsumerFactory::make($brokerConfig, $topicConfig, $schemaConfig); + return ConsumerFactory::make( + $brokerConfig, + $topicConfig, + $schemaConfig + ); } /** diff --git a/src/Connectors/Consumer/Factory.php b/src/Connectors/Consumer/Factory.php index c82c4ad2..923fb817 100644 --- a/src/Connectors/Consumer/Factory.php +++ b/src/Connectors/Consumer/Factory.php @@ -26,32 +26,49 @@ public static function make(ConsumerConfigOptions $configOptions): Manager $middlewares = $configOptions->getMiddlewares(); foreach ($middlewares as &$middleware) { - $middleware = is_string($middleware) ? app($middleware, ['consumerConfigOptions' => $configOptions]) : $middleware; + $middleware = is_string($middleware) + ? app( + $middleware, + ['consumerConfigOptions' => $configOptions] + ) + : $middleware; } - $middlewares[] = app(ConsumerMiddleware::class, ['consumerTopicHandler' => $handler]); + $middlewares[] = app( + ConsumerMiddleware::class, + ['consumerTopicHandler' => $handler] + ); $dispatcher = self::getMiddlewareDispatcher($middlewares); - return new Manager($consumer, $handler, $dispatcher, $autoCommit, $commitAsync); - } - - protected static function requiresPartition(ConsumerConfigOptions $configOptions): bool - { - $partition = $configOptions->getPartition(); - - return !is_null($partition) && $partition >= 0; + return new Manager( + $consumer, + $handler, + $dispatcher, + $autoCommit, + $commitAsync + ); } public static function getConsumer(bool $autoCommit, ConsumerConfigOptions $configOptions): ConsumerInterface { if (self::requiresPartition($configOptions)) { - return app(LowLevel::class)->getConsumer($autoCommit, $configOptions); + return app(LowLevel::class)->getConsumer( + $autoCommit, + $configOptions + ); } return app(HighLevel::class)->getConsumer($autoCommit, $configOptions); } + protected static function requiresPartition(ConsumerConfigOptions $configOptions): bool + { + $partition = $configOptions->getPartition(); + + return !is_null($partition) && $partition >= 0; + } + private static function getMiddlewareDispatcher(array $middlewares): Dispatcher { return new Dispatcher($middlewares); diff --git a/src/Connectors/Consumer/LowLevel.php b/src/Connectors/Consumer/LowLevel.php index 7c7395ac..30f4c277 100644 --- a/src/Connectors/Consumer/LowLevel.php +++ b/src/Connectors/Consumer/LowLevel.php @@ -32,9 +32,15 @@ public function getConsumer(bool $autoCommit, ConfigOptions $configOptions): Con $consumer->addBrokers($broker->getConnections()); $topicConf = $this->getTopicConfigs($configOptions); - $topicConsumer = $consumer->newTopic($configOptions->getTopicId(), $topicConf); + $topicConsumer = $consumer->newTopic( + $configOptions->getTopicId(), + $topicConf + ); - $topicConsumer->consumeStart($configOptions->getPartition(), $configOptions->getOffset()); + $topicConsumer->consumeStart( + $configOptions->getPartition(), + $configOptions->getOffset() + ); return new LowLevelConsumer($topicConsumer, $configOptions); } @@ -46,7 +52,10 @@ protected function getTopicConfigs(ConfigOptions $configOptions) // Set where to start consuming messages when there is no initial offset in // offset store or the desired offset is out of range. // 'smallest': start from the beginning - $topicConfig->set('auto.offset.reset', $configOptions->getOffsetReset()); + $topicConfig->set( + 'auto.offset.reset', + $configOptions->getOffsetReset() + ); return $topicConfig; } diff --git a/src/Connectors/Producer/Connector.php b/src/Connectors/Producer/Connector.php index 1109a598..3d427afc 100644 --- a/src/Connectors/Producer/Connector.php +++ b/src/Connectors/Producer/Connector.php @@ -12,8 +12,10 @@ class Connector { - public function getProducerTopic(HandlerInterface $handler, ProducerConfigOptions $producerConfigOptions): KafkaProducer - { + public function getProducerTopic( + HandlerInterface $handler, + ProducerConfigOptions $producerConfigOptions + ): KafkaProducer { $conf = resolve(Conf::class); if ($this->canHandleResponse($handler)) { diff --git a/src/Console/ConfigOptionsCommand.php b/src/Console/ConfigOptionsCommand.php index c65bf454..d592a8b1 100644 --- a/src/Console/ConfigOptionsCommand.php +++ b/src/Console/ConfigOptionsCommand.php @@ -1,4 +1,5 @@ getTopicId().PHP_EOL; - $text .= ' on consumer group: '.$configOptions->getConsumerGroup().PHP_EOL; - $text .= 'Connecting in '.$configOptions->getBroker()->getConnections().PHP_EOL; + $text = 'Starting consumer for topic: ' . $configOptions->getTopicId() . PHP_EOL; + $text .= ' on consumer group: ' . $configOptions->getConsumerGroup() . PHP_EOL; + $text .= 'Connecting in ' . $configOptions->getBroker()->getConnections() . PHP_EOL; $text .= 'Running consumer..'; $this->output->writeln($text); diff --git a/src/Console/ConsumerCommand.php b/src/Console/ConsumerCommand.php index 93420418..ded31d7f 100644 --- a/src/Console/ConsumerCommand.php +++ b/src/Console/ConsumerCommand.php @@ -51,9 +51,9 @@ public function handle(Config $config) private function writeStartingConsumer(Consumer $consumer) { - $text = 'Starting consumer for topic: '.$consumer->getTopicId().PHP_EOL; - $text .= ' on consumer group: '.$consumer->getConsumerGroup().PHP_EOL; - $text .= 'Connecting in '.$consumer->getBroker()->getConnections().PHP_EOL; + $text = 'Starting consumer for topic: ' . $consumer->getTopicId() . PHP_EOL; + $text .= ' on consumer group: ' . $consumer->getConsumerGroup() . PHP_EOL; + $text .= 'Connecting in ' . $consumer->getBroker()->getConnections() . PHP_EOL; $text .= 'Running consumer..'; $this->output->writeln($text); diff --git a/src/MetamorphosisServiceProvider.php b/src/MetamorphosisServiceProvider.php index 36dffdf5..6a64d8c4 100644 --- a/src/MetamorphosisServiceProvider.php +++ b/src/MetamorphosisServiceProvider.php @@ -14,12 +14,12 @@ class MetamorphosisServiceProvider extends ServiceProvider public function boot() { $this->publishes([ - __DIR__.'/../config/kafka.php' => config_path('kafka.php'), - __DIR__.'/../config/service.php' => config_path('service.php'), + __DIR__ . '/../config/kafka.php' => config_path('kafka.php'), + __DIR__ . '/../config/service.php' => config_path('service.php'), ], 'config'); - $this->mergeConfigFrom(__DIR__.'/../config/kafka.php', 'kafka'); - $this->mergeConfigFrom(__DIR__.'/../config/service.php', 'service'); + $this->mergeConfigFrom(__DIR__ . '/../config/kafka.php', 'kafka'); + $this->mergeConfigFrom(__DIR__ . '/../config/service.php', 'service'); } public function register() diff --git a/src/Middlewares/AvroSchemaDecoder.php b/src/Middlewares/AvroSchemaDecoder.php index d7a39f90..07f2193d 100644 --- a/src/Middlewares/AvroSchemaDecoder.php +++ b/src/Middlewares/AvroSchemaDecoder.php @@ -16,10 +16,14 @@ class AvroSchemaDecoder implements MiddlewareInterface public function __construct(ClientFactory $factory, ConsumerConfigOptions $consumerConfigOptions) { if (!$consumerConfigOptions->getAvroSchema()->getUrl()) { - throw new ConfigurationException("Avro schema url not found, it's required to use AvroSchemaDecoder Middleware"); + throw new ConfigurationException( + "Avro schema url not found, it's required to use AvroSchemaDecoder Middleware" + ); } - $this->decoder = new MessageDecoder($factory->make($consumerConfigOptions->getAvroSchema())); + $this->decoder = new MessageDecoder( + $factory->make($consumerConfigOptions->getAvroSchema()) + ); } public function process(RecordInterface $record, Closure $next) diff --git a/src/Middlewares/AvroSchemaMixedEncoder.php b/src/Middlewares/AvroSchemaMixedEncoder.php index 6969a80e..67c09076 100644 --- a/src/Middlewares/AvroSchemaMixedEncoder.php +++ b/src/Middlewares/AvroSchemaMixedEncoder.php @@ -21,18 +21,22 @@ class AvroSchemaMixedEncoder implements MiddlewareInterface private CachedSchemaRegistryClient $schemaRegistry; - /** - * @var ProducerConfigOptions - */ - private $producerConfigOptions; + private ProducerConfigOptions $producerConfigOptions; - public function __construct(SchemaId $schemaIdEncoder, ClientFactory $factory, ProducerConfigOptions $producerConfigOptions) - { + public function __construct( + SchemaId $schemaIdEncoder, + ClientFactory $factory, + ProducerConfigOptions $producerConfigOptions + ) { if (!$producerConfigOptions->getAvroSchema()->getUrl()) { - throw new ConfigurationException("Avro schema url not found, it's required to use AvroSchemaEncoder Middleware"); + throw new ConfigurationException( + "Avro schema url not found, it's required to use AvroSchemaEncoder Middleware" + ); } - $schemaRegistry = $factory->make($producerConfigOptions->getAvroSchema()); + $schemaRegistry = $factory->make( + $producerConfigOptions->getAvroSchema() + ); $this->schemaIdEncoder = $schemaIdEncoder; $this->schemaRegistry = $schemaRegistry; $this->producerConfigOptions = $producerConfigOptions; @@ -41,7 +45,10 @@ public function __construct(SchemaId $schemaIdEncoder, ClientFactory $factory, P public function process(RecordInterface $record, Closure $next) { $topic = $this->producerConfigOptions->getTopicId(); - $schema = $this->schemaRegistry->getBySubjectAndVersion("{$topic}-value", 'latest'); + $schema = $this->schemaRegistry->getBySubjectAndVersion( + "{$topic}-value", + 'latest' + ); $arrayPayload = json_decode($record->getPayload(), true); $encodedPayload = $this->schemaIdEncoder->encode( $schema, diff --git a/src/Producer.php b/src/Producer.php index 4fa9ee5b..b3211f7c 100644 --- a/src/Producer.php +++ b/src/Producer.php @@ -36,20 +36,36 @@ public function build(HandlerInterface $producerHandler): Dispatcher $middlewares = $producerConfigOptions->getMiddlewares(); foreach ($middlewares as &$middleware) { - $middleware = is_string($middleware) ? app($middleware, ['producerConfigOptions' => $producerConfigOptions]) : $middleware; + $middleware = is_string($middleware) + ? app( + $middleware, + ['producerConfigOptions' => $producerConfigOptions] + ) + : $middleware; } - $middlewares[] = $this->getProducerMiddleware($producerHandler, $producerConfigOptions); + $middlewares[] = $this->getProducerMiddleware( + $producerHandler, + $producerConfigOptions + ); return new Dispatcher($middlewares); } - public function getProducerMiddleware(HandlerInterface $producerHandler, ProducerConfigOptions $producerConfigOptions): ProducerMiddleware - { - $producer = $this->connector->getProducerTopic($producerHandler, $producerConfigOptions); + public function getProducerMiddleware( + HandlerInterface $producerHandler, + ProducerConfigOptions $producerConfigOptions + ): ProducerMiddleware { + $producer = $this->connector->getProducerTopic( + $producerHandler, + $producerConfigOptions + ); $topic = $producer->newTopic($producerConfigOptions->getTopicId()); - $poll = app(Poll::class, ['producer' => $producer, 'producerConfigOptions' => $producerConfigOptions]); + $poll = app( + Poll::class, + ['producer' => $producer, 'producerConfigOptions' => $producerConfigOptions] + ); $partition = $producerConfigOptions->getPartition(); return app( diff --git a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php index 4dd62736..2d28a28c 100644 --- a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php +++ b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php @@ -25,7 +25,10 @@ private static function getConsumerGroupConfig(array $topicData): array $consumer = $topicData['consumer']; $topicData['consumerGroup'] = $consumer['consumer_group']; - return array_merge_recursive($topicData, self::convertConfigAttributes($consumer)); + return array_merge_recursive( + $topicData, + self::convertConfigAttributes($consumer) + ); } private static function convertConfigAttributes(array $consumerConfig): array diff --git a/src/TopicHandler/Producer/AbstractProducer.php b/src/TopicHandler/Producer/AbstractProducer.php index 694aedd0..ecab7c93 100644 --- a/src/TopicHandler/Producer/AbstractProducer.php +++ b/src/TopicHandler/Producer/AbstractProducer.php @@ -20,7 +20,7 @@ class AbstractProducer implements HandlerInterface */ protected $producer; - public function __construct($record, Producer $configOptions, string $key = null) + public function __construct($record, Producer $configOptions, ?string $key = null) { $this->record = $record; $this->key = $key; From cfdd4a7af7fbe0b586979422acd63cbdc67db44f Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 14:15:25 -0300 Subject: [PATCH 62/75] style: fix coding standard violations Signed-off-by: hcdias --- tests/Integration/ConsumerTest.php | 5 +- tests/Integration/ProducerTest.php | 38 +++++---- tests/Integration/ProducerWithAvroTest.php | 12 ++- tests/Unit/Authentication/FactoryTest.php | 6 +- .../Authentication/SASLAuthenticationTest.php | 6 +- .../Authentication/SSLAuthenticationTest.php | 6 +- tests/Unit/Connectors/Consumer/ConfigTest.php | 4 +- .../Unit/Connectors/Consumer/FactoryTest.php | 83 ++++++++++--------- .../Connectors/Producer/ConnectorTest.php | 14 +++- tests/Unit/Console/ConsumerCommandTest.php | 54 ++++++------ tests/Unit/Consumers/LowLevelTest.php | 5 +- .../Middlewares/AvroSchemaDecoderTest.php | 10 ++- .../AvroSchemaMixedEncoderTest.php | 32 +++++-- tests/Unit/ProducerTest.php | 10 +-- 14 files changed, 177 insertions(+), 108 deletions(-) diff --git a/tests/Integration/ConsumerTest.php b/tests/Integration/ConsumerTest.php index 1d4397e8..2fb7b1bf 100644 --- a/tests/Integration/ConsumerTest.php +++ b/tests/Integration/ConsumerTest.php @@ -59,7 +59,10 @@ public function testItShouldSetup(): void $saleOrderDispatcher = Metamorphosis::build($messageProducer); $saleOrderDispatcher->handle($messageProducer->createRecord()); - $consumer = $this->app->make(Consumer::class, ['configOptions' => $consumerConfigOptions]); + $consumer = $this->app->make( + Consumer::class, + ['configOptions' => $consumerConfigOptions] + ); $expected = '{"id":"MESSAGE_ID"}'; // Actions diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index 94ab5626..8fbe5305 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -18,22 +18,9 @@ class ProducerTest extends LaravelTestCase protected string $firstLowLevelMessage; - /** - * @var string - */ - protected $secondLowLevelMessage; + protected string $secondLowLevelMessage; - /** - * @var string - */ - protected $topicId; - - protected function setUp(): void - { - parent::setUp(); - $this->withoutAuthentication(); - $this->topicId = 'kafka-test-'.Str::random(5); - } + protected string $topicId; /** * @group runProducer @@ -66,6 +53,14 @@ public function testShouldRunAProducerAndReceiveMessagesWithALowLevelConsumer(): $this->runTheLowLevelConsumerSkippingTheFirstTwoMessagesAndLimitingToTwoMessagesConsumed(); } + protected function setUp(): void + { + parent::setUp(); + + $this->withoutAuthentication(); + $this->topicId = 'kafka-test-' . Str::random(5); + } + protected function withoutAuthentication(): void { config(['service.broker.auth' => []]); @@ -73,7 +68,9 @@ protected function withoutAuthentication(): void protected function haveAConsumerHandlerConfigured(): void { - config(['kafka.topics.default.consumer.handler' => MessageConsumer::class]); + config( + ['kafka.topics.default.consumer.handler' => MessageConsumer::class] + ); } protected function haveAConsumerPartitionConfigured(): void @@ -145,7 +142,9 @@ private function haveSomeRandomMessagesProduced(): void { $this->highLevelMessage = Str::random(10); - $producerConfigOptions = $this->createProducerConfigOptions($this->topicId); + $producerConfigOptions = $this->createProducerConfigOptions( + $this->topicId + ); $producer = app(MessageProducer::class, [ 'record' => $this->highLevelMessage, 'configOptions' => $producerConfigOptions, @@ -158,7 +157,9 @@ private function haveSomeRandomMessagesProduced(): void private function produceRecordMessage(string $record): string { - $producerConfigOptions = $this->createProducerConfigOptions('low_level'); + $producerConfigOptions = $this->createProducerConfigOptions( + 'low_level' + ); $producer = app(MessageProducer::class, [ 'record' => $record, 'configOptions' => $producerConfigOptions, @@ -206,6 +207,7 @@ private function haveFourProducedMessages(): void private function createProducerConfigOptions(string $topicId): ProducerConfigOptions { $broker = new Broker('kafka:9092', new None()); + return new ProducerConfigOptions( $topicId, $broker, diff --git a/tests/Integration/ProducerWithAvroTest.php b/tests/Integration/ProducerWithAvroTest.php index b0c801ad..54793d98 100644 --- a/tests/Integration/ProducerWithAvroTest.php +++ b/tests/Integration/ProducerWithAvroTest.php @@ -22,11 +22,12 @@ class ProducerWithAvroTest extends LaravelTestCase /** * @var string[] */ - protected $records; + protected array $records; public function setUp(): void { parent::setUp(); + $this->records = ['saleOrderId' => 'SALE_ORDER_ID', 'productId' => 'PRODUCT_ID']; } @@ -110,8 +111,12 @@ protected function haveAHandlerConfigured(): void private function haveSomeRandomMessagesProduced(): void { - $producerConfigOptionsSale = $this->createProducerConfigOptions('sale_order'); - $producerConfigOptionsProduct = $this->createProducerConfigOptions('product'); + $producerConfigOptionsSale = $this->createProducerConfigOptions( + 'sale_order' + ); + $producerConfigOptionsProduct = $this->createProducerConfigOptions( + 'product' + ); $saleOrderProducer = app(MessageProducer::class, [ 'record' => ['saleOrderId' => 'SALE_ORDER_ID'], @@ -166,6 +171,7 @@ private function setLogExpectationsFor(string $message): void private function createProducerConfigOptions(string $topicId): ProducerConfigOptions { $broker = new Broker('kafka:9092', new None()); + return new ProducerConfigOptions( $topicId, $broker, diff --git a/tests/Unit/Authentication/FactoryTest.php b/tests/Unit/Authentication/FactoryTest.php index 717abe16..f13b2e46 100644 --- a/tests/Unit/Authentication/FactoryTest.php +++ b/tests/Unit/Authentication/FactoryTest.php @@ -16,7 +16,11 @@ class FactoryTest extends LaravelTestCase public function testItMakesSslAuthenticationClass(): void { // Set - $configOptionsSsl = new Ssl('path/to/ca', 'path/to/certificate', 'path/to/key'); + $configOptionsSsl = new Ssl( + 'path/to/ca', + 'path/to/certificate', + 'path/to/key' + ); $conf = new Conf(); $expected = [ 'security.protocol' => 'ssl', diff --git a/tests/Unit/Authentication/SASLAuthenticationTest.php b/tests/Unit/Authentication/SASLAuthenticationTest.php index f9e9a474..45a4dc3a 100644 --- a/tests/Unit/Authentication/SASLAuthenticationTest.php +++ b/tests/Unit/Authentication/SASLAuthenticationTest.php @@ -12,7 +12,11 @@ class SASLAuthenticationTest extends LaravelTestCase public function testItShouldValidateAuthenticationConfigurations(): void { // Set - $configSaslSsl = new SaslSsl('PLAIN', 'some-username', 'some-password'); + $configSaslSsl = new SaslSsl( + 'PLAIN', + 'some-username', + 'some-password' + ); $conf = new Conf(); $expected = [ diff --git a/tests/Unit/Authentication/SSLAuthenticationTest.php b/tests/Unit/Authentication/SSLAuthenticationTest.php index 35a9168e..9ea6c6b0 100644 --- a/tests/Unit/Authentication/SSLAuthenticationTest.php +++ b/tests/Unit/Authentication/SSLAuthenticationTest.php @@ -13,7 +13,11 @@ public function testItShouldValidateAuthenticationConfigurations(): void { // Set $conf = new Conf(); - $configSsl = new Ssl('path/to/ca', 'path/to/certificate', 'path/to/key'); + $configSsl = new Ssl( + 'path/to/ca', + 'path/to/certificate', + 'path/to/key' + ); $expected = [ 'security.protocol' => 'ssl', 'ssl.ca.location' => 'path/to/ca', diff --git a/tests/Unit/Connectors/Consumer/ConfigTest.php b/tests/Unit/Connectors/Consumer/ConfigTest.php index ffeaf5cd..224f5666 100644 --- a/tests/Unit/Connectors/Consumer/ConfigTest.php +++ b/tests/Unit/Connectors/Consumer/ConfigTest.php @@ -85,7 +85,9 @@ public function testShouldValidateConsumerConfig(): void ]); // Actions - $configManager = $config->makeWithConfigOptions(ConsumerHandlerDummy::class); + $configManager = $config->makeWithConfigOptions( + ConsumerHandlerDummy::class + ); // Assertions $this->assertArraySubset($expected, $configManager->toArray()); diff --git a/tests/Unit/Connectors/Consumer/FactoryTest.php b/tests/Unit/Connectors/Consumer/FactoryTest.php index 2ccb9cd9..fcd1a6d3 100644 --- a/tests/Unit/Connectors/Consumer/FactoryTest.php +++ b/tests/Unit/Connectors/Consumer/FactoryTest.php @@ -11,6 +11,52 @@ class FactoryTest extends LaravelTestCase { + public function testItMakesManagerWithLowLevelConsumer(): void + { + // Set + $this->haveAConsumerWithPartitionConfigured(); + + $config = new Config(); + $configConsumer = $config->make( + ['timeout' => 61], + ['topic' => 'topic_key', 'consumer_group' => 'with-partition'] + ); + $manager = Factory::make($configConsumer); + + // Assertions + $this->assertInstanceOf(LowLevel::class, $manager->getConsumer()); + } + + public function testItMakesManagerWithHighLevelConsumerWhenPartitionIsNotValid(): void + { + // Set + $this->haveAConsumerWithoutPartitionConfigured(); + $config = new Config(); + $configConsumer = $config->make( + ['timeout' => 61, 'partition' => -1], + ['topic' => 'topic_key', 'consumer_group' => 'with-partition'] + ); + $manager = Factory::make($configConsumer); + + // Assertions + $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); + } + + public function testItMakesHighLevelClass(): void + { + // Set + $this->haveAConsumerWithoutPartitionConfigured(); + $config = new Config(); + $configConsumer = $config->make( + ['timeout' => 61], + ['topic' => 'topic_key', 'consumer_group' => 'without-partition'] + ); + $manager = Factory::make($configConsumer); + + // Assertions + $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); + } + protected function setUp(): void { parent::setUp(); @@ -47,43 +93,6 @@ protected function setUp(): void ]); } - public function testItMakesManagerWithLowLevelConsumer(): void - { - // Set - $this->haveAConsumerWithPartitionConfigured(); - - $config = new Config(); - $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'with-partition']); - $manager = Factory::make($configConsumer); - - // Assertions - $this->assertInstanceOf(LowLevel::class, $manager->getConsumer()); - } - - public function testItMakesManagerWithHighLevelConsumerWhenPartitionIsNotValid(): void - { - // Set - $this->haveAConsumerWithoutPartitionConfigured(); - $config = new Config(); - $configConsumer = $config->make(['timeout' => 61, 'partition' => -1], ['topic' => 'topic_key', 'consumer_group' => 'with-partition']); - $manager = Factory::make($configConsumer); - - // Assertions - $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); - } - - public function testItMakesHighLevelClass(): void - { - // Set - $this->haveAConsumerWithoutPartitionConfigured(); - $config = new Config(); - $configConsumer = $config->make(['timeout' => 61], ['topic' => 'topic_key', 'consumer_group' => 'without-partition']); - $manager = Factory::make($configConsumer); - - // Assertions - $this->assertInstanceOf(HighLevel::class, $manager->getConsumer()); - } - private function haveAConsumerWithPartitionConfigured() { config([ diff --git a/tests/Unit/Connectors/Producer/ConnectorTest.php b/tests/Unit/Connectors/Producer/ConnectorTest.php index f456dfb7..2869318b 100644 --- a/tests/Unit/Connectors/Producer/ConnectorTest.php +++ b/tests/Unit/Connectors/Producer/ConnectorTest.php @@ -33,7 +33,7 @@ public function testItShouldMakeSetup(): void $producerConfigOptions = m::mock(ProducerConfigOptions::class); $connector = new Connector(); - $handler = new class('record', $producerConfigOptions) extends AbstractProducer implements HandleableResponseInterface { + $handler = new class ('record', $producerConfigOptions) extends AbstractProducer implements HandleableResponseInterface { public function success(Message $message): void { } @@ -57,7 +57,10 @@ public function failed(Message $message): void ->andReturn($broker); // Actions - $result = $connector->getProducerTopic($handler, $producerConfigOptions); + $result = $connector->getProducerTopic( + $handler, + $producerConfigOptions + ); // Assertions $this->assertInstanceOf(KafkaProducer::class, $result); @@ -79,7 +82,7 @@ public function testItShouldMakeSetupWithoutHandleResponse(): void $producerConfigOptions = m::mock(ProducerConfigOptions::class); $connector = new Connector(); - $handler = new class('record', $producerConfigOptions) extends AbstractProducer implements HandlerInterface { + $handler = new class ('record', $producerConfigOptions) extends AbstractProducer implements HandlerInterface { public function success(Message $message): void { } @@ -102,7 +105,10 @@ public function failed(Message $message): void ->andReturn($broker); // Actions - $result = $connector->getProducerTopic($handler, $producerConfigOptions); + $result = $connector->getProducerTopic( + $handler, + $producerConfigOptions + ); // Assertions $this->assertInstanceOf(KafkaProducer::class, $result); diff --git a/tests/Unit/Console/ConsumerCommandTest.php b/tests/Unit/Console/ConsumerCommandTest.php index 5a5a8fcf..c4737533 100644 --- a/tests/Unit/Console/ConsumerCommandTest.php +++ b/tests/Unit/Console/ConsumerCommandTest.php @@ -10,33 +10,6 @@ class ConsumerCommandTest extends LaravelTestCase { - protected function setUp(): void - { - parent::setUp(); - - config([ - 'kafka' => [ - 'topics' => [ - 'topic_key' => [ - 'topic_id' => 'topic_name', - 'consumer' => [ - 'consumer_group' => 'default', - 'offset_reset' => 'earliest', - 'handler' => ConsumerHandlerDummy::class, - 'timeout' => 123, - ], - ], - ], - ], - 'service' => [ - 'broker' => [ - 'connections' => 'test_kafka:6680', - 'auth' => [], - ], - ], - ]); - } - public function testItCallsCommandWithInvalidTopic(): void { // Set @@ -158,4 +131,31 @@ public function testItOverridesBrokerConnectionWhenCallingCommand(): void $this->artisan($command, $parameters); } + + protected function setUp(): void + { + parent::setUp(); + + config([ + 'kafka' => [ + 'topics' => [ + 'topic_key' => [ + 'topic_id' => 'topic_name', + 'consumer' => [ + 'consumer_group' => 'default', + 'offset_reset' => 'earliest', + 'handler' => ConsumerHandlerDummy::class, + 'timeout' => 123, + ], + ], + ], + ], + 'service' => [ + 'broker' => [ + 'connections' => 'test_kafka:6680', + 'auth' => [], + ], + ], + ]); + } } diff --git a/tests/Unit/Consumers/LowLevelTest.php b/tests/Unit/Consumers/LowLevelTest.php index b39ac2aa..e2347b60 100644 --- a/tests/Unit/Consumers/LowLevelTest.php +++ b/tests/Unit/Consumers/LowLevelTest.php @@ -36,7 +36,10 @@ public function testItShouldConsume(): void $consumerTopic = m::mock(ConsumerTopic::class); $message = new Message(); - $lowLevelConsumer = new LowLevel($consumerTopic, $consumerConfigOptions); + $lowLevelConsumer = new LowLevel( + $consumerTopic, + $consumerConfigOptions + ); // Expectations $consumerTopic->expects() diff --git a/tests/Unit/Middlewares/AvroSchemaDecoderTest.php b/tests/Unit/Middlewares/AvroSchemaDecoderTest.php index 6c8d31b0..ba9edd29 100644 --- a/tests/Unit/Middlewares/AvroSchemaDecoderTest.php +++ b/tests/Unit/Middlewares/AvroSchemaDecoderTest.php @@ -1,4 +1,5 @@ getAvroSchema() ->andReturn($avroSchema); - $avroSchemaDecoder = new AvroSchemaDecoder($clientFactory, $consumerConfigOptions); + $avroSchemaDecoder = new AvroSchemaDecoder( + $clientFactory, + $consumerConfigOptions + ); $result = $avroSchemaDecoder->process($consumerRecord, $closure); diff --git a/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php b/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php index fcff2d6c..7fc33c0f 100644 --- a/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php +++ b/tests/Unit/Middlewares/AvroSchemaMixedEncoderTest.php @@ -1,4 +1,5 @@ getAvroSchema(); $clientFactory = m::mock(ClientFactory::class); - $cachedSchemaRegistryClient = m::mock(CachedSchemaRegistryClient::class); - $schemaIdEncoder = m::mock(SchemaId::class, [$cachedSchemaRegistryClient]); + $cachedSchemaRegistryClient = m::mock( + CachedSchemaRegistryClient::class + ); + $schemaIdEncoder = m::mock( + SchemaId::class, + [$cachedSchemaRegistryClient] + ); $schema = new Schema(); - $parsedSchema = $schema->parse($avroSchema, '123', 'kafka-test-value', 'latest'); + $parsedSchema = $schema->parse( + $avroSchema, + '123', + 'kafka-test-value', + 'latest' + ); $record = $this->getRecord($parsedSchema->getAvroSchema()); $producerRecord = new ProducerRecord($record, 'kafka-test'); @@ -62,7 +76,11 @@ public function testShouldEncodeRecord() ->andReturn($encodedMessage); // Actions - $avroSchemaMixedEncoder = new AvroSchemaMixedEncoder($schemaIdEncoder, $clientFactory, $producerConfigOptions); + $avroSchemaMixedEncoder = new AvroSchemaMixedEncoder( + $schemaIdEncoder, + $clientFactory, + $producerConfigOptions + ); $result = $avroSchemaMixedEncoder->process($producerRecord, $closure); // Assertions @@ -93,6 +111,8 @@ private function getRecord(AvroSchema $avroSchema): string private function getSchemaFixture(): string { - return file_get_contents(__DIR__.'/../fixtures/schemas/sales_price.avsc'); + return file_get_contents( + __DIR__ . '/../fixtures/schemas/sales_price.avsc' + ); } } diff --git a/tests/Unit/ProducerTest.php b/tests/Unit/ProducerTest.php index 02808390..61f43155 100644 --- a/tests/Unit/ProducerTest.php +++ b/tests/Unit/ProducerTest.php @@ -41,7 +41,7 @@ public function testItShouldProduceRecordAsArrayThroughMiddlewareQueue(): void $topic, $broker ); - $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { + $producerHandler = new class ($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations @@ -85,7 +85,7 @@ public function testItShouldProduceRecordAsStringThroughMiddlewareQueue(): void $kafkaProducer = m::mock(KafkaProducer::class); $producerTopic = m::mock(ProducerTopic::class); - $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { + $producerHandler = new class ($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations @@ -134,7 +134,7 @@ public function testItShouldThrowJsonExceptionWhenPassingMalFormattedArray(): vo 500, 1 ); - $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { + $producerHandler = new class ($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations @@ -187,7 +187,7 @@ public function testShouldBuildDispatcher(): void 1 ); - $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { + $producerHandler = new class ($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations @@ -236,7 +236,7 @@ public function testShouldBuildDispatcherWithConfigOptions(): void 500, 1 ); - $producerHandler = new class($record, $producerConfigOptions, $topic) extends AbstractProducer { + $producerHandler = new class ($record, $producerConfigOptions, $topic) extends AbstractProducer { }; // Expectations From 727d31f2e9724e9ea37bbd5114f464a6e55cb63a Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 14:21:32 -0300 Subject: [PATCH 63/75] style: supress phpcs typehing warning Signed-off-by: hcdias --- src/Console/ConfigOptionsCommand.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Console/ConfigOptionsCommand.php b/src/Console/ConfigOptionsCommand.php index d592a8b1..52d62dde 100644 --- a/src/Console/ConfigOptionsCommand.php +++ b/src/Console/ConfigOptionsCommand.php @@ -11,16 +11,19 @@ class ConfigOptionsCommand extends BaseCommand { /** * @var {inheritdoc} + * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint */ protected $name = 'kafka:consume-config-class'; /** * @var {inheritdoc} + * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint */ protected $description = 'Consumes something with a based class config'; /** * @var {inheritdoc} + * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint */ protected $signature = 'kafka:consume-config-class {handler : handler.} From e1d7e89bb5a9083c313f540d4cd4394159445402 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 14:39:10 -0300 Subject: [PATCH 64/75] style: supress phpcs typehing warning Signed-off-by: hcdias --- src/Connectors/AbstractConfig.php | 7 ++++++- src/Connectors/Consumer/Config.php | 2 +- tests/Unit/Connectors/Producer/ConnectorTest.php | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Connectors/AbstractConfig.php b/src/Connectors/AbstractConfig.php index b71c683c..5b084abc 100644 --- a/src/Connectors/AbstractConfig.php +++ b/src/Connectors/AbstractConfig.php @@ -7,6 +7,11 @@ abstract class AbstractConfig { + /** + * @var string[] + */ + protected array $rules; + protected function getBrokerConfig(string $servicesFile): array { if (!$brokerConfig = config($servicesFile . '.broker')) { @@ -15,7 +20,7 @@ protected function getBrokerConfig(string $servicesFile): array ); } - return $brokerConfig; + return $brokerConfig->all(); } protected function getSchemaConfig(string $servicesFile): array diff --git a/src/Connectors/Consumer/Config.php b/src/Connectors/Consumer/Config.php index d13976be..1e870981 100644 --- a/src/Connectors/Consumer/Config.php +++ b/src/Connectors/Consumer/Config.php @@ -19,7 +19,7 @@ class Config extends AbstractConfig { /** - * @var array + * @var string[] */ protected array $rules = [ 'topic' => 'required', diff --git a/tests/Unit/Connectors/Producer/ConnectorTest.php b/tests/Unit/Connectors/Producer/ConnectorTest.php index 2869318b..650dbd02 100644 --- a/tests/Unit/Connectors/Producer/ConnectorTest.php +++ b/tests/Unit/Connectors/Producer/ConnectorTest.php @@ -34,6 +34,7 @@ public function testItShouldMakeSetup(): void $connector = new Connector(); $handler = new class ('record', $producerConfigOptions) extends AbstractProducer implements HandleableResponseInterface { + /** @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter */ public function success(Message $message): void { } @@ -83,6 +84,7 @@ public function testItShouldMakeSetupWithoutHandleResponse(): void $connector = new Connector(); $handler = new class ('record', $producerConfigOptions) extends AbstractProducer implements HandlerInterface { + /** @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter */ public function success(Message $message): void { } From 5954a6ad82647a5f3687d527b73e8acaab1cbe63 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 15:23:31 -0300 Subject: [PATCH 65/75] chore: remove call to inexistent method --- src/Connectors/AbstractConfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connectors/AbstractConfig.php b/src/Connectors/AbstractConfig.php index 5b084abc..3ed44502 100644 --- a/src/Connectors/AbstractConfig.php +++ b/src/Connectors/AbstractConfig.php @@ -20,7 +20,7 @@ protected function getBrokerConfig(string $servicesFile): array ); } - return $brokerConfig->all(); + return $brokerConfig; } protected function getSchemaConfig(string $servicesFile): array From edd632195a0b0e91946bae0f161db15fc16c66e1 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 15:30:05 -0300 Subject: [PATCH 66/75] chore: supress psalm alert --- src/Connectors/AbstractConfig.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Connectors/AbstractConfig.php b/src/Connectors/AbstractConfig.php index 3ed44502..ef26cbf5 100644 --- a/src/Connectors/AbstractConfig.php +++ b/src/Connectors/AbstractConfig.php @@ -12,6 +12,9 @@ abstract class AbstractConfig */ protected array $rules; + /** + * @psalm-suppress InvalidReturnStatement + */ protected function getBrokerConfig(string $servicesFile): array { if (!$brokerConfig = config($servicesFile . '.broker')) { From 0339538b4215615d85839670c90b5feec5fdb207 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 15:55:36 -0300 Subject: [PATCH 67/75] tests: remove configManager related tests --- tests/Unit/Connectors/Consumer/ManagerTest.php | 18 ------------------ .../Unit/Middlewares/Handler/ProducerTest.php | 16 ---------------- tests/Unit/Producer/PollTest.php | 4 ++-- 3 files changed, 2 insertions(+), 36 deletions(-) diff --git a/tests/Unit/Connectors/Consumer/ManagerTest.php b/tests/Unit/Connectors/Consumer/ManagerTest.php index 230513b2..52e3bcc1 100644 --- a/tests/Unit/Connectors/Consumer/ManagerTest.php +++ b/tests/Unit/Connectors/Consumer/ManagerTest.php @@ -184,22 +184,4 @@ function () use ($messages, &$count, $exception) { $runner->handleMessage(); $runner->handleMessage(); } - - protected function setUp(): void - { - parent::setUp(); - - $configManager = new ConsumerConfigManager(); - $configManager->set([ - 'connections' => 'kafka:2019', - 'topic' => 'topic_key', - 'broker' => 'default', - 'offset_reset' => 'earliest', - 'offset' => 0, - 'timeout' => 30, - 'handler' => ConsumerHandlerDummy::class, - 'middlewares' => [], - 'consumer_group' => 'consumer-id', - ]); - } } diff --git a/tests/Unit/Middlewares/Handler/ProducerTest.php b/tests/Unit/Middlewares/Handler/ProducerTest.php index df2750e6..561a7c78 100644 --- a/tests/Unit/Middlewares/Handler/ProducerTest.php +++ b/tests/Unit/Middlewares/Handler/ProducerTest.php @@ -37,20 +37,4 @@ public function testItShouldSendMessageToKafkaBroker(): void $producerHandler = new Producer($producerTopic, $poll, 1); $producerHandler->process($record, $closure); } - - protected function setUp(): void - { - parent::setUp(); - - $configManager = new ProducerConfigManager(); - $configManager->set([ - 'topic_id' => 'topic_name', - 'timeout' => 4000, - 'is_async' => true, - 'max_poll_records' => 500, - 'flush_attempts' => 10, - 'required_acknowledgment' => true, - 'partition' => 0, - ]); - } } diff --git a/tests/Unit/Producer/PollTest.php b/tests/Unit/Producer/PollTest.php index 0576cd6c..ba216928 100644 --- a/tests/Unit/Producer/PollTest.php +++ b/tests/Unit/Producer/PollTest.php @@ -68,8 +68,8 @@ public function testShouldThrowExceptionWhenFlushFailed(): void ->poll(0); $kafkaProducer->expects() - ->flush(1000) - ->times(3) + ->flush(100) + ->times(10) ->andReturn(1); $this->expectException(RuntimeException::class); From d026b4a61e7b1b08f42886104073800979ced8c7 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 16:14:30 -0300 Subject: [PATCH 68/75] gha: update kafka broker connection --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index e57a08ef..66b85e9d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -18,7 +18,7 @@ jobs: - '8.1' - '8.2' env: - KAFKA_BROKER_CONNECTIONS: 'localhost:9092' + KAFKA_BROKER_CONNECTIONS: 'kafka:9092' services: zookeeper: image: bitnami/zookeeper From c0560340692e97aa0f5316ada6f7893e5cdcf0b1 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 9 Oct 2023 18:06:43 -0300 Subject: [PATCH 69/75] gha: undo update kafka broker connection --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 66b85e9d..e57a08ef 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -18,7 +18,7 @@ jobs: - '8.1' - '8.2' env: - KAFKA_BROKER_CONNECTIONS: 'kafka:9092' + KAFKA_BROKER_CONNECTIONS: 'localhost:9092' services: zookeeper: image: bitnami/zookeeper From 9d5392edba8e935f7161dcffb71fe34a822a79fb Mon Sep 17 00:00:00 2001 From: GetulioMR Date: Tue, 10 Oct 2023 11:49:20 -0300 Subject: [PATCH 70/75] fix(tests): get connection by env --- tests/Integration/ProducerTest.php | 3 ++- tests/Integration/ProducerWithAvroTest.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Integration/ProducerTest.php b/tests/Integration/ProducerTest.php index 8fbe5305..39cedbfd 100644 --- a/tests/Integration/ProducerTest.php +++ b/tests/Integration/ProducerTest.php @@ -206,7 +206,8 @@ private function haveFourProducedMessages(): void private function createProducerConfigOptions(string $topicId): ProducerConfigOptions { - $broker = new Broker('kafka:9092', new None()); + $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); + $broker = new Broker($connections, new None()); return new ProducerConfigOptions( $topicId, diff --git a/tests/Integration/ProducerWithAvroTest.php b/tests/Integration/ProducerWithAvroTest.php index 54793d98..2a83cca3 100644 --- a/tests/Integration/ProducerWithAvroTest.php +++ b/tests/Integration/ProducerWithAvroTest.php @@ -170,7 +170,8 @@ private function setLogExpectationsFor(string $message): void private function createProducerConfigOptions(string $topicId): ProducerConfigOptions { - $broker = new Broker('kafka:9092', new None()); + $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); + $broker = new Broker($connections, new None()); return new ProducerConfigOptions( $topicId, From a10f0d60f580dac61d415251966f11ff057284ee Mon Sep 17 00:00:00 2001 From: GetulioMR Date: Tue, 10 Oct 2023 11:56:13 -0300 Subject: [PATCH 71/75] test(producer): add expect not to perform assertion --- tests/Integration/ProducerWithAvroTest.php | 1 + tests/Integration/ProducerWithConfigOptionsTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/Integration/ProducerWithAvroTest.php b/tests/Integration/ProducerWithAvroTest.php index 2a83cca3..09237bfc 100644 --- a/tests/Integration/ProducerWithAvroTest.php +++ b/tests/Integration/ProducerWithAvroTest.php @@ -41,6 +41,7 @@ public function testShouldRunAProducerMessagesWithAAvroSchema(): void // I expect that $this->myMessagesHaveBeenLogged(); + $this->expectNotToPerformAssertions(); } protected function haveAHandlerConfigured(): void diff --git a/tests/Integration/ProducerWithConfigOptionsTest.php b/tests/Integration/ProducerWithConfigOptionsTest.php index 4e256a42..ec37a620 100644 --- a/tests/Integration/ProducerWithConfigOptionsTest.php +++ b/tests/Integration/ProducerWithConfigOptionsTest.php @@ -31,6 +31,7 @@ public function testShouldRunAProducerMessagesWithConfigOptions(): void // I Expect That $this->myMessagesHaveBeenLogged(); + $this->expectNotToPerformAssertions(); // When I $this->runTheConsumer(); From 377b2e44d48ea3d00d005539810d70c87ebf7a27 Mon Sep 17 00:00:00 2001 From: GetulioMR Date: Tue, 10 Oct 2023 12:02:25 -0300 Subject: [PATCH 72/75] fix(tests): enable to get broker connection from env --- config/service.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/service.php b/config/service.php index 64f81077..7eacd41f 100644 --- a/config/service.php +++ b/config/service.php @@ -19,7 +19,7 @@ 'password' => 'PASSWORD', ], 'broker' => [ - 'connections' => 'kafka:9092', + 'connections' => env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'), 'auth' => [ 'type' => 'ssl', // ssl and none 'ca' => storage_path('ca.pem'), From b792fe0eadc1e455b503bbd11e306be7bdd4ec3c Mon Sep 17 00:00:00 2001 From: GetulioMR Date: Tue, 10 Oct 2023 12:11:43 -0300 Subject: [PATCH 73/75] fix(tests): enable to get broker connection from env --- tests/Unit/Connectors/Producer/ConnectorTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Connectors/Producer/ConnectorTest.php b/tests/Unit/Connectors/Producer/ConnectorTest.php index 650dbd02..dc2dfe96 100644 --- a/tests/Unit/Connectors/Producer/ConnectorTest.php +++ b/tests/Unit/Connectors/Producer/ConnectorTest.php @@ -29,7 +29,8 @@ public function testItShouldMakeSetup(): void m::mock(KafkaProducer::class) ); - $broker = new Broker('kafka:9092', new None()); + $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); + $broker = new Broker($connections, new None()); $producerConfigOptions = m::mock(ProducerConfigOptions::class); $connector = new Connector(); @@ -79,7 +80,8 @@ public function testItShouldMakeSetupWithoutHandleResponse(): void m::mock(KafkaProducer::class) ); - $broker = new Broker('kafka:9092', new None()); + $connections = env('KAFKA_BROKER_CONNECTIONS', 'kafka:9092'); + $broker = new Broker($connections, new None()); $producerConfigOptions = m::mock(ProducerConfigOptions::class); $connector = new Connector(); From c0c368e4827f34a5b960b0631cefdb5057815212 Mon Sep 17 00:00:00 2001 From: GetulioMR Date: Tue, 10 Oct 2023 12:17:05 -0300 Subject: [PATCH 74/75] fix(tests): adjust mock expectations --- tests/Unit/Connectors/Producer/ConnectorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Connectors/Producer/ConnectorTest.php b/tests/Unit/Connectors/Producer/ConnectorTest.php index dc2dfe96..6652a0e7 100644 --- a/tests/Unit/Connectors/Producer/ConnectorTest.php +++ b/tests/Unit/Connectors/Producer/ConnectorTest.php @@ -52,7 +52,7 @@ public function failed(Message $message): void ->withAnyArgs(); $conf->expects() - ->set('metadata.broker.list', 0); + ->set('metadata.broker.list', $connections); $producerConfigOptions->expects() ->getBroker() @@ -102,7 +102,7 @@ public function failed(Message $message): void ->never(); $conf->expects() - ->set('metadata.broker.list', 0); + ->set('metadata.broker.list', $connections); $producerConfigOptions->expects() ->getBroker() From 0428873db29437bc08f29f88c12428d3be871526 Mon Sep 17 00:00:00 2001 From: hcdias Date: Mon, 16 Oct 2023 15:25:55 -0300 Subject: [PATCH 75/75] chore: add max poll interval on configOptions --- config/kafka.php | 4 ++++ src/Connectors/Consumer/HighLevel.php | 4 ++-- src/Connectors/Consumer/LowLevel.php | 4 ++-- src/TopicHandler/ConfigOptions/Consumer.php | 15 ++++++++++++++- .../ConfigOptions/Factories/ConsumerFactory.php | 5 +++++ tests/Unit/Console/ConsumerCommandTest.php | 2 +- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/config/kafka.php b/config/kafka.php index 3e7f0764..4ffe7459 100644 --- a/config/kafka.php +++ b/config/kafka.php @@ -44,6 +44,10 @@ // An array of middlewares applied only for this consumer_group 'middlewares' => [], + + // A max interval for consumer to make poll calls. That means: how much + // time we need to wait for poll calls until consider the consumer has inactive. + 'max_poll_interval_ms' => 300000, ], 'producer' => [ diff --git a/src/Connectors/Consumer/HighLevel.php b/src/Connectors/Consumer/HighLevel.php index 9c832ae0..ebdd09de 100644 --- a/src/Connectors/Consumer/HighLevel.php +++ b/src/Connectors/Consumer/HighLevel.php @@ -14,7 +14,7 @@ class HighLevel implements ConnectorInterface public function getConsumer(bool $autoCommit, ConfigOptions $configOptions): ConsumerInterface { $conf = $this->getConf($configOptions); - $maxPollIntervalMs = (int) $configOptions->getTimeout(); + $maxPollIntervalMs = $configOptions->getMaxPollInterval(); $conf->set('group.id', $configOptions->getConsumerGroup()); $conf->set('auto.offset.reset', $configOptions->getOffsetReset()); if (!$autoCommit) { @@ -22,7 +22,7 @@ public function getConsumer(bool $autoCommit, ConfigOptions $configOptions): Con } $conf->set( 'max.poll.interval.ms', - $maxPollIntervalMs ?: 300000 + $maxPollIntervalMs ); $consumer = app(KafkaConsumer::class, ['conf' => $conf]); diff --git a/src/Connectors/Consumer/LowLevel.php b/src/Connectors/Consumer/LowLevel.php index 30f4c277..da3c1360 100644 --- a/src/Connectors/Consumer/LowLevel.php +++ b/src/Connectors/Consumer/LowLevel.php @@ -15,10 +15,10 @@ class LowLevel implements ConnectorInterface public function getConsumer(bool $autoCommit, ConfigOptions $configOptions): ConsumerInterface { $conf = $this->getConf(); - $maxPollIntervalMs = (int) $configOptions->getTimeout(); + $maxPollIntervalMs = $configOptions->getMaxPollInterval(); $conf->set( 'max.poll.interval.ms', - $maxPollIntervalMs ?: 300000 + $maxPollIntervalMs ); $conf->set('group.id', $configOptions->getConsumerGroup()); if (!$autoCommit) { diff --git a/src/TopicHandler/ConfigOptions/Consumer.php b/src/TopicHandler/ConfigOptions/Consumer.php index e2caa016..2019ed68 100644 --- a/src/TopicHandler/ConfigOptions/Consumer.php +++ b/src/TopicHandler/ConfigOptions/Consumer.php @@ -38,6 +38,8 @@ class Consumer private ?int $offset = null; + private int $maxPollInterval = 300000; + public function __construct( string $topicId, Broker $broker, @@ -50,7 +52,8 @@ public function __construct( int $timeout = 1000, bool $autoCommit = true, bool $commitASync = true, - string $offsetReset = 'smallest' + string $offsetReset = 'smallest', + int $maxPollInterval = 300000 ) { $this->broker = $broker; $this->middlewares = $middlewares; @@ -64,6 +67,7 @@ public function __construct( $this->autoCommit = $autoCommit; $this->commitASync = $commitASync; $this->offsetReset = $offsetReset; + $this->maxPollInterval = $maxPollInterval; } public function getTimeout(): int @@ -147,4 +151,13 @@ public function getOffset(): ?int { return $this->offset; } + public function getMaxPollInterval(): int + { + return $this->maxPollInterval; + } + + public function setMaxPollInterval(int $maxPollInterval): void + { + $this->maxPollInterval = $maxPollInterval; + } } diff --git a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php index 2d28a28c..2f0896fb 100644 --- a/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php +++ b/src/TopicHandler/ConfigOptions/Factories/ConsumerFactory.php @@ -53,6 +53,11 @@ private static function convertConfigAttributes(array $consumerConfig): array $consumerConfig['offsetReset'] = $consumerConfig['offset_reset']; } + + if (isset($consumerConfig['max_poll_interval_ms'])) { + $consumerConfig['maxPollInterval'] = $consumerConfig['max_poll_interval_ms']; + } + return $consumerConfig; } } diff --git a/tests/Unit/Console/ConsumerCommandTest.php b/tests/Unit/Console/ConsumerCommandTest.php index c4737533..fd26cb27 100644 --- a/tests/Unit/Console/ConsumerCommandTest.php +++ b/tests/Unit/Console/ConsumerCommandTest.php @@ -131,7 +131,6 @@ public function testItOverridesBrokerConnectionWhenCallingCommand(): void $this->artisan($command, $parameters); } - protected function setUp(): void { parent::setUp(); @@ -146,6 +145,7 @@ protected function setUp(): void 'offset_reset' => 'earliest', 'handler' => ConsumerHandlerDummy::class, 'timeout' => 123, + 'max_poll_interval_ms' => 300000, ], ], ],