diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index 68a7c5c..0000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-version: 2
-
-jobs:
- build:
- docker:
- - image: circleci/php:7.2-cli
-
- working_directory: ~/repo
-
- steps:
- - checkout
-
- - restore_cache:
- keys:
- - v1-dependencies-{{ checksum "composer.json" }}
- - v1-dependencies-
-
- - run: composer install -n --prefer-dist
-
- - save_cache:
- paths:
- - ./vendor
- key: v1-dependencies-{{ checksum "composer.json" }}
-
- - run: mkdir test/unit/_junit
- - run: vendor/bin/phpunit -c test/unit/phpunit.xml --log-junit test/unit/_junit/junit.xml --coverage-html ./test/unit/_coverage -d memory_limit=512M
-
- - store_test_results:
- path: test/unit/_junit
-
- - store_artifacts:
- path: test/unit/_coverage
- destination: TestCoverage
\ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..8ca7d16
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+# These are supported funding model platforms
+github: [phpgt]
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..307abf3
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+ - package-ecosystem: composer
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
+ ignore:
+ - dependency-name: phpunit/phpunit
+ update-types: ["version-update:semver-patch"]
+ - dependency-name: phpstan/phpstan
+ update-types: ["version-update:semver-patch"]
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..19f7612
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,171 @@
+name: CI
+
+on:
+ push:
+ pull_request:
+
+permissions:
+ contents: read
+ actions: read
+
+jobs:
+ composer:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ php: [ 8.2, 8.3, 8.4, 8.5 ]
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Cache Composer dependencies
+ uses: actions/cache@v5
+ with:
+ path: /tmp/composer-cache
+ key: ${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
+
+ - name: Composer install
+ uses: php-actions/composer@v6
+ with:
+ php_version: ${{ matrix.php }}
+ php_extensions: pcntl
+
+ - name: Archive build
+ run: mkdir /tmp/github-actions/ && tar --exclude=".git" -cvf /tmp/github-actions/build.tar ./
+
+ - name: Upload build archive for test runners
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-artifact-${{ matrix.php }}
+ path: /tmp/github-actions
+ retention-days: 1
+
+ phpunit:
+ runs-on: ubuntu-latest
+ needs: [ composer ]
+ strategy:
+ matrix:
+ php: [ 8.2, 8.3, 8.4, 8.5 ]
+
+ outputs:
+ coverage: ${{ steps.store-coverage.outputs.coverage_text }}
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: build-artifact-${{ matrix.php }}
+ path: /tmp/github-actions
+
+ - name: Extract build archive
+ run: tar -xvf /tmp/github-actions/build.tar ./
+
+ - name: PHP Unit tests
+ uses: php-actions/phpunit@v4
+ env:
+ XDEBUG_MODE: cover
+ with:
+ php_version: ${{ matrix.php }}
+ php_extensions: xdebug
+ coverage_text: _coverage/coverage.txt
+ coverage_clover: _coverage/clover.xml
+
+ - name: Store coverage data
+ uses: actions/upload-artifact@v4
+ with:
+ name: code-coverage-${{ matrix.php }}-${{ github.run_number }}
+ path: _coverage
+
+ coverage:
+ runs-on: ubuntu-latest
+ needs: [ phpunit ]
+ strategy:
+ matrix:
+ php: [ 8.2, 8.3, 8.4, 8.5 ]
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/download-artifact@v4
+ with:
+ name: code-coverage-${{ matrix.php }}-${{ github.run_number }}
+ path: _coverage
+
+ - name: Output coverage
+ run: cat "_coverage/coverage.txt"
+
+ - name: Upload to Codecov
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ slug: ${{ github.repository }}
+
+ phpstan:
+ runs-on: ubuntu-latest
+ needs: [ composer ]
+ strategy:
+ matrix:
+ php: [ 8.2, 8.3, 8.4, 8.5 ]
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: build-artifact-${{ matrix.php }}
+ path: /tmp/github-actions
+
+ - name: Extract build archive
+ run: tar -xvf /tmp/github-actions/build.tar ./
+
+ - name: PHP Static Analysis
+ uses: php-actions/phpstan@v3
+ with:
+ php_version: ${{ matrix.php }}
+ path: src/
+ level: 6
+ memory_limit: 256M
+
+ phpmd:
+ runs-on: ubuntu-latest
+ needs: [ composer ]
+ strategy:
+ matrix:
+ php: [ 8.2, 8.3, 8.4, 8.5 ]
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: build-artifact-${{ matrix.php }}
+ path: /tmp/github-actions
+
+ - name: Extract build archive
+ run: tar -xvf /tmp/github-actions/build.tar ./
+
+ - name: PHP Mess Detector
+ uses: php-actions/phpmd@v1
+ with:
+ php_version: ${{ matrix.php }}
+ path: src/
+ output: text
+ ruleset: phpmd.xml
+
+ phpcs:
+ runs-on: ubuntu-latest
+ needs: [ composer ]
+ strategy:
+ matrix:
+ php: [ 8.2, 8.3, 8.4, 8.5 ]
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: build-artifact-${{ matrix.php }}
+ path: /tmp/github-actions
+
+ - name: Extract build archive
+ run: tar -xvf /tmp/github-actions/build.tar ./
+
+ - name: PHP Code Sniffer
+ uses: php-actions/phpcs@v1
+ with:
+ php_version: ${{ matrix.php }}
+ path: src/
+ standard: phpcs.xml
diff --git a/.gitignore b/.gitignore
index 3c5399a..e38702b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/vendor
-/test/unit/_coverage
+/test/phpunit/_coverage
+/test/phpunit/.phpunit.cache
/.idea
-*.phar
\ No newline at end of file
+*.phar
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
deleted file mode 100644
index dbbd1cb..0000000
--- a/.scrutinizer.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-build:
- environment:
- php:
- version: 7.1.0
- tests:
- override:
- -
- command: 'vendor/bin/phpunit test/unit --coverage-clover coverage --whitelist src'
- coverage:
- file: 'coverage'
- format: 'php-clover'
-
-checks:
- php:
- code_rating: true
- duplication: true
-
-filter:
- excluded_paths:
- - test/*
- - vendor/*
\ No newline at end of file
diff --git a/README.md b/README.md
index e8c2961..6cac016 100644
--- a/README.md
+++ b/README.md
@@ -6,20 +6,20 @@ Sessions are addressed using dot notation, allowing for handling categories of s
***
-
+
-
+
-
+
-
+
## Example usage: Welcome a user by their first name or log out the user
@@ -32,7 +32,7 @@ if($session->contains("auth")) {
}
else {
// Output a variable within the auth namespace:
- $message = "Welcome back, " . $session->get("auth.user.name");
+ $message = "Welcome back, " . $session->getString("auth.user.name");
}
}
else {
@@ -41,3 +41,46 @@ else {
AuthenticationSystem::beginLogin($session->getStore("auth"));
}
```
+
+## Redis session storage
+
+This package now includes `GT\Session\RedisHandler` for shared session storage.
+It works with Redis-compatible backends such as Redis and Valkey, and is intended
+for deployments where application nodes are disposable and session state needs to
+survive traffic moving between servers.
+
+`RedisHandler` expects `save_path` to be a DSN rather than a filesystem path.
+It uses the `phpredis` extension at runtime.
+
+Example production config:
+
+```ini
+[session]
+handler=GT\Session\RedisHandler
+save_path=rediss://default:secret@example-redis.internal:25061/0?prefix=GT:&ttl=1440
+name=GT
+use_cookies=true
+```
+
+Supported DSN forms:
+
+- `redis://host:6379`
+- `redis://:password@host:6379/0`
+- `redis://username:password@host:6379/0`
+- `rediss://username:password@host:6379/0`
+
+Useful query parameters:
+
+- `prefix`: key prefix for stored sessions, defaults to `:`
+- `ttl`: session lifetime in seconds, defaults to `session.gc_maxlifetime`
+- `timeout`: connection timeout in seconds
+- `read_timeout`: socket read timeout in seconds
+- `persistent=1`: enable persistent connections
+- `persistent_id`: optional persistent connection pool id
+- `verify_peer=0` / `verify_peer_name=0`: optional TLS verification flags
+
+# Proudly sponsored by
+
+[JetBrains Open Source sponsorship program](https://www.jetbrains.com/community/opensource/)
+
+[](https://www.jetbrains.com/community/opensource/)
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..ee9f073
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,25 @@
+# Security Policy
+
+## Supported Versions
+
+All MAJOR versions of this package will receive security updates for **two years after the next major version is released**. For example, if version 4.0.0 is released, version 3.x will continue receiving security updates for two years from that date.
+
+Versions outside this window are considered end-of-life and will no longer receive updates, even for critical vulnerabilities.
+
+## Reporting a Vulnerability
+
+If you discover a security issue, please report it using GitHub's [**"Report a vulnerability"** feature](../../security/advisories/new) under the **Security** tab of this repository.
+
+When reporting, please include the following information to help us investigate quickly and thoroughly:
+
+- A clear description of the vulnerability and what part of the code it affects.
+- Steps to reproduce the issue, ideally including:
+ - The affected version
+ - A code snippet or minimal test case
+ - The expected vs. actual behavior
+- If applicable, an explanation of potential impact or severity.
+- Any suggested mitigations or patches (optional, but appreciated).
+
+Please do not disclose the vulnerability publicly until we've had a chance to investigate and publish a fix.
+
+We appreciate responsible disclosure and are committed to resolving issues promptly.
diff --git a/composer.json b/composer.json
index 5f37b3b..d11c730 100644
--- a/composer.json
+++ b/composer.json
@@ -4,20 +4,48 @@
"license": "MIT",
"require": {
- "php": ">=7.2"
+ "php": ">=8.2",
+ "phpgt/typesafegetter": "^1.3"
+ },
+ "suggest": {
+ "ext-redis": "Required to use GT\\Session\\RedisHandler."
},
"require-dev": {
- "phpunit/phpunit": "^8.0"
+ "phpstan/phpstan": "^2.1",
+ "phpunit/phpunit": "^10.1",
+ "phpmd/phpmd": "^2.13",
+ "squizlabs/php_codesniffer": "^3.7"
+ },
+
+ "scripts": {
+ "phpunit": "vendor/bin/phpunit --configuration phpunit.xml",
+ "phpstan": "vendor/bin/phpstan analyse --level 6 src --memory-limit 256M",
+ "phpcs": "vendor/bin/phpcs src --standard=phpcs.xml",
+ "phpmd": "vendor/bin/phpmd src/ text phpmd.xml",
+ "test": [
+ "@phpunit",
+ "@phpstan",
+ "@phpcs",
+ "@phpmd"
+ ]
},
"autoload": {
"psr-4": {
+ "GT\\Session\\": "./src",
"Gt\\Session\\": "./src"
}
},
"autoload-dev": {
"psr-4": {
- "Gt\\Session\\Test\\": "./test/unit"
+ "GT\\Session\\Test\\": "./test/phpunit"
+ }
+ },
+
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/PhpGt"
}
- }
-}
\ No newline at end of file
+ ]
+}
diff --git a/composer.lock b/composer.lock
index a13f63a..807a21f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,42 +4,35 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "39b657e48de8b924fed3a9a11ac33f16",
- "packages": [],
- "packages-dev": [
+ "content-hash": "5bf8b129b89ebdbd2f4b53a66a2b077e",
+ "packages": [
{
- "name": "doctrine/instantiator",
- "version": "1.1.0",
+ "name": "phpgt/typesafegetter",
+ "version": "v1.3.3",
"source": {
"type": "git",
- "url": "https://github.com/doctrine/instantiator.git",
- "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
+ "url": "https://github.com/phpgt/TypeSafeGetter.git",
+ "reference": "a0d339103828791989cbb81f760d252f3c2f8b8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
- "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+ "url": "https://api.github.com/repos/phpgt/TypeSafeGetter/zipball/a0d339103828791989cbb81f760d252f3c2f8b8c",
+ "reference": "a0d339103828791989cbb81f760d252f3c2f8b8c",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "php": ">=8.0"
},
"require-dev": {
- "athletic/athletic": "~0.1.8",
- "ext-pdo": "*",
- "ext-phar": "*",
- "phpunit/phpunit": "^6.2.3",
- "squizlabs/php_codesniffer": "^3.0.2"
+ "phpmd/phpmd": "^2.13",
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^10.1",
+ "squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.2.x-dev"
- }
- },
"autoload": {
"psr-4": {
- "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ "Gt\\TypeSafeGetter\\": "./src"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -48,422 +41,436 @@
],
"authors": [
{
- "name": "Marco Pivetta",
- "email": "ocramius@gmail.com",
- "homepage": "http://ocramius.github.com/"
+ "name": "Greg Bowler",
+ "email": "greg.bowler@g105b.com"
}
],
- "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
- "homepage": "https://github.com/doctrine/instantiator",
- "keywords": [
- "constructor",
- "instantiate"
+ "description": "An interface for objects that expose type-safe getter methods.",
+ "support": {
+ "issues": "https://github.com/phpgt/TypeSafeGetter/issues",
+ "source": "https://github.com/phpgt/TypeSafeGetter/tree/v1.3.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/PhpGt",
+ "type": "github"
+ }
],
- "time": "2017-07-22T11:58:36+00:00"
- },
+ "time": "2026-03-10T22:28:01+00:00"
+ }
+ ],
+ "packages-dev": [
{
- "name": "myclabs/deep-copy",
- "version": "1.8.1",
+ "name": "composer/pcre",
+ "version": "3.3.2",
"source": {
"type": "git",
- "url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8"
+ "url": "https://github.com/composer/pcre.git",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
- "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "php": "^7.4 || ^8.0"
},
- "replace": {
- "myclabs/deep-copy": "self.version"
+ "conflict": {
+ "phpstan/phpstan": "<1.11.10"
},
"require-dev": {
- "doctrine/collections": "^1.0",
- "doctrine/common": "^2.6",
- "phpunit/phpunit": "^7.1"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "DeepCopy\\": "src/DeepCopy/"
- },
- "files": [
- "src/DeepCopy/deep_copy.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Create deep copies (clones) of your objects",
- "keywords": [
- "clone",
- "copy",
- "duplicate",
- "object",
- "object graph"
- ],
- "time": "2018-06-11T23:09:50+00:00"
- },
- {
- "name": "phar-io/manifest",
- "version": "1.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/phar-io/manifest.git",
- "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
- "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-phar": "*",
- "phar-io/version": "^2.0",
- "php": "^5.6 || ^7.0"
+ "phpstan/phpstan": "^1.12 || ^2",
+ "phpstan/phpstan-strict-rules": "^1 || ^2",
+ "phpunit/phpunit": "^8 || ^9"
},
"type": "library",
"extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-main": "3.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Composer\\Pcre\\": "src"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Arne Blankerts",
- "email": "arne@blankerts.de",
- "role": "Developer"
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+ "keywords": [
+ "PCRE",
+ "preg",
+ "regex",
+ "regular expression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/pcre/issues",
+ "source": "https://github.com/composer/pcre/tree/3.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
},
{
- "name": "Sebastian Heuer",
- "email": "sebastian@phpeople.de",
- "role": "Developer"
+ "url": "https://github.com/composer",
+ "type": "github"
},
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "Developer"
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
}
],
- "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
- "time": "2018-07-08T19:23:20+00:00"
+ "time": "2024-11-12T16:29:46+00:00"
},
{
- "name": "phar-io/version",
- "version": "2.0.1",
+ "name": "composer/xdebug-handler",
+ "version": "3.0.5",
"source": {
"type": "git",
- "url": "https://github.com/phar-io/version.git",
- "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
- "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
"shasum": ""
},
"require": {
- "php": "^5.6 || ^7.0"
+ "composer/pcre": "^1 || ^2 || ^3",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
},
"type": "library",
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Arne Blankerts",
- "email": "arne@blankerts.de",
- "role": "Developer"
+ "name": "John Stevenson",
+ "email": "john-stevenson@blueyonder.co.uk"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/xdebug-handler/issues",
+ "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
},
{
- "name": "Sebastian Heuer",
- "email": "sebastian@phpeople.de",
- "role": "Developer"
+ "url": "https://github.com/composer",
+ "type": "github"
},
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "Developer"
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
}
],
- "description": "Library for handling version information and constraints",
- "time": "2018-07-08T19:19:57+00:00"
+ "time": "2024-05-06T16:37:16+00:00"
},
{
- "name": "phpdocumentor/reflection-common",
- "version": "1.0.1",
+ "name": "myclabs/deep-copy",
+ "version": "1.13.4",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
- "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
- "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"shasum": ""
},
"require": {
- "php": ">=5.5"
+ "php": "^7.1 || ^8.0"
+ },
+ "conflict": {
+ "doctrine/collections": "<1.6.8",
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
},
"require-dev": {
- "phpunit/phpunit": "^4.6"
+ "doctrine/collections": "^1.6.8",
+ "doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
"autoload": {
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ],
"psr-4": {
- "phpDocumentor\\Reflection\\": [
- "src"
- ]
+ "DeepCopy\\": "src/DeepCopy/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "authors": [
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
+ },
+ "funding": [
{
- "name": "Jaap van Otterdijk",
- "email": "opensource@ijaap.nl"
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
}
],
- "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
- "homepage": "http://www.phpdoc.org",
- "keywords": [
- "FQSEN",
- "phpDocumentor",
- "phpdoc",
- "reflection",
- "static analysis"
- ],
- "time": "2017-09-11T18:02:19+00:00"
+ "time": "2025-08-01T08:46:24+00:00"
},
{
- "name": "phpdocumentor/reflection-docblock",
- "version": "4.3.0",
+ "name": "nikic/php-parser",
+ "version": "v5.7.0",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "94fd0001232e47129dd3504189fa1c7225010d08"
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
- "reference": "94fd0001232e47129dd3504189fa1c7225010d08",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
- "php": "^7.0",
- "phpdocumentor/reflection-common": "^1.0.0",
- "phpdocumentor/type-resolver": "^0.4.0",
- "webmozart/assert": "^1.0"
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": ">=7.4"
},
"require-dev": {
- "doctrine/instantiator": "~1.0.5",
- "mockery/mockery": "^1.0",
- "phpunit/phpunit": "^6.4"
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^9.0"
},
+ "bin": [
+ "bin/php-parse"
+ ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.x-dev"
+ "dev-master": "5.x-dev"
}
},
"autoload": {
"psr-4": {
- "phpDocumentor\\Reflection\\": [
- "src/"
- ]
+ "PhpParser\\": "lib/PhpParser"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
+ "name": "Nikita Popov"
}
],
- "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2017-11-30T07:14:17+00:00"
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
+ },
+ "time": "2025-12-06T11:56:16+00:00"
},
{
- "name": "phpdocumentor/type-resolver",
- "version": "0.4.0",
+ "name": "pdepend/pdepend",
+ "version": "2.16.2",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
+ "url": "https://github.com/pdepend/pdepend.git",
+ "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
- "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
+ "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
+ "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
"shasum": ""
},
"require": {
- "php": "^5.5 || ^7.0",
- "phpdocumentor/reflection-common": "^1.0"
+ "php": ">=5.3.7",
+ "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0",
+ "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0",
+ "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0",
+ "symfony/polyfill-mbstring": "^1.19"
},
"require-dev": {
- "mockery/mockery": "^0.9.4",
- "phpunit/phpunit": "^5.2||^4.8.24"
+ "easy-doc/easy-doc": "0.0.0|^1.2.3",
+ "gregwar/rst": "^1.0",
+ "squizlabs/php_codesniffer": "^2.0.0"
},
+ "bin": [
+ "src/bin/pdepend"
+ ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
- "phpDocumentor\\Reflection\\": [
- "src/"
- ]
+ "PDepend\\": "src/main/php/PDepend"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
- "authors": [
+ "description": "Official version of pdepend to be handled with Composer",
+ "keywords": [
+ "PHP Depend",
+ "PHP_Depend",
+ "dev",
+ "pdepend"
+ ],
+ "support": {
+ "issues": "https://github.com/pdepend/pdepend/issues",
+ "source": "https://github.com/pdepend/pdepend/tree/2.16.2"
+ },
+ "funding": [
{
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
+ "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend",
+ "type": "tidelift"
}
],
- "time": "2017-07-14T14:27:02+00:00"
+ "time": "2023-12-17T18:09:59+00:00"
},
{
- "name": "phpspec/prophecy",
- "version": "1.8.0",
+ "name": "phar-io/manifest",
+ "version": "2.0.4",
"source": {
"type": "git",
- "url": "https://github.com/phpspec/prophecy.git",
- "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
- "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.0.2",
- "php": "^5.3|^7.0",
- "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
- "sebastian/comparator": "^1.1|^2.0|^3.0",
- "sebastian/recursion-context": "^1.0|^2.0|^3.0"
- },
- "require-dev": {
- "phpspec/phpspec": "^2.5|^3.2",
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-phar": "*",
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.8.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
- "psr-0": {
- "Prophecy\\": "src/"
- }
+ "classmap": [
+ "src/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Konstantin Kudryashov",
- "email": "ever.zet@gmail.com",
- "homepage": "http://everzet.com"
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
},
{
- "name": "Marcello Duarte",
- "email": "marcello.duarte@gmail.com"
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
}
],
- "description": "Highly opinionated mocking framework for PHP 5.3+",
- "homepage": "https://github.com/phpspec/prophecy",
- "keywords": [
- "Double",
- "Dummy",
- "fake",
- "mock",
- "spy",
- "stub"
- ],
- "time": "2018-08-05T17:53:17+00:00"
+ "time": "2024-03-03T12:33:53+00:00"
},
{
- "name": "phpunit/php-code-coverage",
- "version": "7.0.2",
+ "name": "phar-io/version",
+ "version": "3.2.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "cfca9c5f7f2694ca0c7749ffb142927d9f05250f"
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cfca9c5f7f2694ca0c7749ffb142927d9f05250f",
- "reference": "cfca9c5f7f2694ca0c7749ffb142927d9f05250f",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
"shasum": ""
},
"require": {
- "ext-dom": "*",
- "ext-xmlwriter": "*",
- "php": "^7.2",
- "phpunit/php-file-iterator": "^2.0.2",
- "phpunit/php-text-template": "^1.2.1",
- "phpunit/php-token-stream": "^3.0.1",
- "sebastian/code-unit-reverse-lookup": "^1.0.1",
- "sebastian/environment": "^4.1",
- "sebastian/version": "^2.0.1",
- "theseer/tokenizer": "^1.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.0"
- },
- "suggest": {
- "ext-xdebug": "^2.6.1"
+ "php": "^7.2 || ^8.0"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "7.0-dev"
- }
- },
"autoload": {
"classmap": [
"src/"
@@ -474,51 +481,65 @@
"BSD-3-Clause"
],
"authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
- "role": "lead"
+ "role": "Developer"
}
],
- "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
- "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
- "keywords": [
- "coverage",
- "testing",
- "xunit"
- ],
- "time": "2019-02-15T13:40:27+00:00"
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
},
{
- "name": "phpunit/php-file-iterator",
- "version": "2.0.2",
+ "name": "phpmd/phpmd",
+ "version": "2.15.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "050bedf145a257b1ff02746c31894800e5122946"
+ "url": "https://github.com/phpmd/phpmd.git",
+ "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
- "reference": "050bedf145a257b1ff02746c31894800e5122946",
+ "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0",
+ "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0",
+ "ext-xml": "*",
+ "pdepend/pdepend": "^2.16.1",
+ "php": ">=5.3.9"
},
"require-dev": {
- "phpunit/phpunit": "^7.1"
+ "easy-doc/easy-doc": "0.0.0 || ^1.3.2",
+ "ext-json": "*",
+ "ext-simplexml": "*",
+ "gregwar/rst": "^1.0",
+ "mikey179/vfsstream": "^1.6.8",
+ "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2"
},
+ "bin": [
+ "src/bin/phpmd"
+ ],
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-0": {
+ "PHPMD\\": "src/main/php"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -526,84 +547,139 @@
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "name": "Manuel Pichler",
+ "email": "github@manuel-pichler.de",
+ "homepage": "https://github.com/manuelpichler",
+ "role": "Project Founder"
+ },
+ {
+ "name": "Marc Würth",
+ "email": "ravage@bluewin.ch",
+ "homepage": "https://github.com/ravage84",
+ "role": "Project Maintainer"
+ },
+ {
+ "name": "Other contributors",
+ "homepage": "https://github.com/phpmd/phpmd/graphs/contributors",
+ "role": "Contributors"
}
],
- "description": "FilterIterator implementation that filters files based on a list of suffixes.",
- "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.",
+ "homepage": "https://phpmd.org/",
"keywords": [
- "filesystem",
- "iterator"
+ "dev",
+ "mess detection",
+ "mess detector",
+ "pdepend",
+ "phpmd",
+ "pmd"
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.org/phpmd",
+ "issues": "https://github.com/phpmd/phpmd/issues",
+ "source": "https://github.com/phpmd/phpmd/tree/2.15.0"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd",
+ "type": "tidelift"
+ }
],
- "time": "2018-09-13T20:33:42+00:00"
+ "time": "2023-12-11T08:22:20+00:00"
},
{
- "name": "phpunit/php-text-template",
- "version": "1.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
- },
+ "name": "phpstan/phpstan",
+ "version": "2.1.51",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
- "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc3b523c45e714c70de2ac5113b958223b55dc59",
+ "reference": "dc3b523c45e714c70de2ac5113b958223b55dc59",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^7.4|^8.0"
},
+ "conflict": {
+ "phpstan/phpstan-shim": "*"
+ },
+ "bin": [
+ "phpstan",
+ "phpstan.phar"
+ ],
"type": "library",
"autoload": {
- "classmap": [
- "src/"
+ "files": [
+ "bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
- "authors": [
+ "description": "PHPStan - PHP Static Analysis Tool",
+ "keywords": [
+ "dev",
+ "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",
+ "security": "https://github.com/phpstan/phpstan/security/policy",
+ "source": "https://github.com/phpstan/phpstan-src"
+ },
+ "funding": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "url": "https://github.com/ondrejmirtes",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/phpstan",
+ "type": "github"
}
],
- "description": "Simple template engine.",
- "homepage": "https://github.com/sebastianbergmann/php-text-template/",
- "keywords": [
- "template"
- ],
- "time": "2015-06-21T13:50:34+00:00"
+ "time": "2026-04-21T18:22:01+00:00"
},
{
- "name": "phpunit/php-timer",
- "version": "2.1.1",
+ "name": "phpunit/php-code-coverage",
+ "version": "10.1.16",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059"
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b389aebe1b8b0578430bda0c7c95a829608e059",
- "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^4.19.1 || ^5.1.0",
+ "php": ">=8.1",
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "sebastian/code-unit-reverse-lookup": "^3.0.0",
+ "sebastian/complexity": "^3.2.0",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/lines-of-code": "^2.0.2",
+ "sebastian/version": "^4.0.1",
+ "theseer/tokenizer": "^1.2.3"
},
"require-dev": {
- "phpunit/phpunit": "^7.0"
+ "phpunit/phpunit": "^10.1"
+ },
+ "suggest": {
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-main": "10.1.x-dev"
}
},
"autoload": {
@@ -622,38 +698,50 @@
"role": "lead"
}
],
- "description": "Utility class for timing",
- "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
- "timer"
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
],
- "time": "2019-02-20T10:12:59+00:00"
+ "time": "2024-08-22T04:31:57+00:00"
},
{
- "name": "phpunit/php-token-stream",
- "version": "3.0.1",
+ "name": "phpunit/php-file-iterator",
+ "version": "4.1.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18"
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18",
- "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
+ "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
"shasum": ""
},
"require": {
- "ext-tokenizer": "*",
- "php": "^7.1"
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^7.0"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -668,71 +756,57 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Wrapper around PHP's tokenizer extension.",
- "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
- "tokenizer"
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
],
- "time": "2018-10-30T05:52:18+00:00"
+ "time": "2023-08-31T06:24:48+00:00"
},
{
- "name": "phpunit/phpunit",
- "version": "8.0.4",
+ "name": "phpunit/php-invoker",
+ "version": "4.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "a7af0201285445c9c73c4bdf869c486e36b41604"
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a7af0201285445c9c73c4bdf869c486e36b41604",
- "reference": "a7af0201285445c9c73c4bdf869c486e36b41604",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+ "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.1",
- "ext-dom": "*",
- "ext-json": "*",
- "ext-libxml": "*",
- "ext-mbstring": "*",
- "ext-xml": "*",
- "ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.7",
- "phar-io/manifest": "^1.0.2",
- "phar-io/version": "^2.0",
- "php": "^7.2",
- "phpspec/prophecy": "^1.7",
- "phpunit/php-code-coverage": "^7.0",
- "phpunit/php-file-iterator": "^2.0.1",
- "phpunit/php-text-template": "^1.2.1",
- "phpunit/php-timer": "^2.0",
- "sebastian/comparator": "^3.0",
- "sebastian/diff": "^3.0",
- "sebastian/environment": "^4.1",
- "sebastian/exporter": "^3.1",
- "sebastian/global-state": "^3.0",
- "sebastian/object-enumerator": "^3.0.3",
- "sebastian/resource-operations": "^2.0",
- "sebastian/version": "^2.0.1"
+ "php": ">=8.1"
},
"require-dev": {
- "ext-pdo": "*"
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^10.0"
},
"suggest": {
- "ext-soap": "*",
- "ext-xdebug": "*",
- "phpunit/php-invoker": "^2.0"
+ "ext-pcntl": "*"
},
- "bin": [
- "phpunit"
- ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "8.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -751,39 +825,47 @@
"role": "lead"
}
],
- "description": "The PHP Unit Testing framework.",
- "homepage": "https://phpunit.de/",
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
"keywords": [
- "phpunit",
- "testing",
- "xunit"
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
],
- "time": "2019-02-18T09:23:05+00:00"
+ "time": "2023-02-03T06:56:09+00:00"
},
{
- "name": "sebastian/code-unit-reverse-lookup",
- "version": "1.0.1",
+ "name": "phpunit/php-text-template",
+ "version": "3.0.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
- "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
- "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+ "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
"shasum": ""
},
"require": {
- "php": "^5.6 || ^7.0"
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^5.7 || ^6.0"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-main": "3.0-dev"
}
},
"autoload": {
@@ -798,39 +880,52 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Looks up which function or method a line of code belongs to",
- "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
- "time": "2017-03-04T06:30:41+00:00"
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-31T14:07:24+00:00"
},
{
- "name": "sebastian/comparator",
- "version": "3.0.2",
+ "name": "phpunit/php-timer",
+ "version": "6.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
- "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+ "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
"shasum": ""
},
"require": {
- "php": "^7.1",
- "sebastian/diff": "^3.0",
- "sebastian/exporter": "^3.1"
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^7.1"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -843,60 +938,87 @@
"BSD-3-Clause"
],
"authors": [
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Volker Dusch",
- "email": "github@wallbash.com"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@2bepublished.at"
- },
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Provides the functionality to compare PHP values for equality",
- "homepage": "https://github.com/sebastianbergmann/comparator",
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
- "comparator",
- "compare",
- "equality"
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
],
- "time": "2018-07-12T15:12:46+00:00"
+ "time": "2023-02-03T06:57:52+00:00"
},
{
- "name": "sebastian/diff",
- "version": "3.0.2",
+ "name": "phpunit/phpunit",
+ "version": "10.5.63",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29"
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "33198268dad71e926626b618f3ec3966661e4d90"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
- "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90",
+ "reference": "33198268dad71e926626b618f3ec3966661e4d90",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.13.4",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
+ "php": ">=8.1",
+ "phpunit/php-code-coverage": "^10.1.16",
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-invoker": "^4.0.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "phpunit/php-timer": "^6.0.0",
+ "sebastian/cli-parser": "^2.0.1",
+ "sebastian/code-unit": "^2.0.0",
+ "sebastian/comparator": "^5.0.5",
+ "sebastian/diff": "^5.1.1",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/exporter": "^5.1.4",
+ "sebastian/global-state": "^6.0.2",
+ "sebastian/object-enumerator": "^5.0.0",
+ "sebastian/recursion-context": "^5.0.1",
+ "sebastian/type": "^4.0.0",
+ "sebastian/version": "^4.0.1"
},
- "require-dev": {
- "phpunit/phpunit": "^7.5 || ^8.0",
- "symfony/process": "^2 || ^3.3 || ^4"
+ "suggest": {
+ "ext-soap": "To be able to generate mocks based on WSDL files"
},
+ "bin": [
+ "phpunit"
+ ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "10.5-dev"
}
},
"autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
"classmap": [
"src/"
]
@@ -906,175 +1028,175 @@
"BSD-3-Clause"
],
"authors": [
- {
- "name": "Kore Nordmann",
- "email": "mail@kore-nordmann.de"
- },
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Diff implementation",
- "homepage": "https://github.com/sebastianbergmann/diff",
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
"keywords": [
- "diff",
- "udiff",
- "unidiff",
- "unified diff"
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+ "type": "tidelift"
+ }
],
- "time": "2019-02-04T06:01:07+00:00"
+ "time": "2026-01-27T05:48:37+00:00"
},
{
- "name": "sebastian/environment",
- "version": "4.1.0",
+ "name": "psr/container",
+ "version": "2.0.2",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656"
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6fda8ce1974b62b14935adc02a9ed38252eca656",
- "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"shasum": ""
},
"require": {
- "php": "^7.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^7.5"
- },
- "suggest": {
- "ext-posix": "*"
+ "php": ">=7.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.1-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
}
],
- "description": "Provides functionality to handle HHVM/PHP environments",
- "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
"keywords": [
- "Xdebug",
- "environment",
- "hhvm"
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
],
- "time": "2019-02-01T05:27:49+00:00"
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
},
{
- "name": "sebastian/exporter",
- "version": "3.1.0",
+ "name": "psr/log",
+ "version": "3.0.2",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "234199f4528de6d12aaa58b612e98f7d36adb937"
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937",
- "reference": "234199f4528de6d12aaa58b612e98f7d36adb937",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
- "php": "^7.0",
- "sebastian/recursion-context": "^3.0"
- },
- "require-dev": {
- "ext-mbstring": "*",
- "phpunit/phpunit": "^6.0"
+ "php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.1.x-dev"
+ "dev-master": "3.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Volker Dusch",
- "email": "github@wallbash.com"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@2bepublished.at"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
- {
- "name": "Adam Harvey",
- "email": "aharvey@php.net"
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
}
],
- "description": "Provides the functionality to export PHP variables for visualization",
- "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
"keywords": [
- "export",
- "exporter"
+ "log",
+ "psr",
+ "psr-3"
],
- "time": "2017-04-03T13:19:02+00:00"
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
},
{
- "name": "sebastian/global-state",
- "version": "3.0.0",
+ "name": "sebastian/cli-parser",
+ "version": "2.0.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4"
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
- "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
+ "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
"shasum": ""
},
"require": {
- "php": "^7.2",
- "sebastian/object-reflector": "^1.1.1",
- "sebastian/recursion-context": "^3.0"
+ "php": ">=8.1"
},
"require-dev": {
- "ext-dom": "*",
- "phpunit/phpunit": "^8.0"
- },
- "suggest": {
- "ext-uopz": "*"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "2.0-dev"
}
},
"autoload": {
@@ -1089,42 +1211,49 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Snapshotting of global state",
- "homepage": "http://www.github.com/sebastianbergmann/global-state",
- "keywords": [
- "global state"
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
],
- "time": "2019-02-01T05:30:01+00:00"
+ "time": "2024-03-02T07:12:49+00:00"
},
{
- "name": "sebastian/object-enumerator",
- "version": "3.0.3",
+ "name": "sebastian/code-unit",
+ "version": "2.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
+ "url": "https://github.com/sebastianbergmann/code-unit.git",
+ "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
- "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
+ "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
"shasum": ""
},
"require": {
- "php": "^7.0",
- "sebastian/object-reflector": "^1.1.1",
- "sebastian/recursion-context": "^3.0"
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^6.0"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0.x-dev"
+ "dev-main": "2.0-dev"
}
},
"autoload": {
@@ -1139,37 +1268,48 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Traverses array structures and object graphs to enumerate all referenced objects",
- "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
- "time": "2017-08-03T12:35:26+00:00"
+ "description": "Collection of value objects that represent the PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/code-unit",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:58:43+00:00"
},
{
- "name": "sebastian/object-reflector",
- "version": "1.1.1",
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "3.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/object-reflector.git",
- "reference": "773f97c67f28de00d397be301821b06708fca0be"
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
- "reference": "773f97c67f28de00d397be301821b06708fca0be",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+ "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
"shasum": ""
},
"require": {
- "php": "^7.0"
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^6.0"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-main": "3.0-dev"
}
},
"autoload": {
@@ -1187,34 +1327,48 @@
"email": "sebastian@phpunit.de"
}
],
- "description": "Allows reflection of object attributes, including inherited and non-public ones",
- "homepage": "https://github.com/sebastianbergmann/object-reflector/",
- "time": "2017-03-29T09:07:27+00:00"
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:59:15+00:00"
},
{
- "name": "sebastian/recursion-context",
- "version": "3.0.0",
+ "name": "sebastian/comparator",
+ "version": "5.0.5",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
- "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d",
+ "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d",
"shasum": ""
},
"require": {
- "php": "^7.0"
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.1",
+ "sebastian/diff": "^5.0",
+ "sebastian/exporter": "^5.0"
},
"require-dev": {
- "phpunit/phpunit": "^6.0"
+ "phpunit/phpunit": "^10.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0.x-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -1227,44 +1381,80 @@
"BSD-3-Clause"
],
"authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
},
{
- "name": "Adam Harvey",
- "email": "aharvey@php.net"
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
}
],
- "description": "Provides functionality to recursively process PHP variables",
- "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2017-03-03T06:23:57+00:00"
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-01-24T09:25:16+00:00"
},
{
- "name": "sebastian/resource-operations",
- "version": "2.0.1",
+ "name": "sebastian/complexity",
+ "version": "3.2.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/resource-operations.git",
- "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9"
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "68ff824baeae169ec9f2137158ee529584553799"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
- "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
+ "reference": "68ff824baeae169ec9f2137158ee529584553799",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "nikic/php-parser": "^4.18 || ^5.0",
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-main": "3.2-dev"
}
},
"autoload": {
@@ -1279,34 +1469,50 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
}
],
- "description": "Provides a list of PHP built-in functions that operate on resources",
- "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
- "time": "2018-10-04T04:07:39+00:00"
+ "time": "2023-12-21T08:37:17+00:00"
},
{
- "name": "sebastian/version",
- "version": "2.0.1",
+ "name": "sebastian/diff",
+ "version": "5.1.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/version.git",
- "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
- "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
+ "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
"shasum": ""
},
"require": {
- "php": ">=5.6"
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0",
+ "symfony/process": "^6.4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-main": "5.1-dev"
}
},
"autoload": {
@@ -1321,93 +1527,217 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
}
],
- "description": "Library that helps with managing the version number of Git-hosted PHP projects",
- "homepage": "https://github.com/sebastianbergmann/version",
- "time": "2016-10-03T07:35:21+00:00"
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-02T07:15:17+00:00"
},
{
- "name": "symfony/polyfill-ctype",
- "version": "v1.10.0",
+ "name": "sebastian/environment",
+ "version": "6.1.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
- "reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
+ "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
},
"suggest": {
- "ext-ctype": "For best performance"
+ "ext-posix": "*"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.9-dev"
+ "dev-main": "6.1-dev"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- },
- "files": [
- "bootstrap.php"
+ "classmap": [
+ "src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "https://github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-23T08:47:14+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "5.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "0735b90f4da94969541dac1da743446e276defa6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6",
+ "reference": "0735b90f4da94969541dac1da743446e276defa6",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=8.1",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
},
{
- "name": "Gert de Pagter",
- "email": "BackEndTea@gmail.com"
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
}
],
- "description": "Symfony polyfill for ctype functions",
- "homepage": "https://symfony.com",
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
"keywords": [
- "compatibility",
- "ctype",
- "polyfill",
- "portable"
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
+ }
],
- "time": "2018-08-06T14:22:27+00:00"
+ "time": "2025-09-24T06:09:11+00:00"
},
{
- "name": "theseer/tokenizer",
- "version": "1.1.0",
+ "name": "sebastian/global-state",
+ "version": "6.0.2",
"source": {
"type": "git",
- "url": "https://github.com/theseer/tokenizer.git",
- "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b"
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b",
- "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
+ "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
"shasum": ""
},
"require": {
+ "php": ">=8.1",
+ "sebastian/object-reflector": "^3.0",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
"ext-dom": "*",
- "ext-tokenizer": "*",
- "ext-xmlwriter": "*",
- "php": "^7.0"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
"autoload": {
"classmap": [
"src/"
@@ -1419,73 +1749,1157 @@
],
"authors": [
{
- "name": "Arne Blankerts",
- "email": "arne@blankerts.de",
- "role": "Developer"
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
}
],
- "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
- "time": "2017-04-07T12:08:54+00:00"
+ "description": "Snapshotting of global state",
+ "homepage": "https://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-02T07:19:19+00:00"
},
{
- "name": "webmozart/assert",
- "version": "1.4.0",
+ "name": "sebastian/lines-of-code",
+ "version": "2.0.2",
"source": {
"type": "git",
- "url": "https://github.com/webmozart/assert.git",
- "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9"
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9",
- "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
+ "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
"shasum": ""
},
"require": {
- "php": "^5.3.3 || ^7.0",
- "symfony/polyfill-ctype": "^1.8"
+ "nikic/php-parser": "^4.18 || ^5.0",
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^4.6",
- "sebastian/version": "^1.0.1"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.3-dev"
+ "dev-main": "2.0-dev"
}
},
"autoload": {
- "psr-4": {
- "Webmozart\\Assert\\": "src/"
- }
+ "classmap": [
+ "src/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Assertions to validate method input/output with nice error messages.",
- "keywords": [
- "assert",
- "check",
- "validate"
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-12-21T08:38:20+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
+ "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "sebastian/object-reflector": "^3.0",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:08:32+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
+ "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:06:18+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "5.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a",
+ "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-10T07:50:56+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
+ "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:10:45+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+ "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-07T11:34:05+00:00"
+ },
+ {
+ "name": "squizlabs/php_codesniffer",
+ "version": "3.13.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
+ "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4",
+ "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4",
+ "shasum": ""
+ },
+ "require": {
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
+ },
+ "bin": [
+ "bin/phpcbf",
+ "bin/phpcs"
+ ],
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Greg Sherwood",
+ "role": "Former lead"
+ },
+ {
+ "name": "Juliette Reinders Folmer",
+ "role": "Current lead"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
+ }
+ ],
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
+ "keywords": [
+ "phpcs",
+ "standards",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
+ "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
+ "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
+ "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/PHPCSStandards",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/jrfnl",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/php_codesniffer",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/phpcsstandards",
+ "type": "thanks_dev"
+ }
+ ],
+ "time": "2025-11-04T16:30:35+00:00"
+ },
+ {
+ "name": "symfony/config",
+ "version": "v7.4.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/config.git",
+ "reference": "2d19dde43fa2ff720b9a40763ace7226594f503b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/config/zipball/2d19dde43fa2ff720b9a40763ace7226594f503b",
+ "reference": "2d19dde43fa2ff720b9a40763ace7226594f503b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/filesystem": "^7.1|^8.0",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "conflict": {
+ "symfony/finder": "<6.4",
+ "symfony/service-contracts": "<2.5"
+ },
+ "require-dev": {
+ "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
+ "symfony/finder": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/yaml": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Config\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/config/tree/v7.4.8"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-03-24T13:12:05+00:00"
+ },
+ {
+ "name": "symfony/dependency-injection",
+ "version": "v7.4.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/dependency-injection.git",
+ "reference": "f7025fd7b687c240426562f86ada06a93b1e771d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f7025fd7b687c240426562f86ada06a93b1e771d",
+ "reference": "f7025fd7b687c240426562f86ada06a93b1e771d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/service-contracts": "^3.6",
+ "symfony/var-exporter": "^6.4.20|^7.2.5|^8.0"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2",
+ "symfony/config": "<6.4",
+ "symfony/finder": "<6.4",
+ "symfony/yaml": "<6.4"
+ },
+ "provide": {
+ "psr/container-implementation": "1.1|2.0",
+ "symfony/service-implementation": "1.1|2.0|3.0"
+ },
+ "require-dev": {
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/yaml": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\DependencyInjection\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Allows you to standardize and centralize the way objects are constructed in your application",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/dependency-injection/tree/v7.4.8"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-03-31T06:50:29+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v7.4.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "58b9790d12f9670b7f53a1c1738febd3108970a5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/58b9790d12f9670b7f53a1c1738febd3108970a5",
+ "reference": "58b9790d12f9670b7f53a1c1738febd3108970a5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "require-dev": {
+ "symfony/process": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v7.4.8"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-03-24T13:12:05+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.36.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2",
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.36.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-04-10T16:19:22+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.36.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315",
+ "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.36.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-04-10T17:25:58+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v3.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-15T11:30:57+00:00"
+ },
+ {
+ "name": "symfony/var-exporter",
+ "version": "v7.4.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/var-exporter.git",
+ "reference": "398907e89a2a56fe426f7955c6fa943ec0c77225"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/var-exporter/zipball/398907e89a2a56fe426f7955c6fa943ec0c77225",
+ "reference": "398907e89a2a56fe426f7955c6fa943ec0c77225",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "require-dev": {
+ "symfony/property-access": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\VarExporter\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "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": "Allows exporting any serializable PHP data structure to plain PHP code",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "clone",
+ "construct",
+ "export",
+ "hydrate",
+ "instantiate",
+ "lazy-loading",
+ "proxy",
+ "serialize"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/var-exporter/tree/v7.4.8"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-03-24T13:12:05+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/1.3.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
],
- "time": "2018-12-25T11:19:39+00:00"
+ "time": "2025-11-17T20:03:58+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=7.2"
+ "php": ">=8.2"
},
- "platform-dev": []
+ "platform-dev": {},
+ "plugin-api-version": "2.9.0"
}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..2d2aff4
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,64 @@
+
+
+ Created from PHP.Gt/Styleguide
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpmd.xml b/phpmd.xml
new file mode 100644
index 0000000..d125c4d
--- /dev/null
+++ b/phpmd.xml
@@ -0,0 +1,50 @@
+
+
+ Custom ruleset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..5e1b5d9
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+ ./test/phpunit/
+
+
+
+
+
+
+
+
+
+ src/
+
+
+
+
diff --git a/src/FileHandler.php b/src/FileHandler.php
index fce69be..71f82c1 100644
--- a/src/FileHandler.php
+++ b/src/FileHandler.php
@@ -1,28 +1,30 @@
$cache */
+ protected array $cache;
/**
* @link http://php.net/manual/en/sessionhandlerinterface.open.php
- * @param string $save_path The path where to store/retrieve the session.
+ * @param string $savePath The path where to store/retrieve the session.
* @param string $name The session name.
*/
- public function open($save_path, $name):bool {
+ public function open(string $savePath, string $name):bool {
$success = true;
- $save_path = str_replace(
+ $savePath = str_replace(
["/", "\\"],
DIRECTORY_SEPARATOR,
- $save_path
+ $savePath
);
$this->path = implode(DIRECTORY_SEPARATOR, [
- $save_path,
+ $savePath,
$name,
]);
@@ -33,48 +35,40 @@ public function open($save_path, $name):bool {
return $success;
}
- /**
- * @link http://php.net/manual/en/sessionhandlerinterface.close.php
- */
+ /** @link http://php.net/manual/en/sessionhandlerinterface.close.php */
public function close():bool {
return true;
}
- /**
- * @link http://php.net/manual/en/sessionhandlerinterface.read.php
- * @param string $session_id
- */
- public function read($session_id):string {
- if(isset($this->cache[$session_id])) {
- return $this->cache[$session_id];
+ /** @link http://php.net/manual/en/sessionhandlerinterface.read.php */
+ public function read(string $sessionId):string {
+ if(isset($this->cache[$sessionId])) {
+ return $this->cache[$sessionId];
}
- $filePath = $this->getFilePath($session_id);
+ $filePath = $this->getFilePath($sessionId);
if(!file_exists($filePath)) {
return "";
}
- $this->cache[$session_id] = file_get_contents($filePath);
- return $this->cache[$session_id];
+ $this->cache[$sessionId] = file_get_contents($filePath) ?: "";
+ return $this->cache[$sessionId];
}
- /**
- * @link http://php.net/manual/en/sessionhandlerinterface.write.php
- * @param string $session_id
- * @param string $session_data
- */
- public function write($session_id, $session_data):bool {
- $filePath = $this->getFilePath($session_id);
- return file_put_contents($filePath, $session_data) > 0;
+ /** @link http://php.net/manual/en/sessionhandlerinterface.write.php */
+ public function write(string $sessionId, string $sessionData):bool {
+ if($sessionData === self::EMPTY_PHP_ARRAY) {
+ return true;
+ }
+ $filePath = $this->getFilePath($sessionId);
+ $bytesWritten = file_put_contents($filePath, $sessionData);
+ return $bytesWritten !== false;
}
- /**
- * @link http://php.net/manual/en/sessionhandlerinterface.destroy.php
- * @param string $session_id
- */
- public function destroy($session_id):bool {
- $filePath = $this->getFilePath($session_id);
+ /** @link http://php.net/manual/en/sessionhandlerinterface.destroy.php */
+ public function destroy(string $id = ""):bool {
+ $filePath = $this->getFilePath($id);
if(file_exists($filePath)) {
return unlink($filePath);
@@ -83,13 +77,11 @@ public function destroy($session_id):bool {
return true;
}
- /**
- * @link http://php.net/manual/en/sessionhandlerinterface.gc.php
- * @param int $maxlifetime
- */
- public function gc($maxlifetime):bool {
+ /** @link http://php.net/manual/en/sessionhandlerinterface.gc.php */
+ public function gc(int $maxLifeTime):int|false {
$now = time();
- $expired = $now - $maxlifetime;
+ $expired = $now - $maxLifeTime;
+ $num = 0;
foreach(new DirectoryIterator($this->path) as $fileInfo) {
if(!$fileInfo->isFile()) {
@@ -101,10 +93,11 @@ public function gc($maxlifetime):bool {
if(!unlink($fileInfo->getPathname())) {
return false;
}
+ $num++;
}
}
- return true;
+ return $num;
}
protected function getFilePath(string $id):string {
@@ -113,4 +106,4 @@ protected function getFilePath(string $id):string {
$id,
]);
}
-}
\ No newline at end of file
+}
diff --git a/src/Flash.php b/src/Flash.php
new file mode 100644
index 0000000..34b9aa8
--- /dev/null
+++ b/src/Flash.php
@@ -0,0 +1,32 @@
+session->get("queue.$name");
+ if(!$queue) {
+ $queue = new SplQueue();
+ $this->session->set("queue.$name", $queue);
+ }
+
+ $queue->enqueue(new FlashMessage($name, $message));
+ }
+
+ public function consume(string $name):?FlashMessage {
+ /** @var null|SplQueue $queue */
+ $queue = $this->session->get("queue.$name");
+ try {
+ return $queue->dequeue();
+ }
+ catch(RuntimeException $e) {
+ $this->session->remove("queue.$name");
+ return null;
+ }
+ }
+
+}
diff --git a/src/FlashMessage.php b/src/FlashMessage.php
new file mode 100644
index 0000000..a3a3394
--- /dev/null
+++ b/src/FlashMessage.php
@@ -0,0 +1,9 @@
+parseSavePath($savePath, $name);
+ $this->config = $config;
+ return $this->connect($config);
+ }
+
+ /** @param array{
+ * host:string,
+ * port:int,
+ * timeout:float,
+ * readTimeout:float,
+ * persistentId:?string,
+ * prefix:string,
+ * ttl:int,
+ * database:int,
+ * auth:array{string,string}|string|null,
+ * context:array{stream:array{verify_peer:bool,verify_peer_name:bool}}|null
+ * } $config
+ */
+ private function connect(array $config):bool {
+ $client = $this->createClient();
+
+ $connected = $client->connect(
+ $config["host"],
+ $config["port"],
+ $config["timeout"],
+ $config["persistentId"],
+ 0,
+ $config["readTimeout"],
+ $config["context"],
+ );
+
+ if(!$connected) {
+ return false;
+ }
+
+ if($config["auth"] !== null && !$client->auth($config["auth"])) {
+ return false;
+ }
+
+ if($config["database"] > 0 && !$client->select($config["database"])) {
+ return false;
+ }
+
+ $this->client = $client;
+ $this->prefix = $config["prefix"];
+ $this->ttl = $config["ttl"];
+ return true;
+ }
+
+ public function close():bool {
+ if(is_null($this->client)) {
+ return true;
+ }
+
+ try {
+ return $this->client->close();
+ }
+ catch(Throwable) {
+ return true;
+ }
+ finally {
+ $this->client = null;
+ }
+ }
+
+ public function read(string $sessionId):string {
+ $value = $this->retryOnce(
+ fn() => $this->requireClient()->get($this->getKey($sessionId))
+ );
+ return is_string($value) ? $value : "";
+ }
+
+ public function write(string $sessionId, string $sessionData):bool {
+ if($sessionData === self::EMPTY_PHP_ARRAY) {
+ return true;
+ }
+
+ $key = $this->getKey($sessionId);
+
+ if($this->ttl > 0) {
+ return $this->retryOnce(
+ fn() => $this->requireClient()->setEx($key, $this->ttl, $sessionData)
+ );
+ }
+
+ return $this->retryOnce(
+ fn() => $this->requireClient()->set($key, $sessionData)
+ );
+ }
+
+ public function destroy(string $id = ""):bool {
+ return $this->retryOnce(
+ fn() => $this->requireClient()->del($this->getKey($id))
+ ) >= 0;
+ }
+
+ // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
+ public function gc(int $maxLifeTime):int|false {
+ return 0;
+ }
+ // phpcs:enable
+
+ /**
+ * @return array{
+ * host:string,
+ * port:int,
+ * timeout:float,
+ * readTimeout:float,
+ * persistentId:?string,
+ * prefix:string,
+ * ttl:int,
+ * database:int,
+ * auth:array{string,string}|string|null,
+ * context:array{stream:array{verify_peer:bool,verify_peer_name:bool}}|null
+ * }
+ */
+ private function parseSavePath(string $savePath, string $name):array {
+ $parts = parse_url($savePath);
+ if($parts === false || !isset($parts["host"])) {
+ throw new RuntimeException("Invalid Redis save_path DSN.");
+ }
+
+ parse_str($parts["query"] ?? "", $query);
+
+ [$host, $context] = $this->parseHostAndContext($parts, $query);
+
+ return [
+ "host" => $host,
+ "port" => (int)($parts["port"] ?? self::DEFAULT_PORT),
+ "timeout" => (float)($query["timeout"] ?? 0),
+ "readTimeout" => (float)($query["read_timeout"] ?? 0),
+ "persistentId" => $this->parsePersistentId($query),
+ "prefix" => $this->parsePrefix($query, $name),
+ "ttl" => (int)($query["ttl"] ?? ini_get("session.gc_maxlifetime")),
+ "database" => $this->parseDatabase($parts),
+ "auth" => $this->parseAuth($parts),
+ "context" => $context,
+ ];
+ }
+
+ /**
+ * @param array $parts
+ * @param array $query
+ * @return array{
+ * 0:string,
+ * 1:array{stream:array{verify_peer:bool,verify_peer_name:bool}}|null
+ * }
+ */
+ private function parseHostAndContext(array $parts, array $query):array {
+ $scheme = strtolower($parts["scheme"] ?? "redis");
+ $host = $parts["host"];
+
+ if(!in_array($scheme, ["rediss", "tls"], true)) {
+ return [$host, null];
+ }
+
+ return [
+ "tls://$host",
+ [
+ "stream" => [
+ "verify_peer" => filter_var(
+ $query["verify_peer"] ?? true,
+ FILTER_VALIDATE_BOOL
+ ),
+ "verify_peer_name" => filter_var(
+ $query["verify_peer_name"] ?? true,
+ FILTER_VALIDATE_BOOL
+ ),
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @param array $parts
+ * @return array{string,string}|string|null
+ */
+ private function parseAuth(array $parts):array|string|null {
+ if(isset($parts["user"]) && $parts["user"] !== "" && isset($parts["pass"])) {
+ return [rawurldecode($parts["user"]), rawurldecode($parts["pass"])];
+ }
+
+ if(isset($parts["pass"])) {
+ return rawurldecode($parts["pass"]);
+ }
+
+ return null;
+ }
+
+ /**
+ * @param array $query
+ */
+ private function parsePersistentId(array $query):?string {
+ if(
+ !isset($query["persistent"])
+ || !filter_var($query["persistent"], FILTER_VALIDATE_BOOL)
+ ) {
+ return null;
+ }
+
+ return is_string($query["persistent_id"] ?? null)
+ ? $query["persistent_id"]
+ : "phpgt-session";
+ }
+
+ /**
+ * @param array $query
+ */
+ private function parsePrefix(array $query, string $name):string {
+ return is_string($query["prefix"] ?? null)
+ ? $query["prefix"]
+ : $name . self::DEFAULT_PREFIX_SEPARATOR;
+ }
+
+ /**
+ * @param array $parts
+ */
+ private function parseDatabase(array $parts):int {
+ return isset($parts["path"])
+ ? (int)trim($parts["path"], "/")
+ : 0;
+ }
+
+ private function getKey(string $sessionId):string {
+ return $this->prefix . $sessionId;
+ }
+
+ protected function createClient():Redis {
+ if(!class_exists(Redis::class)) {
+ throw new RuntimeException(
+ "The phpredis extension is required to use GT\\Session\\RedisHandler."
+ );
+ }
+
+ return new Redis();
+ }
+
+ private function requireClient():Redis {
+ if(is_null($this->client)) {
+ throw new RuntimeException("RedisHandler::open() must be called before use.");
+ }
+
+ return $this->client;
+ }
+
+ private function reconnect():void {
+ if(is_null($this->config)) {
+ throw new RuntimeException("RedisHandler::open() must be called before reconnect.");
+ }
+
+ $this->close();
+ $this->connect($this->config);
+ }
+
+ /**
+ * @template T
+ * @param callable():T $callback
+ * @return T
+ */
+ private function retryOnce(callable $callback):mixed {
+ try {
+ return $callback();
+ }
+ catch(Throwable) {
+ $this->reconnect();
+ return $callback();
+ }
+ }
+}
diff --git a/src/Session.php b/src/Session.php
index 5a47b47..eab4aa7 100644
--- a/src/Session.php
+++ b/src/Session.php
@@ -1,53 +1,64 @@
*/
+ protected array $config;
+ /** @param iterable $config */
public function __construct(
SessionHandlerInterface $sessionHandler,
iterable $config = [],
- string $id = null
+ ?string $id = null,
) {
$this->sessionHandler = $sessionHandler;
+ if(!is_array($config)) {
+ $config = iterator_to_array($config);
+ }
+ /** @var array $config */
+ $this->config = $config;
+
if(is_null($id)) {
$id = $this->getId();
}
$this->id = $id;
- $sessionPath = $this->getAbsolutePath(
+ $sessionPath = $this->normaliseSavePath(
$config["save_path"] ?? self::DEFAULT_SESSION_PATH
);
$sessionName = $config["name"] ?? self::DEFAULT_SESSION_NAME;
- session_start([
- "save_path" => $sessionPath,
- "name" => $sessionName,
- "cookie_lifetime" => $config["cookie_lifetime"] ?? self::DEFAULT_SESSION_LIFETIME,
- "cookie_path" => $config["cookie_path"] ?? self::DEFAULT_COOKIE_PATH,
- "cookie_domain" => $config["cookie_domain"] ?? self::DEFAULT_SESSION_DOMAIN,
- "cookie_secure" => $config["cookie_secure"] ?? self::DEFAULT_SESSION_SECURE,
- "cookie_httponly" => $config["cookie_httponly"] ?? self::DEFAULT_SESSION_HTTPONLY,
- ]);
+ $this->attemptStart($sessionPath, $sessionName, $config);
$this->sessionHandler->open($sessionPath, $sessionName);
- $this->store = $this->readSessionData() ?: null;
+ $this->store = $this->readSessionData();
if(is_null($this->store)) {
$this->store = new SessionStore(__NAMESPACE__, $this);
}
@@ -57,7 +68,7 @@ public function kill():void {
$this->sessionHandler->destroy($this->getId());
$params = session_get_cookie_params();
setcookie(
- session_name(),
+ session_name() ?: "",
"",
-1,
$params["path"],
@@ -70,18 +81,18 @@ public function kill():void {
public function getStore(
string $namespace,
bool $createIfNotExists = false
- ):?SessionStore {
+ ):?SessionStoreInterface {
return $this->store->getStore(
$namespace,
$createIfNotExists
);
}
- public function get(string $key) {
+ public function get(string $key):mixed {
return $this->store->get($key);
}
- public function set(string $key, $value):void {
+ public function set(string $key, mixed $value):void {
$this->store->set($key, $value);
}
@@ -99,10 +110,14 @@ public function getId():string {
session_id($this->createNewId());
}
- return session_id();
+ return session_id() ?: "";
}
- protected function getAbsolutePath(string $path):string {
+ protected function normaliseSavePath(string $path):string {
+ if($this->isDsn($path)) {
+ return $path;
+ }
+
$path = str_replace(
["/", "\\"],
DIRECTORY_SEPARATOR,
@@ -119,18 +134,132 @@ protected function getAbsolutePath(string $path):string {
return $path;
}
+ protected function isDsn(string $path):bool {
+ return (bool)preg_match('/^[a-z][a-z0-9+.-]*:\/\//i', $path);
+ }
+
+ /** @SuppressWarnings("PHPMD.Superglobals") */
protected function createNewId():string {
- return session_create_id();
+ if(($this->config["use_trans_sid"] ?? null)
+ && !$this->config["use_cookies"]) {
+ return $_GET[$this->config["name"]] ?? session_create_id();
+ }
+ return session_create_id() ?: "";
}
- protected function readSessionData() {
- return unserialize($this->sessionHandler->read($this->id));
+ /** @SuppressWarnings("PHPMD.EmptyCatchBlock") */
+ protected function readSessionData():?SessionStore {
+ try {
+ $data = $this->sessionHandler->read($this->id) ?: "";
+ $store = unserialize($data);
+ if ($store instanceof SessionStore) {
+ return $store;
+ }
+ }
+ // PHPCS:ignore
+ catch (Throwable) {}
+
+ return null;
}
- public function write() {
- $this->sessionHandler->write(
+
+ public function write():bool {
+ return $this->sessionHandler->write(
$this->id,
serialize($this->store)
);
}
-}
\ No newline at end of file
+
+ /**
+ * @param string $sessionPath
+ * @param string $sessionName
+ * @param array $config
+ * @SuppressWarnings("PHPMD.UnusedFormalParameter")
+ * @return void
+ */
+ // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
+ private function attemptStart(
+ string $sessionPath,
+ string $sessionName,
+ array $config,
+ ?string $unusedContext = null,
+ ):void {
+ $sessionOptions = $this->getSessionOptions(
+ $sessionPath,
+ $sessionName,
+ $config,
+ );
+ $this->tryStartSession($sessionOptions);
+ }
+
+ /**
+ * @param array $config
+ * @return array
+ */
+ private function getSessionOptions(
+ string $sessionPath,
+ string $sessionName,
+ array $config
+ ):array {
+ $defaultConfig = [
+ "use_only_cookies" => true,
+ "use_cookies" => true,
+ "use_trans_sid" => false,
+ "cookie_lifetime" => self::DEFAULT_SESSION_LIFETIME,
+ "cookie_path" => self::DEFAULT_COOKIE_PATH,
+ "cookie_domain" => self::DEFAULT_SESSION_DOMAIN,
+ "cookie_secure" => self::DEFAULT_SESSION_SECURE,
+ "cookie_httponly" => self::DEFAULT_SESSION_HTTPONLY,
+ "cookie_samesite" => self::DEFAULT_COOKIE_SAMESITE,
+ "use_strict_mode" => self::DEFAULT_STRICT_MODE,
+ ];
+
+ $config = array_merge($defaultConfig, $config);
+
+ return [
+ "save_path" => $sessionPath,
+ "name" => $sessionName,
+ "serialize_handler" => "php_serialize",
+ "use_only_cookies" => $config["use_only_cookies"],
+ "use_cookies" => $config["use_cookies"],
+ "use_trans_sid" => $config["use_trans_sid"] ?? false,
+ "cookie_lifetime" => $config["cookie_lifetime"],
+ "cookie_path" => $config["cookie_path"],
+ "cookie_domain" => $config["cookie_domain"],
+ "cookie_secure" => $config["cookie_secure"],
+ "cookie_httponly" => $config["cookie_httponly"],
+ "cookie_samesite" => $config["cookie_samesite"],
+ "use_strict_mode" => $config["use_strict_mode"],
+ ];
+ }
+
+ /**
+ * @param array $sessionOptions
+ * @SuppressWarnings("PHPMD.EmptyCatchBlock")
+ */
+ private function tryStartSession(array $sessionOptions):void {
+ $startAttempts = 0;
+ do {
+ $success = false;
+
+ try {
+ if(session_status() !== PHP_SESSION_ACTIVE) {
+ $success = session_start($sessionOptions);
+ }
+ }
+ // PHPCS:ignore
+ catch(Throwable) {}
+
+ if(!$success) {
+ if(session_status() === PHP_SESSION_ACTIVE) {
+ session_destroy();
+ }
+ if(session_id()) {
+ session_regenerate_id(true);
+ }
+ }
+ $startAttempts++;
+ }
+ while(!$success && $startAttempts <= 1);
+ }
+}
diff --git a/src/SessionArrayWrapper.php b/src/SessionArrayWrapper.php
new file mode 100644
index 0000000..ed2ab60
--- /dev/null
+++ b/src/SessionArrayWrapper.php
@@ -0,0 +1,32 @@
+ */
+ private array $sourceArray;
+
+ /** @param array &$sourceArray */
+ public function __construct(array &$sourceArray) {
+ $this->sourceArray = &$sourceArray;
+ }
+
+ public function get(string $key):mixed {
+ return $this->sourceArray[$key] ?? null;
+ }
+
+ public function set(string $key, mixed $value):void {
+ $this->sourceArray[$key] = $value;
+ }
+
+ public function contains(string $key):bool {
+ return isset($this->sourceArray[$key]);
+ }
+
+ public function remove(string $key):void {
+ if(!$this->contains($key)) {
+ return;
+ }
+
+ unset($this->sourceArray[$key]);
+ }
+}
diff --git a/src/SessionContainer.php b/src/SessionContainer.php
new file mode 100644
index 0000000..68d121c
--- /dev/null
+++ b/src/SessionContainer.php
@@ -0,0 +1,9 @@
+
+ * @SuppressWarnings("PHPMD.TooManyPublicMethods")
+ */
+class SessionStore extends ArrayIterator implements SessionStoreInterface {
+ use NullableTypeSafeGetter;
+
+ protected string $name;
+ protected Session $session;
+ /** @var array */
+ protected array $stores;
+ protected ?SessionStore $parentStore;
public function __construct(
string $name,
Session $session,
- self $parentStore = null
+ ?self $parentStore = null
) {
$this->name = $name;
$this->session = $session;
$this->parentStore = $parentStore;
$this->stores = [];
+ parent::__construct();
}
- public function setData(string $key, $value):void {
- $this->data[$key] = $value;
+ public function setData(string $key, mixed $value):void {
+ $this->offsetSet($key, $value);
}
- public function getData(string $key) {
- return $this->data[$key] ?? null;
+ public function getData(string $key):mixed {
+ if(!$this->offsetExists($key)) {
+ return null;
+ }
+
+ return $this->offsetGet($key);
}
public function containsData(string $key):bool {
- return isset($this->data[$key]);
+ return $this->offsetExists($key);
}
public function containsStore(string $key):bool {
@@ -41,7 +52,7 @@ public function containsStore(string $key):bool {
}
public function removeData(string $key):void {
- unset($this->data[$key]);
+ $this->offsetUnset($key);
}
public function removeStore(string $key):void {
@@ -68,16 +79,12 @@ public function getStore(
$namespaceParts = explode(".", $namespace);
$topLevelStoreName = array_shift($namespaceParts);
- /** @var SessionStore $store */
$store = $this->stores[$topLevelStoreName] ?? null;
if(is_null($store)) {
if($createIfNotExists) {
- $store = $this->createStore($namespace);
- return $store;
- }
- else {
- return null;
+ return $this->createStore($namespace);
}
+ return null;
}
if(empty($namespaceParts)) {
@@ -85,7 +92,7 @@ public function getStore(
}
$namespace = implode(".", $namespaceParts);
- return $store->getStore($namespace);
+ return $store->getStore($namespace, $createIfNotExists);
}
public function setStore(
@@ -116,27 +123,13 @@ public function createStore(string $namespace):SessionStore {
return $this->getStore($namespace);
}
- public function get(string $key) {
- $store = $this;
- $lastDotPosition = strrpos($key, ".");
-
- if ($lastDotPosition !== false) {
- $namespace = $this->getNamespaceFromKey($key);
- $store = $this->getStore($namespace);
- }
-
- if (is_null($store)) {
- return null;
- }
-
- if ($lastDotPosition !== false) {
- $key = substr($key, $lastDotPosition + 1);
- }
-
- return $store->getData($key);
+ public function get(string $key):mixed {
+ $store = $this->getStoreFromKey($key);
+ $key = $this->normaliseKey($key);
+ return $store?->getData($key);
}
- public function set(string $key, $value):void {
+ public function set(string $key, mixed $value):void {
$store = $this;
$lastDotPosition = strrpos($key, ".");
@@ -158,6 +151,12 @@ public function set(string $key, $value):void {
}
public function contains(string $key):bool {
+ $store = $this->getStoreFromKey($key);
+ $key = $this->normaliseKey($key);
+ return $store?->containsData($key) ?? false;
+ }
+
+ private function getStoreFromKey(string $key):?SessionStore {
$store = $this;
$lastDotPosition = strrpos($key, ".");
@@ -167,19 +166,24 @@ public function contains(string $key):bool {
}
if (is_null($store)) {
- return false;
+ return null;
}
- if ($lastDotPosition !== false) {
+ return $store;
+ }
+
+ private function normaliseKey(string $key):string {
+ $lastDotPosition = strrpos($key, ".");
+ if($lastDotPosition !== false) {
$key = substr($key, $lastDotPosition + 1);
}
- return $store->containsData($key);
+ return $key;
}
- public function remove(string $key = null):void {
+ public function remove(?string $key = null):void {
if(is_null($key)) {
- foreach($this->stores as $i => $childStore) {
+ foreach(array_keys($this->stores) as $i) {
unset($this->stores[$i]);
}
@@ -190,16 +194,16 @@ public function remove(string $key = null):void {
$store = $this;
$lastDotPosition = strrpos($key, ".");
- if ($lastDotPosition !== false) {
+ if($lastDotPosition !== false) {
$namespace = $this->getNamespaceFromKey($key);
$store = $this->getStore($namespace);
}
- if (is_null($store)) {
+ if(is_null($store)) {
return;
}
- if ($lastDotPosition !== false) {
+ if($lastDotPosition !== false) {
$key = substr($key, $lastDotPosition + 1);
}
@@ -212,11 +216,11 @@ protected function getSession():Session {
}
protected function getNamespaceFromKey(string $key):?string {
- $lastDotPostition = strrpos($key, ".");
- if ($lastDotPostition === false) {
+ $lastDotPosition = strrpos($key, ".");
+ if ($lastDotPosition === false) {
return null;
}
- return substr($key, 0, $lastDotPostition);
+ return substr($key, 0, $lastDotPosition);
}
-}
\ No newline at end of file
+}
diff --git a/src/SessionStoreFactory.php b/src/SessionStoreFactory.php
index 10bdae1..2bf6d5b 100644
--- a/src/SessionStoreFactory.php
+++ b/src/SessionStoreFactory.php
@@ -1,8 +1,11 @@
expects(self::once())
+ ->method("get")
+ ->with("queue.test")
+ ->willReturn(null);
+ $sessionStore->expects(self::once())
+ ->method("set")
+ ->with(
+ self::equalTo("queue.test"),
+ self::isInstanceOf(SplQueue::class)
+ );
+
+ $sut = new Flash($sessionStore);
+ $sut->put("test", "Test message");
+ }
+
+ public function testConsume_none():void {
+ $queue = self::createMock(SplQueue::class);
+ $queue->expects(self::once())
+ ->method("dequeue")
+ ->willThrowException(new RuntimeException("Can't shift from an empty datastructure"));
+ $sessionStore = self::createMock(SessionStoreInterface::class);
+ $sessionStore->expects(self::once())
+ ->method("get")
+ ->with("queue.test")
+ ->willReturn($queue);
+ $sut = new Flash($sessionStore);
+ $flashMessage = $sut->consume("test");
+ self::assertNull($flashMessage);
+ }
+
+ public function testConsume():void {
+ $fm1 = new FlashMessage("test", "First");
+ $fm2 = new FlashMessage("test", "Second");
+
+ $queue = self::createMock(SplQueue::class);
+ $queue->expects(self::exactly(3))
+ ->method("dequeue")
+ ->willReturnOnConsecutiveCalls($fm1, $fm2);
+
+ $sessionStore = self::createMock(SessionStoreInterface::class);
+ $sessionStore->expects(self::exactly(3))
+ ->method("get")
+ ->with("queue.test")
+ ->willReturn($queue);
+ $sessionStore->expects(self::once())
+ ->method("remove")
+ ->with("queue.test");
+ $sut = new Flash($sessionStore);
+
+ $flashMessage = $sut->consume("test");
+ self::assertInstanceOf(FlashMessage::class, $flashMessage);
+ self::assertSame("First", $flashMessage->message);
+ $flashMessage = $sut->consume("test");
+ self::assertInstanceOf(FlashMessage::class, $flashMessage);
+ self::assertSame("Second", $flashMessage->message);
+ $flashMessage = $sut->consume("test");
+ self::assertNull($flashMessage);
+ }
+}
diff --git a/test/unit/Helper/DataProvider/ConfigProvider.php b/test/phpunit/Helper/DataProvider/ConfigProvider.php
similarity index 78%
rename from test/unit/Helper/DataProvider/ConfigProvider.php
rename to test/phpunit/Helper/DataProvider/ConfigProvider.php
index 541d7c1..1f6d440 100644
--- a/test/unit/Helper/DataProvider/ConfigProvider.php
+++ b/test/phpunit/Helper/DataProvider/ConfigProvider.php
@@ -1,5 +1,7 @@
client;
+ }
+ };
+
+ $sut->open(
+ "redis://default:secret@example.internal:25061/2?prefix=prod:session:&ttl=1800&timeout=1.5&read_timeout=2.5&persistent=1&persistent_id=pool-a",
+ "GT",
+ );
+
+ self::assertSame("example.internal", $client->connectParameters["host"]);
+ self::assertSame(25061, $client->connectParameters["port"]);
+ self::assertSame(1.5, $client->connectParameters["timeout"]);
+ self::assertSame(2.5, $client->connectParameters["readTimeout"]);
+ self::assertSame("pool-a", $client->connectParameters["persistentId"]);
+ self::assertSame([["default", "secret"]], $client->authCalls);
+ self::assertSame([2], $client->selectCalls);
+
+ $sut->write("abc123", "payload");
+ self::assertSame("payload", $sut->read("abc123"));
+ self::assertSame(
+ [
+ "key" => "prod:session:abc123",
+ "ttl" => 1800,
+ "value" => "payload",
+ ],
+ $client->setExCalls[0],
+ );
+ }
+
+ public function testOpenParsesTlsDsn():void {
+ $client = new TestRedisClient();
+ $sut = new class($client) extends RedisHandler {
+ public function __construct(private readonly TestRedisClient $client) {}
+
+ protected function createClient():Redis {
+ /** @phpstan-ignore-next-line */
+ return $this->client;
+ }
+ };
+
+ $sut->open(
+ "rediss://:secret@example.internal?verify_peer=0&verify_peer_name=0",
+ "GT",
+ );
+ $sut->write("abc123", "payload");
+
+ self::assertSame("tls://example.internal", $client->connectParameters["host"]);
+ self::assertSame(
+ [
+ "stream" => [
+ "verify_peer" => false,
+ "verify_peer_name" => false,
+ ],
+ ],
+ $client->connectParameters["context"],
+ );
+ self::assertSame(["secret"], $client->authCalls);
+ self::assertSame("payload", $client->data["GT:abc123"]);
+ }
+
+ public function testDestroyAndClose():void {
+ $client = new TestRedisClient();
+ $sut = new class($client) extends RedisHandler {
+ public function __construct(private readonly TestRedisClient $client) {}
+
+ protected function createClient():Redis {
+ /** @phpstan-ignore-next-line */
+ return $this->client;
+ }
+ };
+ $sut->open("redis://cache.internal", "GT");
+ $sut->write("abc123", "payload");
+
+ self::assertTrue($sut->destroy("abc123"));
+ self::assertSame("", $sut->read("abc123"));
+ self::assertTrue($sut->close());
+ self::assertTrue($client->closed);
+ }
+
+ public function testEmptyNativePhpSessionWriteDoesNotOverwriteStoredSession():void {
+ $client = new TestRedisClient();
+ $sut = new class($client) extends RedisHandler {
+ public function __construct(private readonly TestRedisClient $client) {}
+
+ protected function createClient():Redis {
+ /** @phpstan-ignore-next-line */
+ return $this->client;
+ }
+ };
+ $sut->open("redis://cache.internal", "GT");
+ $sut->write("abc123", "stored-session");
+ $sut->write("abc123", "a:0:{}");
+
+ self::assertSame("stored-session", $sut->read("abc123"));
+ }
+
+ public function testCommandRetriesAfterDisconnectedClient():void {
+ $client = new TestRedisClient();
+ $sut = new class($client) extends RedisHandler {
+ public function __construct(private readonly TestRedisClient $client) {}
+
+ protected function createClient():Redis {
+ /** @phpstan-ignore-next-line */
+ return $this->client;
+ }
+ };
+ $sut->open("redis://cache.internal", "GT");
+ $client->failNextSetEx = true;
+
+ self::assertTrue($sut->write("abc123", "payload"));
+ self::assertSame("payload", $sut->read("abc123"));
+ self::assertSame(2, $client->connectCount);
+ }
+}
+
+class TestRedisClient extends Redis {
+ /** @var array */
+ public array $connectParameters = [];
+ /** @var array */
+ public array $setExCalls = [];
+ /** @var array */
+ public array $setCalls = [];
+ /** @var array */
+ public array $authCalls = [];
+ /** @var array */
+ public array $selectCalls = [];
+ /** @var array */
+ public array $data = [];
+ public int $deleted = 0;
+ public int $connectCount = 0;
+ public bool $failNextSetEx = false;
+ public bool $closed = false;
+
+ /**
+ * @param array{auth?:array{0:string|false|null,1?:string},stream?:array}|null $context
+ */
+ public function connect(
+ string $host,
+ int $port = 6379,
+ float $timeout = 0,
+ ?string $persistent_id = null,
+ int $retry_interval = 0,
+ float $read_timeout = 0,
+ ?array $context = null,
+ ):bool {
+ $this->connectCount++;
+ $this->connectParameters = [
+ "host" => $host,
+ "port" => $port,
+ "timeout" => $timeout,
+ "persistentId" => $persistent_id,
+ "retryInterval" => $retry_interval,
+ "readTimeout" => $read_timeout,
+ "context" => $context,
+ ];
+ return true;
+ }
+
+ /**
+ * @param array{string,string}|string $credentials
+ */
+ public function auth(mixed $credentials):Redis|bool {
+ $this->authCalls []= $credentials;
+ return true;
+ }
+
+ public function select(int $database):Redis|bool {
+ $this->selectCalls []= $database;
+ return true;
+ }
+
+ public function get(string $key):string|false {
+ return $this->data[$key] ?? false;
+ }
+
+ public function set(string $key, mixed $value, mixed $options = null):Redis|string|bool {
+ $this->setCalls []= $key;
+ $this->data[$key] = (string)$value;
+ return true;
+ }
+
+ public function setEx(string $key, int $ttl, mixed $value) {
+ if($this->failNextSetEx) {
+ $this->failNextSetEx = false;
+ throw new \RedisException("Redis server went away");
+ }
+
+ $this->setExCalls []= [
+ "key" => $key,
+ "ttl" => $ttl,
+ "value" => (string)$value,
+ ];
+ $this->data[$key] = (string)$value;
+ return true;
+ }
+
+ public function del(array|string $key, string ...$otherKeys):Redis|int|false {
+ if(is_array($key)) {
+ $key = reset($key);
+ }
+
+ unset($this->data[$key]);
+ return ++$this->deleted;
+ }
+
+ public function close():bool {
+ $this->closed = true;
+ return true;
+ }
+}
diff --git a/test/phpunit/SessionArrayWrapperTest.php b/test/phpunit/SessionArrayWrapperTest.php
new file mode 100644
index 0000000..5ca7b31
--- /dev/null
+++ b/test/phpunit/SessionArrayWrapperTest.php
@@ -0,0 +1,50 @@
+contains($key));
+ $sut->set($key, "test-value");
+ self::assertTrue($sut->contains($key));
+ }
+
+ public function testSet() {
+ $sessionArray = [];
+ $key = uniqid();
+ $value = uniqid();
+ $sut = new SessionArrayWrapper($sessionArray);
+ $sut->set($key, $value);
+ self::assertEquals($value, $sessionArray[$key]);
+ }
+
+ public function testGet() {
+ $sessionArray = [];
+ $key = uniqid();
+ $value = uniqid();
+ $sut = new SessionArrayWrapper($sessionArray);
+ self::assertNull($sut->get($key));
+ self::assertArrayNotHasKey($key, $sessionArray);
+ $sut->set($key, $value);
+ self::assertEquals($value, $sut->get($key));
+ self::assertEquals($value, $sessionArray[$key]);
+ }
+
+ public function testRemove() {
+ $key = uniqid();
+ $value = uniqid();
+ $sessionArray = [
+ $key => $value,
+ ];
+ $sut = new SessionArrayWrapper($sessionArray);
+ self::assertTrue($sut->contains($key));
+ $sut->remove($key);
+ self::assertFalse($sut->contains($key));
+ self::assertArrayNotHasKey($key, $sessionArray);
+ }
+}
\ No newline at end of file
diff --git a/test/phpunit/SessionStoreTest.php b/test/phpunit/SessionStoreTest.php
new file mode 100644
index 0000000..334e873
--- /dev/null
+++ b/test/phpunit/SessionStoreTest.php
@@ -0,0 +1,182 @@
+createMock($className);
+ }
+
+ /** @dataProvider data_randomKeyValuePairs */
+ public static function testGetSetDotNotation(array $keyValuePairs, Handler $handler):void {
+ $session = new Session($handler);
+
+ $sessionNamespace = "gt.test.session";
+
+ foreach($keyValuePairs as $key => $value) {
+ $fullKey = "$sessionNamespace.$key";
+ $session->set($fullKey, $value);
+ }
+
+ foreach($keyValuePairs as $key => $value) {
+ $fullKey = "$sessionNamespace.$key";
+ self::assertEquals($value, $session->get($fullKey));
+ }
+ }
+
+ public function testRemoveSelf():void {
+ /** @var MockObject|SessionHandler $handler */
+ $handler = $this->getMockBuilder(Handler::class)
+ ->getMock();
+ $session = new Session($handler);
+
+ $leafStore = $session->getStore(
+ "gt.test.session.trunk.leaf",
+ true
+ );
+ $trunkStore = $session->getStore(
+ "gt.test.session.trunk"
+ );
+
+ $trunkStore->remove();
+
+ self::assertNull($session->getStore("gt.test.session.trunk"));
+ self::assertNull($session->getStore("gt.test.session.trunk.leaf"));
+ self::assertInstanceOf(
+ SessionStore::class,
+ $session->getStore("gt.test.session")
+ );
+ }
+
+ public function testGetCreatesNonExistantStore() {
+ /** @var MockObject|SessionHandler $handler */
+ $handler = $this->getMockBuilder(Handler::class)
+ ->getMock();
+ $session = new Session($handler);
+
+ $trunkStore = $session->getStore(
+ "gt.test.session",
+ true
+ );
+ $leafStore = $session->getStore(
+ "gt.test.session.leaf",
+ true
+ );
+
+ self::assertNotNull($leafStore);
+ }
+
+ public function testGetString():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $numericValue = rand(1000, 9999);
+ $sut->set("test.value", $numericValue);
+
+ self::assertSame((string)$numericValue, $sut->getString("test.value"));
+ }
+
+ public function testGetInt():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $numericStringValue = (string)rand(1000, 9999);
+ $sut->set("test.value", $numericStringValue);
+
+ self::assertSame((int)$numericStringValue, $sut->getInt("test.value"));
+ }
+
+ public function testGetFloat():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $numericStringValue = (string)(rand(1000, 9999) - 0.105);
+ $sut->set("test.value", $numericStringValue);
+
+ self::assertSame((float)$numericStringValue, $sut->getFloat("test.value"));
+ }
+
+ public function testGetBool():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $numericValue = rand(0, 1);
+ $sut->set("test.value", $numericValue);
+
+ self::assertSame((bool)$numericValue, $sut->getBool("test.value"));
+ }
+
+ public function testGetDateTime():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $numericValue = time();
+ $sut->set("test.value", $numericValue);
+
+ $dateTime = new DateTime();
+ $dateTime->setTimestamp($numericValue);
+ self::assertEquals($dateTime, $sut->getDateTime("test.value"));
+ }
+
+ public function testCount():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $rawData = [
+ "one" => "first",
+ "two" => "second",
+ "three" => "third",
+ ];
+
+ foreach($rawData as $key => $value) {
+ $sut->set($key, $value);
+ }
+
+ self::assertCount(3, $sut);
+ }
+
+
+ public function testSessionStoreIsIterable():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+
+ $rawData = [
+ "key1" => "value1",
+ "key2" => "value2",
+ "key3" => "value3",
+ ];
+
+ foreach($rawData as $key => $value) {
+ $sut->set($key, $value);
+ }
+
+ foreach($sut as $key => $value) {
+ self::assertArrayHasKey($key, $rawData);
+ self::assertSame($rawData[$key], $value);
+ }
+ }
+
+ public function testSessionStoreImplementsInterface():void {
+ $session = $this->createMock(Session::class);
+ $sut = new SessionStore("test", $session);
+ self::assertInstanceOf(SessionStoreInterface::class, $sut);
+ }
+}
diff --git a/test/unit/SessionTest.php b/test/phpunit/SessionTest.php
similarity index 50%
rename from test/unit/SessionTest.php
rename to test/phpunit/SessionTest.php
index 1d4fc1d..bb4ec01 100644
--- a/test/unit/SessionTest.php
+++ b/test/phpunit/SessionTest.php
@@ -1,12 +1,14 @@
getMockBuilder(Handler::class)
- ->getMock();
+ protected static function createStaticMock(string $className):MockObject {
+ $tc = new SessionStoreTest("");
+ return $tc->createMock($className);
+ }
+ public function testSessionStarts():void {
self::assertEmpty(FunctionMocker::$mockCalls["session_start"]);
- $session = new Session($handler);
+ $handler = self::createMock(Handler::class);
+ new Session($handler);
self::assertCount(
1,
FunctionMocker::$mockCalls["session_start"]
);
}
- /**
- * @dataProvider data_randomConfig
- */
- public function testSessionStartsWithConfig(array $config):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ public function testSessionStartPreservesDsnSavePath():void {
+ $handler = self::createMock(Handler::class);
+ $savePath = "valkey://cache.internal:6379/0?ttl=1440";
+
+ new Session($handler, [
+ "save_path" => $savePath,
+ ]);
- $session = new Session($handler ,$config);
+ $sessionStartParameter = FunctionMocker::$mockCalls["session_start"][0][0];
+ self::assertSame($savePath, $sessionStartParameter["save_path"]);
+ }
+
+ public function testWriteSessionDataCalled() {
+ $handler = self::createMock(Handler::class);
+ $handler->expects($this->exactly(2))
+ ->method("write");
+ $session = new Session($handler);
+
+ $session->set("test-key", "test-value");
+ $session->remove("test-key");
+ }
+
+ public function testGetString():void {
+ $handler = self::createMock(Handler::class);
+ $sut = new Session($handler);
+
+ $numericValue = rand(1000, 9999);
+ $sut->set("test.value", $numericValue);
+
+ self::assertSame((string)$numericValue, $sut->getString("test.value"));
+ }
+
+ public function testGetInt():void {
+ $handler = self::createMock(Handler::class);
+ $sut = new Session($handler);
+
+ $numericStringValue = (string)rand(1000, 9999);
+ $sut->set("test.value", $numericStringValue);
+
+ self::assertSame((int)$numericStringValue, $sut->getInt("test.value"));
+ }
+
+ public function testGetFloat():void {
+ $handler = self::createMock(Handler::class);
+ $sut = new Session($handler);
+
+ $numericStringValue = (string)(rand(1000, 9999) - 0.105);
+ $sut->set("test.value", $numericStringValue);
+
+ self::assertSame((float)$numericStringValue, $sut->getFloat("test.value"));
+ }
+
+ public function testGetBool():void {
+ $handler = self::createMock(Handler::class);
+ $sut = new Session($handler);
+
+ $numericValue = rand(0, 1);
+ $sut->set("test.value", $numericValue);
+
+ self::assertSame((bool)$numericValue, $sut->getBool("test.value"));
+ }
+
+ public function testGetDateTime():void {
+ $handler = self::createMock(Handler::class);
+ $sut = new Session($handler);
+
+ $numericValue = time();
+ $sut->set("test.value", $numericValue);
+
+ $dateTime = new DateTime();
+ $dateTime->setTimestamp($numericValue);
+ self::assertEquals($dateTime, $sut->getDateTime("test.value"));
+ }
+
+ /** @dataProvider data_randomConfig */
+ private static function testSessionStartsWithConfig(array $config, Handler $handler):void {
+ new Session($handler, $config);
$sessionStartParameter = FunctionMocker::$mockCalls["session_start"][0][0];
foreach($config as $key => $value) {
@@ -49,33 +125,21 @@ public function testSessionStartsWithConfig(array $config):void {
}
}
- public function testWriteSessionDataCalled() {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
- $handler->expects($this->exactly(2))
- ->method("write");
- $session = new Session($handler);
-
- $session->set("test-key", "test-value");
- $session->remove("test-key");
+ /** @dataProvider data_randomConfig */
+ private static function testSessionStartDestroysFailedSession(array $config, Handler $handler):void {
+ FunctionMocker::$callState["session_start__fail"] = true;
+ new Session($handler, $config);
+ self::assertCount(1, FunctionMocker::$mockCalls["session_destroy"]);
}
- /**
- * @dataProvider data_randomString
- */
- public function testGetReturnsNull(string $randomString):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomString */
+ private static function testGetReturnsNull(string $randomString, Handler $handler):void {
$session = new Session($handler);
self::assertNull($session->get($randomString));
}
- /**
- * @@dataProvider data_randomKeyValuePairs
- */
- public function testSetGet(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testSetGet(array $keyValuePairs, Handler $handler):void {
$session = new Session($handler);
foreach($keyValuePairs as $key => $value) {
@@ -87,12 +151,8 @@ public function testSetGet(array $keyValuePairs):void {
}
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testSetGetNamespaced(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testSetGetNamespaced(array $keyValuePairs, Handler $handler):void {
$session = new Session($handler);
foreach($keyValuePairs as $key => $value) {
@@ -114,43 +174,35 @@ public function testSetGetNamespaced(array $keyValuePairs):void {
}
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testSetGetNamespacedSameParentNamespace(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
- $session = new Session($handler);
-
- $parentNamespace = implode(".", [
- uniqid("namespace1-"),
- uniqid("namespace2-"),
- ]);
-
- foreach($keyValuePairs as $key => $value) {
- $newKey = implode(".", [
- $parentNamespace,
- $key,
- ]);
- $keyValuePairs[$newKey] = $value;
- unset($keyValuePairs[$key]);
- }
-
- foreach($keyValuePairs as $key => $value) {
- $session->set($key, $value);
- }
-
- foreach($keyValuePairs as $key => $value) {
- self::assertEquals($value, $session->get($key));
- }
- }
-
- /**
- * @@dataProvider data_randomKeyValuePairs
- */
- public function testSetGetNotExistsOtherKey(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testSetGetNamespacedSameParentNamespace(array $keyValuePairs, Handler $handler):void {
+ $session = new Session($handler);
+
+ $parentNamespace = implode(".", [
+ uniqid("namespace1-"),
+ uniqid("namespace2-"),
+ ]);
+
+ foreach($keyValuePairs as $key => $value) {
+ $newKey = implode(".", [
+ $parentNamespace,
+ $key,
+ ]);
+ $keyValuePairs[$newKey] = $value;
+ unset($keyValuePairs[$key]);
+ }
+
+ foreach($keyValuePairs as $key => $value) {
+ $session->set($key, $value);
+ }
+
+ foreach($keyValuePairs as $key => $value) {
+ self::assertEquals($value, $session->get($key));
+ }
+ }
+
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testSetGetNotExistsOtherKey(array $keyValuePairs, Handler $handler):void {
$session = new Session($handler);
foreach($keyValuePairs as $key => $value) {
@@ -175,12 +227,8 @@ public function testSetGetNotExistsOtherKey(array $keyValuePairs):void {
}
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testContains(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testContains(array $keyValuePairs, Handler $handler):void {
$session = new Session($handler);
foreach($keyValuePairs as $key => $value) {
@@ -192,12 +240,8 @@ public function testContains(array $keyValuePairs):void {
}
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testNotContains(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testNotContains(array $keyValuePairs, Handler $handler):void {
$session = new Session($handler);
foreach($keyValuePairs as $key => $value) {
@@ -209,19 +253,15 @@ public function testNotContains(array $keyValuePairs):void {
}
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testRemove(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testRemove(array $keyValuePairs, Handler $handler):void {
$session = new Session($handler);
foreach($keyValuePairs as $key => $value) {
$session->set($key, $value);
}
- uasort($keyValuePairs, function () {
+ uasort($keyValuePairs, function() {
return rand(-1, 1);
});
@@ -232,55 +272,47 @@ public function testRemove(array $keyValuePairs):void {
}
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testNamespaceKeyIsRemovedFromSession(array $keyValuePairs):void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
- $session = new Session($handler);
-
- $parentNamespace = implode(".", [
- uniqid("namespace1-"),
- uniqid("namespace2-"),
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testNamespaceKeyIsRemovedFromSession(array $keyValuePairs, Handler $handler):void {
+ $session = new Session($handler);
+
+ $parentNamespace = implode(".", [
+ uniqid("namespace1-"),
+ uniqid("namespace2-"),
]);
- foreach($keyValuePairs as $key => $value) {
- $fullKey = implode(".", [
- $parentNamespace,
+ foreach($keyValuePairs as $key => $value) {
+ $fullKey = implode(".", [
+ $parentNamespace,
$key,
]);
- $session->set($fullKey, $value);
+ $session->set($fullKey, $value);
}
$keyToRemove = array_rand($keyValuePairs);
- $fullKeyToRemove = implode(".", [
- $parentNamespace,
+ $fullKeyToRemove = implode(".", [
+ $parentNamespace,
$keyToRemove,
]);
- $store = $session->getStore($parentNamespace);
- $store->remove($keyToRemove);
- unset($keyValuePairs[$keyToRemove]);
+ $store = $session->getStore($parentNamespace);
+ $store->remove($keyToRemove);
+ unset($keyValuePairs[$keyToRemove]);
- foreach($keyValuePairs as $key => $value) {
- $fullKey = implode(".", [
- $parentNamespace,
+ foreach($keyValuePairs as $key => $value) {
+ $fullKey = implode(".", [
+ $parentNamespace,
$key,
]);
- self::assertTrue($session->contains($fullKey));
+ self::assertTrue($session->contains($fullKey));
}
self::assertFalse($session->contains($fullKeyToRemove));
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testNamespaceKeyIsRemovedFromStore(array $keyValuePairs): void {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testNamespaceKeyIsRemovedFromStore(array $keyValuePairs, Handler $handler): void {
$session = new Session($handler);
$parentNamespace = implode(".", [
@@ -309,12 +341,8 @@ public function testNamespaceKeyIsRemovedFromStore(array $keyValuePairs): void {
self::assertFalse($store->contains($keyToRemove));
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testRemoveNamespace(array $keyValuePairs) {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testRemoveNamespace(array $keyValuePairs, Handler $handler) {
$session = new Session($handler);
$namespace1 = uniqid("namespace1-");
@@ -351,12 +379,8 @@ public function testRemoveNamespace(array $keyValuePairs) {
self::assertFalse($session->contains($parentNamespace));
}
- /**
- * @dataProvider data_randomKeyValuePairs
- */
- public function testRemoveSiblingNamespace(array $keyValuePairs) {
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
+ /** @dataProvider data_randomKeyValuePairs */
+ private static function testRemoveSiblingNamespace(array $keyValuePairs, Handler $handler) {
$session = new Session($handler);
$namespace0 = uniqid("namespace0-");
@@ -435,4 +459,4 @@ public function testRemoveSiblingNamespace(array $keyValuePairs) {
);
}
}
-}
\ No newline at end of file
+}
diff --git a/test/unit/Helper/FunctionOverride/session_id.php b/test/unit/Helper/FunctionOverride/session_id.php
deleted file mode 100644
index a2c22a9..0000000
--- a/test/unit/Helper/FunctionOverride/session_id.php
+++ /dev/null
@@ -1,6 +0,0 @@
-getMockBuilder(Handler::class)
- ->getMock();
- $session = new Session($handler);
-
- $sessionNamespace = "gt.test.session";
-
- foreach($keyValuePairs as $key => $value) {
- $fullKey = "$sessionNamespace.$key";
- $session->set($fullKey, $value);
- }
-
- foreach($keyValuePairs as $key => $value) {
- $fullKey = "$sessionNamespace.$key";
- self::assertEquals($value, $session->get($fullKey));
- }
- }
-
- public function testRemoveSelf():void {
- /** @var MockObject|SessionHandler $handler */
- $handler = $this->getMockBuilder(Handler::class)
- ->getMock();
- $session = new Session($handler);
-
- $leafStore = $session->getStore(
- "gt.test.session.trunk.leaf",
- true
- );
- $trunkStore = $session->getStore(
- "gt.test.session.trunk"
- );
-
- $trunkStore->remove();
-
- self::assertNull($session->getStore("gt.test.session.trunk"));
- self::assertNull($session->getStore("gt.test.session.trunk.leaf"));
- self::assertInstanceOf(
- SessionStore::class,
- $session->getStore("gt.test.session")
- );
- }
-}
\ No newline at end of file
diff --git a/test/unit/phpunit.xml b/test/unit/phpunit.xml
deleted file mode 100644
index bb2e951..0000000
--- a/test/unit/phpunit.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- .
-
-
-
-
-
- ../../src
-
-
-
\ No newline at end of file