diff --git a/.github/workflows/code_checks.yaml b/.github/workflows/code_checks.yaml index c369cde..cc0d02d 100644 --- a/.github/workflows/code_checks.yaml +++ b/.github/workflows/code_checks.yaml @@ -32,7 +32,7 @@ jobs: - name: Update project dependencies run: | composer update --no-interaction --no-progress --ansi - composer require --dev "phpstan/phpstan:^1.10" "phpstan/phpstan-strict-rules:^1.5" "phpstan/phpstan-phpunit: ^1.3" "phpstan/phpstan-deprecation-rules:^1.1" + composer require --dev "phpstan/phpstan:^2.1" "phpstan/phpstan-strict-rules:^2.0" "phpstan/phpstan-phpunit: ^2.0" "phpstan/phpstan-deprecation-rules:^2.0" - name: Run PHPStan analysis run: | @@ -43,25 +43,9 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] - symfony: ['^3.4', '^4.0', '^5.0', '^6.0', '^7.0'] + php: ['8.1', '8.2', '8.3', '8.4'] + symfony: ['^6.0', '^7.0', '^8.0'] exclude: - - symfony: ^3.4 - php: 8.1 - - symfony: ^3.4 - php: 8.2 - - symfony: ^3.4 - php: 8.3 - - symfony: ^3.4 - php: 8.4 - - symfony: ^4.0 - php: 8.1 - - symfony: ^4.0 - php: 8.2 - - symfony: ^4.0 - php: 8.3 - - symfony: ^4.0 - php: 8.4 - symfony: ^6.0 php: 7.4 - symfony: ^7.0 @@ -70,6 +54,12 @@ jobs: php: 8.0 - symfony: ^7.0 php: 8.1 + - symfony: ^8.0 + php: 8.1 + - symfony: ^8.0 + php: 8.2 + - symfony: ^8.0 + php: 8.3 fail-fast: false name: PHPUnit (PHP ${{ matrix.php }}) (Symfony ${{ matrix.symfony }}) steps: @@ -106,7 +96,7 @@ jobs: timeout-minutes: 5 env: APP_DEBUG: '1' # https://github.com/phpstan/phpstan-symfony/issues/37 - SYMFONY_REQUIRE: '^5.0' + SYMFONY_REQUIRE: '^6.4' SYMFONY_PHPUNIT_VERSION: '9.5' steps: - name: Checkout @@ -115,7 +105,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.1' tools: flex coverage: xdebug ini-values: memory_limit=-1 @@ -125,9 +115,4 @@ jobs: composer update --no-interaction --no-progress --ansi - name: Run code coverage - run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover - - - name: Send code coverage - run: | - wget https://scrutinizer-ci.com/ocular.phar - php ocular.phar code-coverage:upload --format=php-clover coverage.clover + run: vendor/bin/phpunit --coverage-text diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e177c4c..56584a0 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -10,14 +10,9 @@ class Configuration implements ConfigurationInterface { public function getConfigTreeBuilder(): TreeBuilder { - if (method_exists(TreeBuilder::class, 'getRootNode')) { - $treeBuilder = new TreeBuilder('karser_recaptcha3'); - $rootNode = $treeBuilder->getRootNode(); - } else { - // BC layer for symfony/config 4.1 and older - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('karser_recaptcha3', 'array'); - } + $treeBuilder = new TreeBuilder('karser_recaptcha3'); + $rootNode = $treeBuilder->getRootNode(); + $rootNode ->children() ->scalarNode('site_key')->isRequired()->end() diff --git a/README.md b/README.md index 083b6e8..bfeec36 100644 --- a/README.md +++ b/README.md @@ -27,24 +27,34 @@ With [composer](https://getcomposer.org), require: `composer require karser/karser-recaptcha3-bundle` +### Version compatibility + +| Bundle Version | Symfony Version | PHP Version | +|----------------|-----------------|-------------| +| 0.3.x | 6.4, 7.x, 8.x | ≥8.1 | +| 0.2.x | 3.4, 4.x, 5.x, 6.x, 7.x | ≥7.4 | +| 0.1.x | 3.4, 4.x, 5.x | ≥7.1 | + You can quickly configure this bundle by using symfony/flex. -Configuration without symfony/flex: +Configuration without symfony/flex: -------------------- ### 1. Register the bundle -**Symfony 4/5/6/7 Version :** +**Symfony 6.4/7.x/8.x Version:** Register bundle into `config/bundles.php`: -```php +```php return [ //... Karser\Recaptcha3Bundle\KarserRecaptcha3Bundle::class => ['all' => true], ]; ``` -**Symfony 3 Version:** -Register bundle into `app/AppKernel.php`: +**Older Symfony Versions (3.x/4.x/5.x):** +Please use bundle version 0.2.x for these Symfony versions. + +For Symfony 3, register bundle into `app/AppKernel.php`: ``` php public function registerBundles() diff --git a/ReCaptcha/RequestMethod/Socket.php b/ReCaptcha/RequestMethod/Socket.php index 995cf29..1341fef 100644 --- a/ReCaptcha/RequestMethod/Socket.php +++ b/ReCaptcha/RequestMethod/Socket.php @@ -58,7 +58,7 @@ public function fsockopen($hostname, $port = -1, &$errno = 0, &$errstr = '', $ti { $this->handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout)); - if ($this->handle != false && $errno === 0 && $errstr === '') { + if ($this->handle !== false && $errno === 0 && $errstr === '') { return $this->handle; } return null; diff --git a/ReCaptcha/Response.php b/ReCaptcha/Response.php index 33d5967..513453e 100644 --- a/ReCaptcha/Response.php +++ b/ReCaptcha/Response.php @@ -102,7 +102,7 @@ public static function fromJson($json) $score = isset($responseData['score']) ? floatval($responseData['score']) : null; $action = isset($responseData['action']) ? $responseData['action'] : ''; - if (isset($responseData['success']) && $responseData['success'] == true) { + if (isset($responseData['success']) && $responseData['success'] === true) { return new Response(true, array(), $hostname, $challengeTs, $apkPackageName, $score, $action); } diff --git a/Tests/Form/Recaptcha3TypeTest.php b/Tests/Form/Recaptcha3TypeTest.php index 51ad653..00fc2ff 100644 --- a/Tests/Form/Recaptcha3TypeTest.php +++ b/Tests/Form/Recaptcha3TypeTest.php @@ -11,7 +11,7 @@ class Recaptcha3TypeTest extends TypeTestCase const SITEKEY = ''; const HOST = ''; - protected function getExtensions() + protected function getExtensions(): array { $type = new Recaptcha3Type(self::SITEKEY, self::HOST, true); diff --git a/Tests/ReCaptcha/RequestMethod/CurlPostTest.php b/Tests/ReCaptcha/RequestMethod/CurlPostTest.php index 00877fd..19a5713 100644 --- a/Tests/ReCaptcha/RequestMethod/CurlPostTest.php +++ b/Tests/ReCaptcha/RequestMethod/CurlPostTest.php @@ -42,7 +42,7 @@ use PHPUnit\Framework\TestCase; /** - * @covers \Karser\Recaptcha3Bundle\Tests\ReCaptcha\RequestMethod\CurlPost + * @covers \Karser\Recaptcha3Bundle\ReCaptcha\RequestMethod\CurlPost */ class CurlPostTest extends TestCase { diff --git a/Tests/TestKernel.php b/Tests/TestKernel.php index a1c701c..ddbe23a 100644 --- a/Tests/TestKernel.php +++ b/Tests/TestKernel.php @@ -34,7 +34,7 @@ public function registerBundles(): iterable /** * {@inheritdoc} */ - public function registerContainerConfiguration(LoaderInterface $loader) + public function registerContainerConfiguration(LoaderInterface $loader): void { $loader->load($this->configurationFilename); $loader->load(self::MAJOR_VERSION >= 6 ? __DIR__.'/fixtures/config/symfony6.yml' : __DIR__.'/fixtures/config/symfony4.yml'); diff --git a/Validator/Constraints/Recaptcha3.php b/Validator/Constraints/Recaptcha3.php index 25c82ae..db44689 100644 --- a/Validator/Constraints/Recaptcha3.php +++ b/Validator/Constraints/Recaptcha3.php @@ -19,14 +19,40 @@ final class Recaptcha3 extends Constraint protected static $errorNames = self::ERROR_NAMES; - public $message = 'Your computer or network may be sending automated queries'; - public $messageMissingValue = 'The captcha value is missing'; - - public function __construct(?array $options = null, ?string $message = null, ?string $messageMissingValue = null, ?array $groups = null, $payload = null) - { - parent::__construct($options ?? [], $groups, $payload); - - $this->message = $message ?? $this->message; - $this->messageMissingValue = $messageMissingValue ?? $this->messageMissingValue; + public string $message = 'Your computer or network may be sending automated queries'; + public string $messageMissingValue = 'The captcha value is missing'; + + /** + * @param array|string|null $options + * @param string[]|null $groups + * @param mixed $payload + */ + public function __construct( + array|string|null $options = null, + ?string $message = null, + ?string $messageMissingValue = null, + ?array $groups = null, + mixed $payload = null + ) { + // Handle both old array-based and new named-parameter style + if (is_array($options)) { + // Extract named parameters from options array for backward compatibility + $message = $message ?? $options['message'] ?? null; + $messageMissingValue = $messageMissingValue ?? $options['messageMissingValue'] ?? null; + $groups = $groups ?? $options['groups'] ?? null; + $payload = $payload ?? $options['payload'] ?? null; + } + + // Set properties directly in constructor (Symfony 7.4+ requirement) + if ($message !== null) { + $this->message = $message; + } + if ($messageMissingValue !== null) { + $this->messageMissingValue = $messageMissingValue; + } + + // Pass null as first argument to avoid legacy option processing + // This prevents the deprecation warning in Symfony 7.4+ + parent::__construct(null, $groups, $payload); } } diff --git a/composer.json b/composer.json index a8f8f76..a4b7cee 100644 --- a/composer.json +++ b/composer.json @@ -35,19 +35,19 @@ } ], "require": { - "php": ">=7.4", + "php": ">=8.1", "ext-json": "*", - "symfony/form": "^3.4|^4.0|^5.0|^6.0|^7.0", - "symfony/framework-bundle": "^3.4.26|^4.2.7|^5.0|^6.0|^7.0", - "symfony/expression-language": "^3.4|^4.0|^5.0|^6.0|^7.0", - "symfony/yaml": "^3.4|^4.0|^5.0|^6.0|^7.0", - "symfony/validator": "^3.4|^4.0|^5.0|^6.0|^7.0", - "symfony/twig-bundle": "^3.4|^4.0|^5.0|^6.0|^7.0", - "twig/twig": "^2.9|^3.0" + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "twig/twig": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^7|^8|^9|^10", - "symfony/http-client": "^4.3|^5.0|^6.0|^7.0" + "phpunit/phpunit": "^9|^10|^11", + "symfony/http-client": "^6.4|^7.0|^8.0" }, "autoload": { "psr-4": { diff --git a/phpstan.neon b/phpstan.neon index b8dd331..c855135 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -16,6 +16,7 @@ parameters: - '#Call to function method_exists\(\) with .*?TreeBuilder.*? and .*?getRootNode.*? will always evaluate to true#' - '#Comparison operation ".*?" between \d+ and \d+ is always (true|false)#' - '#Else branch is unreachable because ternary operator condition is always true#' + - '#Call to deprecated function curl_close\(\)#' excludePaths: - %currentWorkingDirectory%/.github/*