Skip to content

Commit

Permalink
feat(deps): support PHP to 8.4 and Symfony 5+
Browse files Browse the repository at this point in the history
- Upgrade minimum PHP version to 8.2 and Symfony framework to version 5+
- Upgrade PHPStan and PHPUnit
- Remove Safe PHP library dependency due to maintenance issues and 8.4 deprecations
- Implement custom safe PHP function wrappers for internal usage
- Update testing strategy to use PHP 8.4 as default, while maintaining compatibility tests for minimum supported versions

BREAKING CHANGE: Drops support for PHP 8.1
  • Loading branch information
tigitz committed Jan 11, 2025
1 parent dfba2a6 commit d58de46
Show file tree
Hide file tree
Showing 42 changed files with 424 additions and 224 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/php-cs-fixer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
php-version: 8.2
coverage: none
tools: php-cs-fixer:3.54.x, cs2pr
tools: php-cs-fixer:3.67.x, cs2pr

- name: Restore PHP-CS-Fixer cache
uses: actions/cache@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: [ "8.1", "8.3" ]
php: [ "8.2", "8.4" ]
steps:
- uses: actions/checkout@v4

Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: ["8.1", "8.2", "8.3"]
stability: [--prefer-lowest, --prefer-stable]
include:
- php: "8.4"
stability: --prefer-stable
- php: "8.2"
stability: --prefer-lowest
env:
PHP_VERSION: ${{ matrix.php }}
DEPS_STRATEGY: ${{ matrix.stability }}
Expand Down Expand Up @@ -46,7 +49,7 @@ jobs:

- name: Run tests
run: |
export WITH_COVERAGE=$(if [[ ("${{ matrix.php }}" = "8.3") && ("${{ matrix.stability }}" = "--prefer-stable") ]]; then echo "true"; else echo "false"; fi)
export WITH_COVERAGE=$(if [[ ("${{ matrix.php }}" = "8.4") && ("${{ matrix.stability }}" = "--prefer-stable") ]]; then echo "true"; else echo "false"; fi)
echo "WITH_COVERAGE=${WITH_COVERAGE}" >> $GITHUB_ENV
make vendor
make tests
Expand Down
7 changes: 5 additions & 2 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
'lowercase_cast' => true,
'method_chaining_indentation' => true,
'native_function_casing' => true,
'native_function_invocation' => ['include' => ['@compiler_optimized']],
'new_with_braces' => true,
'native_function_invocation' => [
'include' => ['@compiler_optimized'],
'strict' => false
],
'new_with_parentheses' => true,
'modernize_types_casting' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'no_empty_statement' => true,
Expand Down
2 changes: 1 addition & 1 deletion .scrutinizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ build:
analysis:
environment:
php:
version: 8.1
version: 8.4
cache:
disabled: false
directories:
Expand Down
25 changes: 14 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
DOCKER_COMPOSE ?= docker compose
EXEC_PHP = $(DOCKER_COMPOSE) run --rm -T php
PHP_VERSION ?= 8.2
EXEC_PHP = $(DOCKER_COMPOSE) run --rm php
PHP_VERSION ?= 8.4
DEPS_STRATEGY ?= --prefer-stable
COMPOSER = $(EXEC_PHP) composer
WITH_COVERAGE ?= "FALSE"
EXAMPLES_DIR ?= "examples"

pull:
@$(DOCKER_COMPOSE) pull languagetools jamspell php
@$(DOCKER_COMPOSE) pull languagetools jamspell

build:
$(DOCKER_COMPOSE) build --no-cache php
Expand All @@ -25,13 +25,16 @@ setup: build

.PHONY: build kill setup

PHPUNIT_FLAGS = $(if $(filter 8.4,$(PHP_VERSION)),--display-deprecations,) \
$(if $(filter true,$(WITH_COVERAGE)),--coverage-clover clover.xml,)

tests: ## Run all tests
tests:
if [ $(WITH_COVERAGE) = true ]; then $(EXEC_PHP) vendor/bin/phpunit --coverage-clover clover.xml; else $(EXEC_PHP) vendor/bin/phpunit; fi
$(EXEC_PHP) vendor/bin/phpunit $(PHPUNIT_FLAGS)

tests-dox: ## Run all tests in dox format
tests-dox:
if [ $(WITH_COVERAGE) = true ]; then $(EXEC_PHP) vendor/bin/phpunit --coverage-clover clover.xml --testdox; else $(EXEC_PHP) vendor/bin/phpunit --testdox; fi
$(EXEC_PHP) vendor/bin/phpunit $(PHPUNIT_FLAGS) --testdox

# @TODO not optimized, it recreates a container for each example
examples-test:
Expand All @@ -45,11 +48,11 @@ examples-test:

tu: ## Run unit tests
tu: vendor
$(EXEC_PHP) vendor/bin/phpunit --exclude-group integration
$(EXEC_PHP) vendor/bin/phpunit --display-deprecations --exclude-group integration

ti: ## Run functional tests
ti: vendor
$(EXEC_PHP) vendor/bin/phpunit --group integration
$(EXEC_PHP) vendor/bin/phpunit --display-deprecations --group integration

.PHONY: tests tests-dox examples-test tu ti

Expand All @@ -59,12 +62,12 @@ vendor:
PHP_CS_FIXER = docker-compose run --rm -T php tools/php-cs-fixer/vendor/bin/php-cs-fixer fix -vv --allow-risky=yes

phpcs:
PHP_VERSION=8.1 $(EXEC_PHP) composer -d tools/php-cs-fixer update
PHP_VERSION=8.1 $(PHP_CS_FIXER) --dry-run
PHP_VERSION=8.2 $(EXEC_PHP) composer -d tools/php-cs-fixer update
PHP_VERSION=8.2 $(PHP_CS_FIXER) --dry-run

phpcbf:
PHP_VERSION=8.1 $(EXEC_PHP) composer -d tools/php-cs-fixer update
PHP_VERSION=8.1 $(PHP_CS_FIXER)
PHP_VERSION=8.2 $(EXEC_PHP) composer -d tools/php-cs-fixer update
PHP_VERSION=8.2 $(PHP_CS_FIXER)

phpstan: vendor
$(EXEC_PHP) vendor/bin/phpstan analyse src -c phpstan.neon -a vendor/autoload.php
Expand Down
27 changes: 13 additions & 14 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "tigitz/php-spellchecker",
"type": "library",
"version": "0.8.0",
"description": "Provides an easy way to spellcheck multiple text source by many spellcheckers, directly from PHP",
"keywords": [
"spelling",
Expand All @@ -21,28 +22,26 @@
}
],
"require": {
"php": "^8.1",
"php": "^8.2",
"nyholm/psr7": "^1.3",
"psr/http-client": "^1.0",
"symfony/process": "^4.4.30 | ^5.0 |^6.0 | ^7.0",
"thecodingmachine/safe": "^1.0 | ^2.0",
"symfony/process": "^6.4 | ^7",
"webmozart/assert": "^1.11"
},
"require-dev": {
"aptoma/twig-markdown": "^3.0",
"cocur/slugify": "^3.2 || ^4.0",
"erusev/parsedown": "^1.7",
"erusev/parsedown-extra": "^0.8",
"phpstan/phpstan": "^1.2.0",
"phpstan/phpstan-strict-rules": "^1.1.0",
"phpstan/phpstan-webmozart-assert": "^1.0.0",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpunit/phpunit": "^9.5",
"pixelrobin/php-feather": "^1.0",
"symfony/filesystem": "^4.4 || ^5.0 || ^6.0",
"symfony/finder": "^4.4 || ^5.0 || ^6.0",
"symfony/http-client": "^5.0 || ^6.0",
"thecodingmachine/phpstan-safe-rule": "^1.1"
"phpstan/phpstan": "^2",
"phpstan/phpstan-strict-rules": "^2",
"phpstan/phpstan-webmozart-assert": "^2",
"phpstan/phpstan-phpunit": "^2",
"phpunit/phpunit": "^10.5 || ^11.0",
"pixelrobin/php-feather": "^2",
"symfony/filesystem": "^5 |^6 | ^7",
"symfony/finder": "^5 |^6 | ^7",
"symfony/http-client": "^5 |^6 | ^7"
},
"suggest": {
"symfony/http-client": "A PSR-18 Client implementation to use spellcheckers that relies on HTTP APIs"
Expand All @@ -51,7 +50,7 @@
"psr-4": {
"PhpSpellcheck\\": "src"
},
"files": [ "src/Text/functions.php" ]
"files": [ "src/Text/functions.php" , "src/Utils/php-functions.php" ]
},
"autoload-dev": {
"psr-4": {
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
services:
php:
image: tigitz/phpspellchecker:${PHP_VERSION:-8.1}
image: tigitz/phpspellchecker:${PHP_VERSION:-8.4}
build:
context: docker/php
args:
PHP_VERSION: ${PHP_VERSION:-8.1}
PHP_VERSION: ${PHP_VERSION:-8.4}
volumes:
- .:/usr/src/myapp
- ./cache:/root/composer/cache
Expand Down
23 changes: 13 additions & 10 deletions docker/php/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,19 @@ RUN apt-get update \
aspell-en \
aspell-ru \
libpspell-dev
RUN set -eux; \
case "$PHP_VERSION" in \
8.1*) pecl install xdebug-3.1.1;; \
*) pecl install xdebug-3.3.2;; \
esac
RUN docker-php-ext-configure pspell \
&& docker-php-ext-enable xdebug \
&& docker-php-ext-install pspell \
&& docker-php-ext-install zip \
&& rm -r /var/lib/apt/lists/*

RUN pecl channel-update pecl.php.net && \
pecl install xdebug-3.4.0 && \
docker-php-ext-enable xdebug

RUN if [ "${PHP_VERSION}" = "8.4" ]; then \
pecl install pspell; \
else \
docker-php-ext-configure pspell && \
docker-php-ext-install pspell; \
fi && \
docker-php-ext-enable pspell && \
rm -r /var/lib/apt/lists/*

RUN cp /usr/share/hunspell/en_US.aff /usr/share/hunspell/en_US.aff.orig \
&& cp /usr/share/hunspell/en_US.dic /usr/share/hunspell/en_US.dic.orig \
Expand Down
8 changes: 4 additions & 4 deletions docs/generate-docs.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@
}

// Generate index.html doc file from the readme while stripping some sections
$readme = \Safe\file_get_contents(__DIR__.'/../README.md');
$readme = \PhpSpellcheck\file_get_contents(__DIR__.'/../README.md');

$readme = \Safe\preg_replace('/(# Install[\s\S]+?)^# /m', '# ', $readme);
$readme = \Safe\preg_replace('/(# Usage[\s\S]+?)^# /m', '# ', $readme);
$readme = \Safe\preg_replace('/(# Testing[\s\S]+?)^# /m', '# ', $readme);
$readme = \PhpSpellcheck\preg_replace('/(# Install[\s\S]+?)^# /m', '# ', $readme);
$readme = \PhpSpellcheck\preg_replace('/(# Usage[\s\S]+?)^# /m', '# ', $readme);
$readme = \PhpSpellcheck\preg_replace('/(# Testing[\s\S]+?)^# /m', '# ', $readme);

$fs->dumpFile(
__DIR__.'/index.html',
Expand Down
41 changes: 9 additions & 32 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
includes:
- vendor/phpstan/phpstan-webmozart-assert/extension.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon
- vendor/phpstan/phpstan-phpunit/extension.neon

parameters:
Expand All @@ -24,41 +23,19 @@ parameters:
path: src/MisspellingHandler/MisspellingHandlerInterface.php

-
message: "#^Function pspell_config_create is unsafe to use\\. It can return FALSE instead of throwing an exception\\. Please add 'use function Safe\\\\pspell_config_create;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library\\.$#"
message: '#^Default value of the parameter \#2 \$flags \(0\) of function PhpSpellcheck\\json_encode\(\) is incompatible with type int\<1, max\>\.$#'
identifier: parameter.defaultValue
count: 1
path: src/Spellchecker/PHPPspell.php
path: src/Utils/php-functions.php

-
message: "#^Function pspell_config_ignore is unsafe to use\\. It can return FALSE instead of throwing an exception\\. Please add 'use function Safe\\\\pspell_config_ignore;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library\\.$#"
message: '#^Parameter \#3 \$depth of function json_decode expects int\<1, max\>, int given\.$#'
identifier: argument.type
count: 1
path: src/Spellchecker/PHPPspell.php
path: src/Utils/php-functions.php

-
message: "#^Function pspell_config_mode is unsafe to use\\. It can return FALSE instead of throwing an exception\\. Please add 'use function Safe\\\\pspell_config_mode;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library\\.$#"
message: '#^Parameter \#3 \$depth of function json_encode expects int\<1, max\>, int given\.$#'
identifier: argument.type
count: 1
path: src/Spellchecker/PHPPspell.php

-
message: "#^Function pspell_new_config is unsafe to use\\. It can return FALSE instead of throwing an exception\\. Please add 'use function Safe\\\\pspell_new_config;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library\\.$#"
count: 1
path: src/Spellchecker/PHPPspell.php

-
message: "#^Parameter \\#1 \\$dictionary of function pspell_check expects PSpell\\\\Dictionary, PSpell\\\\Dictionary\\|false given\\.$#"
count: 1
path: src/Spellchecker/PHPPspell.php

-
message: "#^Parameter \\#1 \\$dictionary of function pspell_check expects PSpell\\\\Dictionary, int given\\.$#"
count: 1
path: src/Spellchecker/PHPPspell.php

-
message: "#^Parameter \\#1 \\$dictionary of function pspell_suggest expects PSpell\\\\Dictionary, PSpell\\\\Dictionary\\|false given\\.$#"
count: 1
path: src/Spellchecker/PHPPspell.php

-
message: "#^Parameter \\#1 \\$dictionary of function pspell_suggest expects PSpell\\\\Dictionary, int given\\.$#"
count: 1
path: src/Spellchecker/PHPPspell.php
path: src/Utils/php-functions.php
19 changes: 6 additions & 13 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,16 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="tests/bootstrap.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stderr="true"
displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnTestsThatTriggerErrors="true"
displayDetailsOnTestsThatTriggerNotices="true"
displayDetailsOnTestsThatTriggerWarnings="true"
displayDetailsOnPhpunitDeprecations="true"
failOnRisky="true"
failOnWarning="true"
stopOnFailure="false"
>
<coverage>
<include>
<directory suffix=".php">src/</directory>
</include>
</coverage>
<php>
<ini name="error_reporting" value="-1"/>
<ini name="memory_limit" value="-1"/>
Expand Down
15 changes: 15 additions & 0 deletions src/Exception/FilesystemException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace PhpSpellcheck\Exception;

class FilesystemException extends \ErrorException implements ExceptionInterface
{
public static function createFromPhpError(): self
{
$error = error_get_last();

return new self($error['message'] ?? 'An error occured', 0, $error['type'] ?? 1);
}
}
13 changes: 13 additions & 0 deletions src/Exception/JsonException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace PhpSpellcheck\Exception;

class JsonException extends \JsonException implements ExceptionInterface
{
public static function createFromPhpError(): self
{
return new self(json_last_error_msg(), json_last_error());
}
}
23 changes: 23 additions & 0 deletions src/Exception/PcreException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace PhpSpellcheck\Exception;

class PcreException extends \Exception implements ExceptionInterface
{
public static function createFromPhpError(): self
{
$errorMap = [
PREG_INTERNAL_ERROR => 'PREG_INTERNAL_ERROR: Internal error',
PREG_BACKTRACK_LIMIT_ERROR => 'PREG_BACKTRACK_LIMIT_ERROR: Backtrack limit reached',
PREG_RECURSION_LIMIT_ERROR => 'PREG_RECURSION_LIMIT_ERROR: Recursion limit reached',
PREG_BAD_UTF8_ERROR => 'PREG_BAD_UTF8_ERROR: Invalid UTF8 character',
PREG_BAD_UTF8_OFFSET_ERROR => 'PREG_BAD_UTF8_OFFSET_ERROR',
PREG_JIT_STACKLIMIT_ERROR => 'PREG_JIT_STACKLIMIT_ERROR',
];
$errMsg = $errorMap[preg_last_error()] ?? 'Unknown PCRE error: '.preg_last_error();

return new self($errMsg, preg_last_error());
}
}
Loading

0 comments on commit d58de46

Please sign in to comment.