diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..e8b80f1 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,31 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "bash -c 'input=$(cat); fp=$(echo \"$input\" | jq -r \".tool_input.file_path\"); if [[ \"$fp\" == *composer.lock ]] || [[ \"$fp\" == vendor/* ]] || [[ \"$fp\" == */vendor/* ]]; then echo \"{\\\"decision\\\":\\\"deny\\\",\\\"reason\\\":\\\"Do not edit $fp directly\\\"}\" >&2; exit 2; fi'" + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "bash -c 'input=$(cat); fp=$(echo \"$input\" | jq -r \".tool_input.file_path\"); if [[ \"$fp\" == *.php ]]; then cd \"$CLAUDE_PROJECT_DIR\" && php vendor/bin/phpcbf --standard=PSR12 \"$fp\" 2>/dev/null; fi; true'" + }, + { + "type": "command", + "command": "bash -c 'input=$(cat); fp=$(echo \"$input\" | jq -r \".tool_input.file_path\"); if [[ \"$fp\" == *.php ]]; then cd \"$CLAUDE_PROJECT_DIR\" && composer phpstan 2>&1 | tail -5; fi; true'", + "timeout": 30 + } + ] + } + ] + } +} diff --git a/.claude/skills/check-quality/SKILL.md b/.claude/skills/check-quality/SKILL.md new file mode 100644 index 0000000..4fa1b9d --- /dev/null +++ b/.claude/skills/check-quality/SKILL.md @@ -0,0 +1,13 @@ +--- +name: check-quality +description: Run lint, phpstan, and tests in sequence, fix any issues found +disable-model-invocation: true +--- + +Run the full quality check pipeline: +1. `composer lint` — fix any PSR-12 violations with `composer lint-fix` +2. `composer phpstan` — fix any static analysis issues +3. `composer test` — fix any failing tests + +After each step, if issues are found, fix them before proceeding to the next step. +Do not commit. Report results when done. diff --git a/.claude/skills/gen-test/SKILL.md b/.claude/skills/gen-test/SKILL.md new file mode 100644 index 0000000..8724eba --- /dev/null +++ b/.claude/skills/gen-test/SKILL.md @@ -0,0 +1,16 @@ +--- +name: gen-test +description: Generate a Pest test for a PHP class following project conventions +disable-model-invocation: true +--- + +Generate a Pest test file for the specified class. + +Rules: +- Place tests in `tests/Unit/` mirroring the src/ structure +- Use Pest syntax (test(), expect(), describe()) +- For DTOs: test construction with valid data, verify all readonly properties +- For traits: test each method the trait provides +- For clients: mock Guzzle responses, test Valinor hydration +- Follow existing test patterns in tests/Unit/ +- Read existing tests first to match style diff --git a/.claude/skills/new-dto/SKILL.md b/.claude/skills/new-dto/SKILL.md new file mode 100644 index 0000000..3e4e1ae --- /dev/null +++ b/.claude/skills/new-dto/SKILL.md @@ -0,0 +1,15 @@ +--- +name: new-dto +description: Create a new final readonly DTO class with Valinor-compatible constructor +disable-model-invocation: true +--- + +Create a new DTO class following project conventions: +- `final readonly class` with constructor promotion +- Place in `src/v1/Dto/` or `src/v3/Dto/` based on API version +- All properties as constructor-promoted readonly parameters +- Use appropriate PHP types (string, int, ?string for nullable) +- Apply relevant traits (HasSource, HasLanguage, etc.) if applicable +- Namespace: `Ivuorinen\BusinessDataFetcher\{v1|v3}\Dto` +- Generate a corresponding Pest test in tests/Unit/ +- Read existing DTOs first to match style diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 0000000..5a2d3ba --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,28 @@ +--- +- name: bug + color: d73a4a + description: Something isn't working + +- name: enhancement + color: a2eeef + description: New feature or request + +- name: documentation + color: 0075ca + description: Improvements or additions to documentation + +- name: dependencies + color: 0366d6 + description: Pull requests that update a dependency file + +- name: breaking-change + color: e11d48 + description: Breaking change to public API + +- name: maintenance + color: fbca04 + description: Code maintenance and refactoring + +- name: ci + color: 7057ff + description: Continuous integration and tooling diff --git a/.github/renovate.json b/.github/renovate.json index 5b9cda3..d1ad7f8 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,4 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["github>ivuorinen/.github:renovate-config"] + "extends": ["github>ivuorinen/renovate-config"] } diff --git a/.github/workflows/composer.yml b/.github/workflows/composer.yml index 33c30a8..f0482da 100644 --- a/.github/workflows/composer.yml +++ b/.github/workflows/composer.yml @@ -18,33 +18,36 @@ jobs: strategy: matrix: - php-versions: ['8.2', '8.3'] + php-versions: ['8.2', '8.3', '8.4'] steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2 - with: - php-version: ${{ matrix.php-versions }} + - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + with: + php-version: ${{ matrix.php-versions }} - - name: Validate composer.json and composer.lock - run: composer validate --strict + - name: Validate composer.json and composer.lock + run: composer validate --strict - - name: Cache Composer packages - id: composer-cache - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5 - with: - path: vendor - key: ${{ runner.os }}-php-${{ matrix.php-versions }}-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php-${{ matrix.php-versions }}- - ${{ runner.os }}-php- + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + with: + path: ~/.composer/cache + key: ${{ runner.os }}-composer-${{ matrix.php-versions }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer-${{ matrix.php-versions }}- + ${{ runner.os }}-composer- - - name: Install dependencies - run: composer install --prefer-dist --no-progress + - name: Install dependencies + run: composer install --prefer-dist --no-progress - # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" - # Docs: https://getcomposer.org/doc/articles/scripts.md + - name: Run linting + run: composer lint - # - name: Run test suite - # run: composer run-script test + - name: Run static analysis + run: composer phpstan + + - name: Run test suite + run: composer test diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index 36b989c..7220ab5 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -2,12 +2,19 @@ name: PR Lint on: - push: - branches-ignore: [master, main] - # Remove the line above to run when pushing to master pull_request: branches: [master, main] jobs: - SuperLinter: - uses: ivuorinen/.github/.github/workflows/pr-lint.yml@main + lint: + permissions: + contents: read + issues: write + pull-requests: write + statuses: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: ivuorinen/actions/pr-lint@d1af04260d903f572ee953cc790ff7c1410709a6 # v2026.03.05 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 3b3945d..520770e 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -1,10 +1,18 @@ --- -name: Release Drafter +name: Release Monthly # yamllint disable-line rule:truthy on: workflow_call: + workflow_dispatch: + +permissions: + contents: write jobs: - Draft: - uses: ivuorinen/.github/.github/workflows/sync-labels.yml@main + release: + runs-on: ubuntu-latest + steps: + - uses: ivuorinen/actions/release-monthly@d1af04260d903f572ee953cc790ff7c1410709a6 # v2026.03.05 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 2055b92..7057920 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -8,12 +8,15 @@ on: workflow_call: workflow_dispatch: +permissions: + contents: read + issues: write + pull-requests: write + jobs: stale: runs-on: ubuntu-latest - permissions: - contents: write # only for delete-branch option - issues: write - pull-requests: write steps: - - uses: ivuorinen/actions/stale@main + - uses: ivuorinen/actions/stale@d1af04260d903f572ee953cc790ff7c1410709a6 # v2026.03.05 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml index f8dbfba..507f870 100644 --- a/.github/workflows/sync-labels.yml +++ b/.github/workflows/sync-labels.yml @@ -18,4 +18,10 @@ permissions: jobs: SyncLabels: - uses: ivuorinen/.github/.github/workflows/sync-labels.yml@main + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: ivuorinen/actions/sync-labels@d1af04260d903f572ee953cc790ff7c1410709a6 # v2026.03.05 + with: + labels: .github/labels.yml + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index ca05913..35a752d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,90 +1,49 @@ -.php-cs-fixer.cache -.php-cs-fixer.php +# PHP / Composer composer.phar /vendor/ + +# PHP CS Fixer +.php-cs-fixer.cache +.php-cs-fixer.php + +# PHPUnit / Pest .phpunit.result.cache .phpunit.cache -/app/phpunit.xml /phpunit.xml + +# Build artifacts /build/ -logs + +# Logs *.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json -pids -*.pid -*.seed -*.pid.lock -lib-cov -coverage -*.lcov -.nyc_output -.grunt -bower_components -.lock-wscript -build/Release -node_modules/ -jspm_packages/ -web_modules/ -*.tsbuildinfo -.npm -.eslintcache -.stylelintcache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ -.node_repl_history -*.tgz -.yarn-integrity + +# Environment .env -.env.development.local -.env.test.local -.env.production.local -.env.local -.cache -.parcel-cache -.next -out -.nuxt -dist -.cache/ -.vuepress/dist -.temp -.docusaurus -.serverless/ -.fusebox/ -.dynamodb/ -.tern-port -.vscode-test -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* +.env*.local + +# OS / Editor +.DS_Store [._]*.s[a-v][a-z] -!*.svg # comment out if you don't need vector files +!*.svg [._]*.sw[a-p] [._]s[a-rt-v][a-z] [._]ss[a-gi-z] [._]sw[a-p] +*~ +[._]*.un~ + +# Vim Session.vim Sessionx.vim .netrwhist -*~ tags -[._]*.un~ + +# JetBrains (PHPStorm) .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf -.idea/**/aws.xml -.idea/**/contentModel.xml .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml @@ -92,44 +51,13 @@ tags .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml -.idea/**/gradle.xml .idea/**/libraries -cmake-build-*/ -.idea/**/mongoSettings.xml *.iws -out/ .idea_modules/ -atlassian-ide-plugin.xml .idea/replstate.xml .idea/sonarlint/ -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties .idea/httpRequests .idea/caches/build_file_checksums.ser -npm-debug.log -yarn-error.log -bootstrap/compiled.php -app/storage/ -public/storage -public/hot -public_html/storage -public_html/hot -storage/*.key -Homestead.yaml -Homestead.json -/.vagrant -/node_modules -/.pnp -.pnp.js -/coverage -/.next/ -/out/ -/build -.DS_Store -*.pem -.env*.local -.vercel -next-env.d.ts +# Claude Code +.claude/settings.local.json diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..cd07f00 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "MD013": false, + "MD041": false +} diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 0000000..9038976 --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1 @@ +docs.md diff --git a/.mega-linter.yml b/.mega-linter.yml new file mode 100644 index 0000000..41eea22 --- /dev/null +++ b/.mega-linter.yml @@ -0,0 +1,26 @@ +--- +APPLY_FIXES: all +PARALLEL: true +VALIDATE_ALL_CODEBASE: true +GITHUB_STATUS_REPORTER: true +SARIF_REPORTER: true +IGNORE_GENERATED_FILES: true +PRINT_ALPACA: false +SHOW_SKIPPED_LINTERS: false +SHOW_ELAPSED_TIME: false +FILEIO_REPORTER: false + +ENABLE_LINTERS: + - YAML_YAMLLINT + - MARKDOWN_MARKDOWNLINT + - PHP_PHPCS + +DISABLE_LINTERS: + - REPOSITORY_DEVSKIM + - JSON_PRETTIER + - YAML_PRETTIER + +PHP_PHPCS_CLI_LINT_MODE: project +PHP_PHPCS_ARGUMENTS: "--warning-severity=0" + +FILTER_REGEX_EXCLUDE: "(vendor/|node_modules/|\\.git/|\\.claude/|composer\\.lock|package-lock\\.json)" diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..0fb3c03 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,20 @@ +--- +extends: default + +rules: + comments: + require-starting-space: true + ignore-shebangs: true + min-spaces-from-content: 1 + line-length: + max: 120 + allow-non-breakable-words: true + allow-non-breakable-inline-mappings: false + truthy: + check-keys: false + brackets: + min-spaces-inside: 0 + max-spaces-inside: 1 + +ignore: | + vendor/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a458fe4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,40 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- v3 API client (`Ivuorinen\BusinessDataFetcher\v3\Client`) with support for: + - Company search (`searchCompanies()`) + - Code list descriptions (`getDescription()`) + - Postal code lookup (`getPostCodes()`) + - Full company ZIP download (`getAllCompanies()`) +- v3 DTOs based on the official OpenAPI schema +- Pest test suite with 57 tests covering traits, DTOs, and both API clients +- Shared HTTP infrastructure (`AbstractClient`, `HttpClientFactory`) +- PHP 8.4 added to CI matrix +- CI pipeline now runs linting, static analysis, and tests +- `phpunit.xml` configuration +- `.github/labels.yml` for label sync workflow + +### Changed + +- **BREAKING:** Replaced `spatie/data-transfer-object` with `cuyz/valinor` for DTO hydration +- **BREAKING:** All v1 DTOs are now `final readonly` classes with constructor promotion +- **BREAKING:** Removed `$sourceText` and `$authorityText` computed properties from traits; use `getSourceText()` and `getAuthorityString()` methods instead +- **BREAKING:** `BusinessDataFetcher` constructor now accepts an optional `?Client` parameter for testability +- Upgraded `squizlabs/php_codesniffer` from v3 to v4 +- **BREAKING:** `BusinessDataFetcher` now extends `AbstractClient` +- **BREAKING:** Traits are now method-only (no properties or constructors) +- **BREAKING:** Removed empty `HasVersion` trait (version is a regular constructor property) + +### Removed + +- `spatie/data-transfer-object` dependency +- `ivuorinen/markdowndocs` dependency (incompatible with Pest's symfony/console requirement) +- `composer docs` script (pending markdowndocs update) diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d67178e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,45 @@ +# CLAUDE.md + +## Project Overview + +PHP library for fetching Finnish business data from the PRH (Finnish Patent and Registration Office) open data API. Supports both v1 (BIS) and v3 (YTJ) APIs. + +## Commands + +```bash +composer lint # PSR-12 linting (phpcs v4) + Rector dry-run +composer lint-fix # Auto-fix PSR-12 violations (phpcbf) + Rector apply +composer rector # Run Rector standalone +composer phpstan # Static analysis (level 9) +composer test # Pest test suite +``` + +## Architecture + +- **v1 Entry point**: `src/BusinessDataFetcher.php` — extends `AbstractClient`, fetches from `/bis/v1` +- **v3 Entry point**: `src/v3/Client.php` — extends `AbstractClient`, fetches from `/opendata-ytj-api/v3` +- **Shared HTTP**: `src/Http/AbstractClient.php` — base class with Guzzle + Valinor mapper +- **v1 DTOs**: `src/v1/Dto/` — `final readonly` classes with Valinor-compatible constructors +- **v3 DTOs**: `src/v3/Dto/` — `final readonly` classes matching the v3 OpenAPI schema +- **Traits**: `src/v1/Traits/` — method-only helpers (`HasSource`, `HasLanguage`, `HasRegister`, `HasAuthority`, `HasChange`) +- **Exceptions**: `src/v1/Exceptions/`, `src/v3/Exceptions/` +- **Tests**: `tests/Unit/` — Pest tests for traits, DTOs, and both clients + +## Conventions + +- PHP 8.2+ +- PSR-12 coding standard (squizlabs/php_codesniffer v4) +- Rector (`rector.php`): `deadCode`, `codeQuality`, `typeDeclarations` sets — no `codingStyle` (phpcs handles that) +- PHPStan level 9 +- Valinor v1 for DTO hydration with `allowSuperfluousKeys()` +- All DTOs are `final readonly` with constructor promotion +- Traits are method-only (no properties) +- Namespace: `Ivuorinen\BusinessDataFetcher` + +## CI/CD + +- GitHub Actions workflows in `.github/workflows/` +- Reusable composite actions from `ivuorinen/actions` (not `ivuorinen/.github`) +- Renovate config: `.github/renovate.json` extends `github>ivuorinen/renovate-config` +- `pinact run -u -v --fix` — pin all action refs to commit SHAs after editing workflows +- PHP matrix: 8.2, 8.3, 8.4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4082e06 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# Contributing + +## Requirements + +- PHP 8.2+ +- Composer + +## Setup + +```bash +git clone https://github.com/ivuorinen/business-data-fetcher.git +cd business-data-fetcher +composer install +``` + +## Development Workflow + +### Running checks + +```bash +composer lint # PSR-12 linting +composer lint-fix # Auto-fix PSR-12 violations +composer phpstan # Static analysis (level 9) +composer test # Pest test suite +``` + +### Branch Strategy + +- `main` — stable release branch +- `feat/*` — feature branches +- `fix/*` — bugfix branches + +### Pull Request Process + +1. Create a feature or fix branch from `main` +2. Make your changes +3. Ensure all checks pass: `composer lint && composer phpstan && composer test` +4. Open a PR against `main` +5. PRs require passing CI before merge + +## Code Conventions + +- PSR-12 coding standard +- PHPStan level 9 strict analysis +- All DTOs are `final readonly` classes with constructor promotion +- Use Valinor for hydration (not manual array mapping) +- Write Pest tests for new functionality diff --git a/README.md b/README.md index b16824a..8de3fb4 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,112 @@ # Business Data Fetcher -This is an API client to Finnish Patent and Registration -Office's (PRH) Business Information System (BIS) v1. +[![PHP Composer](https://github.com/ivuorinen/business-data-fetcher/actions/workflows/composer.yml/badge.svg)](https://github.com/ivuorinen/business-data-fetcher/actions/workflows/composer.yml) -Use it to get company data from the Business Information System by Business ID. +PHP library for fetching Finnish business data from the PRH (Finnish Patent and Registration Office) open data API. + +Supports both **v1** (BIS) and **v3** (YTJ) APIs. ## Installation ```bash -composer install ivuorinen/business-data-fetcher +composer require ivuorinen/business-data-fetcher ``` -## Usage example +## Usage + +### v1 API (BIS) + +Fetch company details by Business ID: ```php -getBusinessInformation('1639413-9'); - print_r($results); -} catch (\GuzzleHttp\Exception\GuzzleException $e) { - var_dump($e); +$client = new BusinessDataFetcher(); +$results = $client->getBusinessInformation('1639413-9'); + +foreach ($results as $company) { + echo $company->name . "\n"; + echo $company->businessId . "\n"; + + foreach ($company->names as $name) { + echo $name->name . ' (' . $name->getLanguageString() . ")\n"; + } } ``` -## Data source +### v3 API (YTJ) -All models are transcribed from PRH Open Data portal. You can find the examples -and models descriptions, among other details and live API query tool following -this link: https://avoindata.prh.fi/ytj_en.html +Search companies with multiple filters: + +```php +use Ivuorinen\BusinessDataFetcher\v3\Client; + +$client = new Client(); + +// Search by name +$result = $client->searchCompanies(name: 'Example'); +echo "Found {$result->totalResults} companies\n"; + +foreach ($result->companies as $company) { + echo $company->businessId->value . ' - '; + echo $company->names[0]->name . "\n"; +} + +// Search by Business ID +$result = $client->searchCompanies(businessId: '1639413-9'); + +// Search with multiple filters +$result = $client->searchCompanies( + location: 'Helsinki', + companyForm: 'OY', + mainBusinessLine: '62010', +); + +// Get code list descriptions +$description = $client->getDescription('REK', 'en'); + +// Get postal codes +$postCodes = $client->getPostCodes('fi'); + +// Download all companies as ZIP +$stream = $client->getAllCompanies(); +file_put_contents('companies.zip', $stream->getContents()); +``` + +## v1 vs v3 API Comparison + +| Feature | v1 (BIS) | v3 (YTJ) | +| --------- | ---------- | ---------- | +| Base URL | `/bis/v1` | `/opendata-ytj-api/v3` | +| Lookup | By Business ID only | Search by name, location, form, etc. | +| Company form | String code | Structured with descriptions | +| Addresses | Flat structure | Nested with PostOffice objects | +| Code lists | N/A | `/description` endpoint | +| Postal codes | N/A | `/post_codes` endpoint | +| Bulk download | N/A | `/all_companies` ZIP | + +## Migration from v1 DTOs + +If upgrading from the Spatie DTO version: + +- DTOs are now `final readonly` classes (no `->toArray()`) +- `$sourceText` / `$authorityText` properties removed; use `getSourceText()` / `getAuthorityString()` methods +- `HasVersion` trait removed; `$version` is a regular constructor property +- `BusinessDataFetcher` constructor accepts an optional Guzzle `Client` for testing + +## Development + +```bash +composer lint # PSR-12 linting +composer lint-fix # Auto-fix violations +composer phpstan # Static analysis (level 9) +composer test # Pest test suite +``` + +## Data Source + +- v1: +- v3: ## Notice of Liability @@ -40,4 +116,3 @@ of this library are providing this without compensation and cannot be held respo ## License [MIT licensed](LICENSE.md) - diff --git a/captainhook.json b/captainhook.json new file mode 100644 index 0000000..2e890a5 --- /dev/null +++ b/captainhook.json @@ -0,0 +1,69 @@ +{ + "pre-commit": { + "enabled": true, + "actions": [ + { + "action": "\\CaptainHook\\App\\Hook\\Diff\\Action\\BlockSecrets", + "options": {}, + "conditions": [] + }, + { + "action": "composer lint-fix", + "options": {}, + "conditions": [] + }, + { + "action": "composer test", + "options": {}, + "conditions": [] + } + ] + }, + "commit-msg": { + "enabled": true, + "actions": [ + { + "action": "\\Ramsey\\CaptainHook\\ValidateConventionalCommit", + "options": {}, + "conditions": [] + } + ] + }, + "pre-push": { + "enabled": false, + "actions": [] + }, + "post-commit": { + "enabled": false, + "actions": [] + }, + "post-merge": { + "enabled": false, + "actions": [] + }, + "post-checkout": { + "enabled": false, + "actions": [] + }, + "post-rewrite": { + "enabled": false, + "actions": [] + }, + "post-change": { + "enabled": true, + "actions": [ + { + "action": "composer install", + "options": {}, + "conditions": [ + { + "exec": "CaptainHook.FileChanged.Any", + "args": [ + ["composer.json", "composer.lock"] + ] + } + ] + } + ] + } +} diff --git a/composer.json b/composer.json index 30aad10..7e359ac 100644 --- a/composer.json +++ b/composer.json @@ -5,23 +5,51 @@ "license": "MIT", "require": { "php": "^8.2", + "ext-json": "*", "guzzlehttp/guzzle": "^7.4", - "spatie/data-transfer-object": "^3.9" + "cuyz/valinor": "^1.0" }, "autoload": { "psr-4": { "Ivuorinen\\BusinessDataFetcher\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "Ivuorinen\\BusinessDataFetcher\\Tests\\": "tests/" + } + }, "require-dev": { "squizlabs/php_codesniffer": "^4.0", - "ivuorinen/markdowndocs": "^4.0", - "phpstan/phpstan": "^2.0" + "phpstan/phpstan": "^2.0", + "pestphp/pest": "^3.0", + "rector/rector": "^2.3", + "captainhook/captainhook": "^5.0", + "captainhook/hook-installer": "^1.0", + "ramsey/conventional-commits": "^1.7", + "captainhook/secrets": "^0.9.7", + "phpstan/extension-installer": "^1.0", + "jbelien/phpstan-sarif-formatter": "^1.0", + "bartlett/sarif-php-converters": "^1.0" }, "scripts": { - "docs": "php vendor/bin/phpdoc-md generate src > docs.md", - "lint": "php vendor/bin/phpcs --standard=PSR12 src", - "lint-fix": "php vendor/bin/phpcbf --standard=PSR12 src", - "phpstan": "php vendor/bin/phpstan analyse" + "lint": [ + "php vendor/bin/phpcs --standard=PSR12 src", + "php vendor/bin/rector --dry-run" + ], + "lint-fix": [ + "php vendor/bin/phpcbf --standard=PSR12 src", + "php vendor/bin/rector" + ], + "rector": "php vendor/bin/rector", + "phpstan": "php vendor/bin/phpstan analyse", + "test": "php vendor/bin/pest" + }, + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true, + "captainhook/hook-installer": true, + "phpstan/extension-installer": true + } } } diff --git a/composer.lock b/composer.lock index ae1e582..8a1b975 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,86 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "83075a3e4a40fbf6e58d914985fd4ed9", + "content-hash": "02814da9b1173972503f6c7cb41ab4c0", "packages": [ + { + "name": "cuyz/valinor", + "version": "1.17.0", + "source": { + "type": "git", + "url": "https://github.com/CuyZ/Valinor.git", + "reference": "9eb2802797e36f3af1fd6e13ff23e4e3d0058022" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/9eb2802797e36f3af1fd6e13ff23e4e3d0058022", + "reference": "9eb2802797e36f3af1fd6e13ff23e4e3d0058022", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "conflict": { + "phpstan/phpstan": "<1.0 || >= 3.0", + "vimeo/psalm": "<5.0 || >=7.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.4", + "infection/infection": "^0.29", + "marcocesarato/php-conventional-changelog": "^1.12", + "mikey179/vfsstream": "^1.6.10", + "phpbench/phpbench": "^1.3", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^10.5", + "rector/rector": "^2.0", + "vimeo/psalm": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "CuyZ\\Valinor\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Canon", + "email": "romain.hydrocanon@gmail.com", + "homepage": "https://github.com/romm" + } + ], + "description": "Library that helps to map any input into a strongly-typed value object structure.", + "homepage": "https://github.com/CuyZ/Valinor", + "keywords": [ + "array", + "conversion", + "hydrator", + "json", + "mapper", + "mapping", + "object", + "tree", + "yaml" + ], + "support": { + "issues": "https://github.com/CuyZ/Valinor/issues", + "source": "https://github.com/CuyZ/Valinor/tree/1.17.0" + }, + "funding": [ + { + "url": "https://github.com/romm", + "type": "github" + } + ], + "time": "2025-06-20T06:40:38+00:00" + }, { "name": "guzzlehttp/guzzle", "version": "7.10.0", @@ -491,6 +569,57 @@ }, "time": "2023-04-04T09:54:51+00:00" }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, { "name": "ralouphie/getallheaders", "version": "3.0.3", @@ -535,70 +664,6 @@ }, "time": "2019-03-08T08:55:37+00:00" }, - { - "name": "spatie/data-transfer-object", - "version": "3.9.1", - "source": { - "type": "git", - "url": "https://github.com/spatie/data-transfer-object.git", - "reference": "1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/data-transfer-object/zipball/1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8", - "reference": "1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8", - "shasum": "" - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "illuminate/collections": "^8.36", - "jetbrains/phpstorm-attributes": "^1.0", - "larapack/dd": "^1.1", - "phpunit/phpunit": "^9.5.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\DataTransferObject\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Brent Roose", - "email": "brent@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "Data transfer objects with batteries included", - "homepage": "https://github.com/spatie/data-transfer-object", - "keywords": [ - "data-transfer-object", - "spatie" - ], - "support": { - "issues": "https://github.com/spatie/data-transfer-object/issues", - "source": "https://github.com/spatie/data-transfer-object/tree/3.9.1" - }, - "funding": [ - { - "url": "https://spatie.be/open-source/support-us", - "type": "custom" - }, - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "abandoned": "spatie/laravel-data", - "time": "2022-09-16T13:34:38+00:00" - }, { "name": "symfony/deprecation-contracts", "version": "v3.6.0", @@ -669,39 +734,48 @@ ], "packages-dev": [ { - "name": "ivuorinen/markdowndocs", - "version": "4.0.0", + "name": "bartlett/sarif-php-converters", + "version": "1.5.0", "source": { "type": "git", - "url": "https://github.com/ivuorinen/markdowndocs.git", - "reference": "d5a11dcb177eeb998077dc69c6e65750e6ebe7ef" + "url": "https://github.com/llaville/sarif-php-converters.git", + "reference": "6230197e4054d004afec4ece83c50d0e3d451bee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ivuorinen/markdowndocs/zipball/d5a11dcb177eeb998077dc69c6e65750e6ebe7ef", - "reference": "d5a11dcb177eeb998077dc69c6e65750e6ebe7ef", + "url": "https://api.github.com/repos/llaville/sarif-php-converters/zipball/6230197e4054d004afec4ece83c50d0e3d451bee", + "reference": "6230197e4054d004afec4ece83c50d0e3d451bee", "shasum": "" }, "require": { + "bartlett/sarif-php-sdk": "^2.2", + "composer-runtime-api": "^2.0", "ext-json": "*", - "php": "^8.2", - "symfony/console": "^5 || ^6" + "ext-pcre": "*", + "ext-spl": "*", + "php": "^8.2" }, "require-dev": { - "ergebnis/composer-normalize": "^2.23.1", - "friendsofphp/php-cs-fixer": "^3.6", - "phpunit/phpunit": "^10", - "roave/security-advisories": "dev-latest", - "squizlabs/php_codesniffer": "^3.6", - "vimeo/psalm": "^5" + "bamarni/composer-bin-plugin": "^1.8", + "jawira/case-converter": "^3.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "symfony/console": "^7.0 || ^8.0" + }, + "suggest": { + "ext-libxml": "If you use the Console Tool and checkstyle input format", + "ext-simplexml": "If you use the Console Tool and checkstyle input format" }, - "bin": [ - "bin/phpdoc-md" - ], "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false, + "target-directory": "vendor-bin" + } + }, "autoload": { - "psr-0": { - "PHPDocsMD": "src/" + "psr-4": { + "Bartlett\\Sarif\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -710,34 +784,2010 @@ ], "authors": [ { - "name": "Victor Jonsson", - "email": "kontakt@victorjonsson.se" - }, - { - "name": "Grav CMS", - "email": "hello@getgrav.org", - "homepage": "https://getgrav.org" - }, - { - "name": "Ismo Vuorinen", - "homepage": "https://github.com/ivuorinen" + "name": "Laurent Laville", + "homepage": "https://github.com/llaville", + "role": "Lead" } ], - "description": "Command line tool for generating markdown-formatted class documentation", - "homepage": "https://github.com/ivuorinen/PHP-Markdown-Documentation-Generator", + "description": "Allows PHP projects to print a static code analysis report in SARIF format", + "keywords": [ + "converter", + "sarif" + ], "support": { - "issues": "https://github.com/ivuorinen/markdowndocs/issues", - "source": "https://github.com/ivuorinen/markdowndocs/tree/4.0.0" + "issues": "https://github.com/llaville/sarif-php-converters/issues", + "source": "https://github.com/llaville/sarif-php-converters" }, - "time": "2024-08-15T01:08:58+00:00" + "time": "2026-01-31T08:28:22+00:00" + }, + { + "name": "bartlett/sarif-php-sdk", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/llaville/sarif-php-sdk.git", + "reference": "d7f0174df65378b7f382372cef1bd7a76166abdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/llaville/sarif-php-sdk/zipball/d7f0174df65378b7f382372cef1bd7a76166abdd", + "reference": "d7f0174df65378b7f382372cef1bd7a76166abdd", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8", + "php-parallel-lint/php-console-highlighter": "^1.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false, + "target-directory": "vendor-bin" + } + }, + "autoload": { + "psr-4": { + "Bartlett\\Sarif\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Laville", + "homepage": "https://github.com/llaville", + "role": "Lead" + } + ], + "description": "PHP library to create and manipulate SARIF logs", + "keywords": [ + "sarif" + ], + "support": { + "issues": "https://github.com/llaville/sarif-php-sdk/issues", + "source": "https://github.com/llaville/sarif-php-sdk" + }, + "time": "2026-02-03T06:31:31+00:00" + }, + { + "name": "brianium/paratest", + "version": "v7.8.5", + "source": { + "type": "git", + "url": "https://github.com/paratestphp/paratest.git", + "reference": "9b324c8fc319cf9728b581c7a90e1c8f6361c5e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/9b324c8fc319cf9728b581c7a90e1c8f6361c5e5", + "reference": "9b324c8fc319cf9728b581c7a90e1c8f6361c5e5", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-simplexml": "*", + "fidry/cpu-core-counter": "^1.3.0", + "jean85/pretty-package-versions": "^2.1.1", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-timer": "^7.0.1", + "phpunit/phpunit": "^11.5.46", + "sebastian/environment": "^7.2.1", + "symfony/console": "^6.4.22 || ^7.3.4 || ^8.0.3", + "symfony/process": "^6.4.20 || ^7.3.4 || ^8.0.3" + }, + "require-dev": { + "doctrine/coding-standard": "^12.0.0", + "ext-pcov": "*", + "ext-posix": "*", + "phpstan/phpstan": "^2.1.33", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.11", + "phpstan/phpstan-strict-rules": "^2.0.7", + "squizlabs/php_codesniffer": "^3.13.5", + "symfony/filesystem": "^6.4.13 || ^7.3.2 || ^8.0.1" + }, + "bin": [ + "bin/paratest", + "bin/paratest_for_phpstorm" + ], + "type": "library", + "autoload": { + "psr-4": { + "ParaTest\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Scaturro", + "email": "scaturrob@gmail.com", + "role": "Developer" + }, + { + "name": "Filippo Tessarotto", + "email": "zoeslam@gmail.com", + "role": "Developer" + } + ], + "description": "Parallel testing for PHP", + "homepage": "https://github.com/paratestphp/paratest", + "keywords": [ + "concurrent", + "parallel", + "phpunit", + "testing" + ], + "support": { + "issues": "https://github.com/paratestphp/paratest/issues", + "source": "https://github.com/paratestphp/paratest/tree/v7.8.5" + }, + "funding": [ + { + "url": "https://github.com/sponsors/Slamdunk", + "type": "github" + }, + { + "url": "https://paypal.me/filippotessarotto", + "type": "paypal" + } + ], + "time": "2026-01-08T08:02:38+00:00" + }, + { + "name": "captainhook/captainhook", + "version": "5.28.5", + "source": { + "type": "git", + "url": "https://github.com/captainhook-git/captainhook.git", + "reference": "2a7316bf4ba4c3b11b3544c063788622d3520ee1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/captainhook-git/captainhook/zipball/2a7316bf4ba4c3b11b3544c063788622d3520ee1", + "reference": "2a7316bf4ba4c3b11b3544c063788622d3520ee1", + "shasum": "" + }, + "require": { + "captainhook/secrets": "^0.9.4", + "ext-json": "*", + "ext-spl": "*", + "ext-xml": "*", + "php": ">=8.0", + "sebastianfeldmann/camino": "^0.9.2", + "sebastianfeldmann/cli": "^3.3", + "sebastianfeldmann/git": "^3.16.0", + "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0" + }, + "replace": { + "sebastianfeldmann/captainhook": "*" + }, + "require-dev": { + "composer/composer": "~1 || ^2.0", + "mikey179/vfsstream": "~1" + }, + "bin": [ + "bin/captainhook" + ], + "type": "library", + "extra": { + "captainhook": { + "config": "captainhook.json" + }, + "branch-alias": { + "dev-main": "6.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "CaptainHook\\App\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "PHP git hook manager", + "homepage": "https://php.captainhook.info/", + "keywords": [ + "commit-msg", + "git", + "hooks", + "post-merge", + "pre-commit", + "pre-push", + "prepare-commit-msg" + ], + "support": { + "issues": "https://github.com/captainhook-git/captainhook/issues", + "source": "https://github.com/captainhook-git/captainhook/tree/5.28.5" + }, + "funding": [ + { + "url": "https://github.com/sponsors/sebastianfeldmann", + "type": "github" + } + ], + "time": "2026-02-28T08:59:22+00:00" + }, + { + "name": "captainhook/hook-installer", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/captainhook-git/hook-installer.git", + "reference": "fb3c45f6204b08baba999f4ffc4ae707bf684e8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/captainhook-git/hook-installer/zipball/fb3c45f6204b08baba999f4ffc4ae707bf684e8b", + "reference": "fb3c45f6204b08baba999f4ffc4ae707bf684e8b", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1|^2.0", + "php": ">=8.0" + }, + "require-dev": { + "composer/composer": "*" + }, + "type": "composer-plugin", + "extra": { + "class": "CaptainHook\\HookInstaller\\ComposerPlugin" + }, + "autoload": { + "psr-4": { + "CaptainHook\\HookInstaller\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "Composer Plugin that makes everyone activate the CaptainHook git hooks locally", + "support": { + "issues": "https://github.com/captainhook-git/hook-installer/issues", + "source": "https://github.com/captainhook-git/hook-installer/tree/1.0.4" + }, + "time": "2025-04-08T07:12:26+00:00" + }, + { + "name": "captainhook/secrets", + "version": "0.9.7", + "source": { + "type": "git", + "url": "https://github.com/captainhook-git/secrets.git", + "reference": "d62c97f75f81ac98e22f1c282482bd35fa82f631" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/captainhook-git/secrets/zipball/d62c97f75f81ac98e22f1c282482bd35fa82f631", + "reference": "d62c97f75f81ac98e22f1c282482bd35fa82f631", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "CaptainHook\\Secrets\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "Utility classes to detect secrets", + "keywords": [ + "commit-msg", + "keys", + "passwords", + "post-merge", + "prepare-commit-msg", + "secrets", + "tokens" + ], + "support": { + "issues": "https://github.com/captainhook-git/secrets/issues", + "source": "https://github.com/captainhook-git/secrets/tree/0.9.7" + }, + "funding": [ + { + "url": "https://github.com/sponsors/sebastianfeldmann", + "type": "github" + } + ], + "time": "2025-04-08T07:10:48+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.6", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=14" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", + "psr/log": "^1 || ^2 || ^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" + }, + "time": "2026-02-07T07:09:04+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2025-08-14T07:29:31+00:00" + }, + { + "name": "filp/whoops", + "version": "2.18.4", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.4" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-08-08T12:00:00+00:00" + }, + { + "name": "jawira/case-converter", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/jawira/case-converter.git", + "reference": "de9956122568743a83e0fc7e2eaa92c1b0de3f18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jawira/case-converter/zipball/de9956122568743a83e0fc7e2eaa92c1b0de3f18", + "reference": "de9956122568743a83e0fc7e2eaa92c1b0de3f18", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=7.4" + }, + "require-dev": { + "behat/behat": "^3.0", + "phpstan/phpstan": "^v2", + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "pds/skeleton": "PHP Package Development Standards", + "phing/phing": "PHP Build Tool" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jawira\\CaseConverter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jawira Portugal", + "email": "dev@tugal.be" + } + ], + "description": "Convert strings between 13 naming conventions: Snake case, Camel case, Pascal case, Kebab case, Ada case, Train case, Cobol case, Macro case, Upper case, Lower case, Sentence case, Title case and Dot notation.", + "homepage": "https://jawira.github.io/case-converter/", + "keywords": [ + "Ada case", + "Cobol case", + "Macro case", + "Train case", + "camel case", + "dot notation", + "kebab case", + "lower case", + "pascal case", + "sentence case", + "snake case", + "title case", + "upper case" + ], + "support": { + "issues": "https://github.com/jawira/case-converter/issues", + "source": "https://github.com/jawira/case-converter/tree/v3.6.0" + }, + "time": "2025-06-13T21:12:55+00:00" + }, + { + "name": "jbelien/phpstan-sarif-formatter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/jbelien/phpstan-sarif-formatter.git", + "reference": "6a21162f610238f86647065b7c99c9c7af380a96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jbelien/phpstan-sarif-formatter/zipball/6a21162f610238f86647065b7c99c9c7af380a96", + "reference": "6a21162f610238f86647065b7c99c9c7af380a96", + "shasum": "" + }, + "require": { + "nette/utils": "^3.0 || ^4.0", + "php": "^8.1", + "phpstan/phpstan": "^1.9 || ^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStanSarifErrorFormatter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "SARIF formatter for PHPStan", + "support": { + "issues": "https://github.com/jbelien/phpstan-sarif-formatter/issues", + "source": "https://github.com/jbelien/phpstan-sarif-formatter/tree/1.2.0" + }, + "funding": [ + { + "url": "https://github.com/jbelien", + "type": "github" + } + ], + "time": "2025-02-07T08:32:44+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "rector/rector": "^2.0", + "vimeo/psalm": "^4.3 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" + }, + "time": "2025-03-19T14:43:43+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "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", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nette/utils", + "version": "v4.1.3", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.5", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.1.3" + }, + "time": "2026-02-13T03:05:33+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "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": "nunomaduro/collision", + "version": "v8.9.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", + "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.18.4", + "nunomaduro/termwind": "^2.4.0", + "php": "^8.2.0", + "symfony/console": "^7.4.4 || ^8.0.4" + }, + "conflict": { + "laravel/framework": "<11.48.0 || >=14.0.0", + "phpunit/phpunit": "<11.5.50 || >=14.0.0" + }, + "require-dev": { + "brianium/paratest": "^7.8.5", + "larastan/larastan": "^3.9.2", + "laravel/framework": "^11.48.0 || ^12.52.0", + "laravel/pint": "^1.27.1", + "orchestra/testbench-core": "^9.12.0 || ^10.9.0", + "pestphp/pest": "^3.8.5 || ^4.4.1 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.0.3 || ^9.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2026-02-17T17:33:08+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.4.4 || ^8.0.4" + }, + "require-dev": { + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", + "phpstan/phpstan": "^1.12.32", + "phpstan/phpstan-strict-rules": "^1.6.2", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "It's like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2026-02-16T23:10:27+00:00" + }, + { + "name": "opis/json-schema", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/opis/json-schema.git", + "reference": "8458763e0dd0b6baa310e04f1829fc73da4e8c8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/json-schema/zipball/8458763e0dd0b6baa310e04f1829fc73da4e8c8a", + "reference": "8458763e0dd0b6baa310e04f1829fc73da4e8c8a", + "shasum": "" + }, + "require": { + "ext-json": "*", + "opis/string": "^2.1", + "opis/uri": "^1.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ext-bcmath": "*", + "ext-intl": "*", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\JsonSchema\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + }, + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + } + ], + "description": "Json Schema Validator for PHP", + "homepage": "https://opis.io/json-schema", + "keywords": [ + "json", + "json-schema", + "schema", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/opis/json-schema/issues", + "source": "https://github.com/opis/json-schema/tree/2.6.0" + }, + "time": "2025-10-17T12:46:48+00:00" + }, + { + "name": "opis/string", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/opis/string.git", + "reference": "3e4d2aaff518ac518530b89bb26ed40f4503635e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/string/zipball/3e4d2aaff518ac518530b89bb26ed40f4503635e", + "reference": "3e4d2aaff518ac518530b89bb26ed40f4503635e", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "ext-json": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\String\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "Multibyte strings as objects", + "homepage": "https://opis.io/string", + "keywords": [ + "multi-byte", + "opis", + "string", + "string manipulation", + "utf-8" + ], + "support": { + "issues": "https://github.com/opis/string/issues", + "source": "https://github.com/opis/string/tree/2.1.0" + }, + "time": "2025-10-17T12:38:41+00:00" + }, + { + "name": "opis/uri", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/opis/uri.git", + "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/uri/zipball/0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a", + "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a", + "shasum": "" + }, + "require": { + "opis/string": "^2.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Uri\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "Build, parse and validate URIs and URI-templates", + "homepage": "https://opis.io", + "keywords": [ + "URI Template", + "parse url", + "punycode", + "uri", + "uri components", + "url", + "validate uri" + ], + "support": { + "issues": "https://github.com/opis/uri/issues", + "source": "https://github.com/opis/uri/tree/1.1.0" + }, + "time": "2021-05-22T15:57:08+00:00" + }, + { + "name": "pestphp/pest", + "version": "v3.8.5", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest.git", + "reference": "7796630eafcfd1c02660cecdde3bc6984fbf01f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest/zipball/7796630eafcfd1c02660cecdde3bc6984fbf01f4", + "reference": "7796630eafcfd1c02660cecdde3bc6984fbf01f4", + "shasum": "" + }, + "require": { + "brianium/paratest": "^7.8.5", + "nunomaduro/collision": "^8.8.3", + "nunomaduro/termwind": "^2.3.3", + "pestphp/pest-plugin": "^3.0.0", + "pestphp/pest-plugin-arch": "^3.1.1", + "pestphp/pest-plugin-mutate": "^3.0.5", + "php": "^8.2.0", + "phpunit/phpunit": "^11.5.50" + }, + "conflict": { + "filp/whoops": "<2.16.0", + "phpunit/phpunit": ">11.5.50", + "sebastian/exporter": "<6.0.0", + "webmozart/assert": "<1.11.0" + }, + "require-dev": { + "pestphp/pest-dev-tools": "^3.4.0", + "pestphp/pest-plugin-type-coverage": "^3.6.1", + "symfony/process": "^7.4.4" + }, + "bin": [ + "bin/pest" + ], + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Mutate\\Plugins\\Mutate", + "Pest\\Plugins\\Configuration", + "Pest\\Plugins\\Bail", + "Pest\\Plugins\\Cache", + "Pest\\Plugins\\Coverage", + "Pest\\Plugins\\Init", + "Pest\\Plugins\\Environment", + "Pest\\Plugins\\Help", + "Pest\\Plugins\\Memory", + "Pest\\Plugins\\Only", + "Pest\\Plugins\\Printer", + "Pest\\Plugins\\ProcessIsolation", + "Pest\\Plugins\\Profile", + "Pest\\Plugins\\Retry", + "Pest\\Plugins\\Snapshot", + "Pest\\Plugins\\Verbose", + "Pest\\Plugins\\Version", + "Pest\\Plugins\\Parallel" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "files": [ + "src/Functions.php", + "src/Pest.php" + ], + "psr-4": { + "Pest\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "The elegant PHP Testing Framework.", + "keywords": [ + "framework", + "pest", + "php", + "test", + "testing", + "unit" + ], + "support": { + "issues": "https://github.com/pestphp/pest/issues", + "source": "https://github.com/pestphp/pest/tree/v3.8.5" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2026-01-28T01:33:45+00:00" + }, + { + "name": "pestphp/pest-plugin", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin.git", + "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/e79b26c65bc11c41093b10150c1341cc5cdbea83", + "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0.0", + "composer-runtime-api": "^2.2.2", + "php": "^8.2" + }, + "conflict": { + "pestphp/pest": "<3.0.0" + }, + "require-dev": { + "composer/composer": "^2.7.9", + "pestphp/pest": "^3.0.0", + "pestphp/pest-dev-tools": "^3.0.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Pest\\Plugin\\Manager" + }, + "autoload": { + "psr-4": { + "Pest\\Plugin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Pest plugin manager", + "keywords": [ + "framework", + "manager", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2024-09-08T23:21:41+00:00" + }, + { + "name": "pestphp/pest-plugin-arch", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-arch.git", + "reference": "db7bd9cb1612b223e16618d85475c6f63b9c8daa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/db7bd9cb1612b223e16618d85475c6f63b9c8daa", + "reference": "db7bd9cb1612b223e16618d85475c6f63b9c8daa", + "shasum": "" + }, + "require": { + "pestphp/pest-plugin": "^3.0.0", + "php": "^8.2", + "ta-tikoma/phpunit-architecture-test": "^0.8.4" + }, + "require-dev": { + "pestphp/pest": "^3.8.1", + "pestphp/pest-dev-tools": "^3.4.0" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Arch\\Plugin" + ] + } + }, + "autoload": { + "files": [ + "src/Autoload.php" + ], + "psr-4": { + "Pest\\Arch\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Arch plugin for Pest PHP.", + "keywords": [ + "arch", + "architecture", + "framework", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-arch/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2025-04-16T22:59:48+00:00" + }, + { + "name": "pestphp/pest-plugin-mutate", + "version": "v3.0.5", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-mutate.git", + "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-mutate/zipball/e10dbdc98c9e2f3890095b4fe2144f63a5717e08", + "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.2.0", + "pestphp/pest-plugin": "^3.0.0", + "php": "^8.2", + "psr/simple-cache": "^3.0.0" + }, + "require-dev": { + "pestphp/pest": "^3.0.8", + "pestphp/pest-dev-tools": "^3.0.0", + "pestphp/pest-plugin-type-coverage": "^3.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Pest\\Mutate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sandro Gehri", + "email": "sandrogehri@gmail.com" + } + ], + "description": "Mutates your code to find untested cases", + "keywords": [ + "framework", + "mutate", + "mutation", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-mutate/tree/v3.0.5" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/gehrisandro", + "type": "github" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2024-09-22T07:54:40+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "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": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "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": "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" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "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" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "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": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "897b5986ece6b4f9d8413fea345c7d49c757d6bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/897b5986ece6b4f9d8413fea345c7d49c757d6bf", + "reference": "897b5986ece6b4f9d8413fea345c7d49c757d6bf", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^2.0", + "phpstan/phpdoc-parser": "^2.0", + "webmozart/assert": "^1.9.1 || ^2" + }, + "require-dev": { + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26", + "shipmonk/dead-code-detector": "^0.5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.2" + }, + "time": "2026-03-01T18:43:49+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9", + "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev", + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0" + }, + "time": "2026-01-06T21:53:42+00:00" + }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.3.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" + }, + "time": "2026-01-25T14:56:51+00:00" }, { "name": "phpstan/phpstan", - "version": "2.1.39", + "version": "2.1.40", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", - "reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", + "reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", "shasum": "" }, "require": { @@ -782,7 +2832,463 @@ "type": "github" } ], - "time": "2026-02-11T14:48:56+00:00" + "time": "2026-02-23T15:04:35+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.46" + }, + "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-main": "11.0.x-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 provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "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/11.0.12" + }, + "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/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-24T07:01:01+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "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", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "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/5.1.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/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-02T13:52:54+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "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", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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": "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/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.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": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.50", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fdfc727f0fcacfeb8fcb30c7e5da173125b58be3", + "reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3", + "shasum": "" + }, + "require": { + "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.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "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/11.5.50" + }, + "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": "2026-01-27T05:59:18+00:00" }, { "name": "psr/container", @@ -837,6 +3343,1381 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "ramsey/conventional-commits", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/conventional-commits.git", + "reference": "2d24a17b3505f03948c315ff55c14b03d6f8bc61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/conventional-commits/zipball/2d24a17b3505f03948c315ff55c14b03d6f8bc61", + "reference": "2d24a17b3505f03948c315ff55c14b03d6f8bc61", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0", + "ext-json": "*", + "jawira/case-converter": "^3.5", + "opis/json-schema": "^2.3", + "php": "^8.1", + "symfony/console": "^6.0 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.0 || ^7.0 || ^8.0" + }, + "require-dev": { + "captainhook/captainhook": "^5.15", + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.30", + "hamcrest/hamcrest-php": "^2.0", + "mockery/mockery": "^1.6.12", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5.63", + "ramsey/coding-standard": "^2.3", + "ramsey/composer-repl": "^1.5", + "ramsey/composer-repl-lib": "^1.4.0", + "roave/security-advisories": "dev-latest", + "sebastianfeldmann/cli": "^3.4", + "sebastianfeldmann/git": "^3.8", + "spatie/phpunit-snapshot-assertions": "^5.1", + "symfony/process": "^6.0 || ^7.0 || ^8.0" + }, + "suggest": { + "captainhook/captainhook": "Manage your project's Git hooks with CaptainHook, and use ramsey/conventional-commits in your commit-msg and prepare-commit-msg hooks." + }, + "bin": [ + "bin/conventional-commits" + ], + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "branch-alias": { + "dev-main": "1.x-dev" + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\CaptainHook\\": "src/CaptainHook/", + "Ramsey\\ConventionalCommits\\": "src/ConventionalCommits/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for creating and validating commit messages according to the Conventional Commits specification. Includes a CaptainHook action!", + "keywords": [ + "HOOK", + "captainhook", + "commit", + "commit-msg", + "conventional", + "conventional-commits", + "git", + "plugin" + ], + "support": { + "issues": "https://github.com/ramsey/conventional-commits/issues", + "source": "https://github.com/ramsey/conventional-commits/tree/1.7.0" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + } + ], + "time": "2026-03-04T06:55:21+00:00" + }, + { + "name": "rector/rector", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/bbd37aedd8df749916cffa2a947cfc4714d1ba2c", + "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.38" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/2.3.8" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2026-02-22T09:45:50+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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", + "role": "lead" + } + ], + "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/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "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", + "role": "lead" + } + ], + "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", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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" + } + ], + "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", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-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": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "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/6.3.3" + }, + "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:26:40+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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": "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/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "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/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "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/7.2.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/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-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": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "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/6.3.2" + }, + "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": "2025-09-24T06:12:51+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "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/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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", + "role": "lead" + } + ], + "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/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.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", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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" + } + ], + "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", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.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/6.0.3" + }, + "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-13T04:42:22+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "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", + "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", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" + }, + "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/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:55:48+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "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", + "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", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "sebastianfeldmann/camino", + "version": "0.9.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianfeldmann/camino.git", + "reference": "bf2e4c8b2a029e9eade43666132b61331e3e8184" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianfeldmann/camino/zipball/bf2e4c8b2a029e9eade43666132b61331e3e8184", + "reference": "bf2e4c8b2a029e9eade43666132b61331e3e8184", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "SebastianFeldmann\\Camino\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "Path management the OO way", + "homepage": "https://github.com/sebastianfeldmann/camino", + "keywords": [ + "file system", + "path" + ], + "support": { + "issues": "https://github.com/sebastianfeldmann/camino/issues", + "source": "https://github.com/sebastianfeldmann/camino/tree/0.9.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianfeldmann", + "type": "github" + } + ], + "time": "2022-01-03T13:15:10+00:00" + }, + { + "name": "sebastianfeldmann/cli", + "version": "3.4.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianfeldmann/cli.git", + "reference": "6fa122afd528dae7d7ec988a604aa6c600f5d9b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianfeldmann/cli/zipball/6fa122afd528dae7d7ec988a604aa6c600f5d9b5", + "reference": "6fa122afd528dae7d7ec988a604aa6c600f5d9b5", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "symfony/process": "^4.3 | ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "autoload": { + "psr-4": { + "SebastianFeldmann\\Cli\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "PHP cli helper classes", + "homepage": "https://github.com/sebastianfeldmann/cli", + "keywords": [ + "cli" + ], + "support": { + "issues": "https://github.com/sebastianfeldmann/cli/issues", + "source": "https://github.com/sebastianfeldmann/cli/tree/3.4.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianfeldmann", + "type": "github" + } + ], + "time": "2024-11-26T10:19:01+00:00" + }, + { + "name": "sebastianfeldmann/git", + "version": "3.16.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianfeldmann/git.git", + "reference": "40a5cc043f0957228767f639e370ec92590e940f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianfeldmann/git/zipball/40a5cc043f0957228767f639e370ec92590e940f", + "reference": "40a5cc043f0957228767f639e370ec92590e940f", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "php": ">=8.0", + "sebastianfeldmann/cli": "^3.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "SebastianFeldmann\\Git\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "PHP git wrapper", + "homepage": "https://github.com/sebastianfeldmann/git", + "keywords": [ + "git" + ], + "support": { + "issues": "https://github.com/sebastianfeldmann/git/issues", + "source": "https://github.com/sebastianfeldmann/git/tree/3.16.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianfeldmann", + "type": "github" + } + ], + "time": "2026-01-26T20:59:18+00:00" + }, { "name": "squizlabs/php_codesniffer", "version": "4.0.1", @@ -917,48 +4798,100 @@ "time": "2025-11-10T16:43:36+00:00" }, { - "name": "symfony/console", - "version": "v6.4.32", + "name": "staabm/side-effects-detector", + "version": "1.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3" + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", - "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", "shasum": "" }, "require": { - "php": ">=8.1", + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/console", + "version": "v7.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "shasum": "" + }, + "require": { + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" + "symfony/string": "^7.2|^8.0" }, "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -992,7 +4925,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.32" + "source": "https://github.com/symfony/console/tree/v7.4.7" }, "funding": [ { @@ -1012,7 +4945,145 @@ "type": "tidelift" } ], - "time": "2026-01-13T08:45:59+00:00" + "time": "2026-03-06T14:06:20+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", + "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.6" + }, + "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-02-25T16:50:00+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.4.6" + }, + "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-01-29T09:40:50+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1349,6 +5420,71 @@ ], "time": "2024-12-23T08:48:59+00:00" }, + { + "name": "symfony/process", + "version": "v7.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "608476f4604102976d687c483ac63a79ba18cc97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", + "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "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": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.4.5" + }, + "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-01-26T15:07:59+00:00" + }, { "name": "symfony/service-contracts", "version": "v3.6.1", @@ -1438,16 +5574,16 @@ }, { "name": "symfony/string", - "version": "v7.4.4", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f" + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f", + "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", "shasum": "" }, "require": { @@ -1505,7 +5641,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.4" + "source": "https://github.com/symfony/string/tree/v7.4.6" }, "funding": [ { @@ -1525,7 +5661,178 @@ "type": "tidelift" } ], - "time": "2026-01-12T10:54:30+00:00" + "time": "2026-02-09T09:33:46+00:00" + }, + { + "name": "ta-tikoma/phpunit-architecture-test", + "version": "0.8.7", + "source": { + "type": "git", + "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", + "reference": "1248f3f506ca9641d4f68cebcd538fa489754db8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/1248f3f506ca9641d4f68cebcd538fa489754db8", + "reference": "1248f3f506ca9641d4f68cebcd538fa489754db8", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18.0 || ^5.0.0", + "php": "^8.1.0", + "phpdocumentor/reflection-docblock": "^5.3.0 || ^6.0.0", + "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0 || ^13.0.0", + "symfony/finder": "^6.4.0 || ^7.0.0 || ^8.0.0" + }, + "require-dev": { + "laravel/pint": "^1.13.7", + "phpstan/phpstan": "^1.10.52" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPUnit\\Architecture\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ni Shi", + "email": "futik0ma011@gmail.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Methods for testing application architecture", + "keywords": [ + "architecture", + "phpunit", + "stucture", + "test", + "testing" + ], + "support": { + "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", + "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.7" + }, + "time": "2026-02-17T17:25:14+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": "2025-11-17T20:03:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "2.1.6", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/ff31ad6efc62e66e518fbab1cde3453d389bcdc8", + "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", + "php": "^8.2" + }, + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-feature/2-0": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/2.1.6" + }, + "time": "2026-02-27T10:28:38+00:00" } ], "aliases": [], @@ -1534,7 +5841,8 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^8.2" + "php": "^8.2", + "ext-json": "*" }, "platform-dev": {}, "plugin-api-version": "2.9.0" diff --git a/example.php b/example.php index a12e728..c6d1a99 100644 --- a/example.php +++ b/example.php @@ -5,7 +5,8 @@ require_once "vendor/autoload.php"; $client = new Ivuorinen\BusinessDataFetcher\BusinessDataFetcher(); try { $results = $client->getBusinessInformation("1639413-9"); - print_r($results); + // Convert to JSON + echo json_encode($results, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT); } catch (Exception $e) { var_dump($e); } diff --git a/gen/parser.php b/gen/parser.php index d8d3d1e..6d85edd 100644 --- a/gen/parser.php +++ b/gen/parser.php @@ -87,7 +87,7 @@ foreach ($classes as $className => $vars) { // Get name of the class from filename and split CamelCase to words. $classNameString = $className; $classNameString = str_replace("Bis", "", $classNameString); - $classNameString = preg_replace('/(? $vars) { } if (!empty($traits)) { - $usesHeader[] = "use Ivuorinen\BusinessDataFetcher\Traits;"; + $usesHeader[] = "use Ivuorinen\BusinessDataFetcher\\v1\Traits;"; } $usesString = implode("\n", $usesHeader); @@ -134,7 +134,7 @@ foreach ($classes as $className => $vars) { $file = " $file) { $filePath = sprintf('%s%s%s.php', $dtoDir, DS, $className); echo $filePath . "\n"; diff --git a/phpcs.xml b/phpcs.xml index 66173cf..7d00f4f 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,6 +1,7 @@ PSR12 + src diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..d7b8544 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,18 @@ + + + + + tests/Unit + + + + + src + + + diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..002641b --- /dev/null +++ b/rector.php @@ -0,0 +1,16 @@ +withPaths([ + __DIR__ . '/src', + ]) + ->withPhpSets(php82: true) + ->withPreparedSets( + deadCode: true, + codeQuality: true, + typeDeclarations: true, + ); diff --git a/src/BusinessDataFetcher.php b/src/BusinessDataFetcher.php index 8b5ca69..506e7b7 100644 --- a/src/BusinessDataFetcher.php +++ b/src/BusinessDataFetcher.php @@ -2,47 +2,37 @@ namespace Ivuorinen\BusinessDataFetcher; -use GuzzleHttp\Client; use GuzzleHttp\Exception\RequestException; -use Ivuorinen\BusinessDataFetcher\Dto\BisCompanyDetails; -use Ivuorinen\BusinessDataFetcher\Exceptions\ApiResponseErrorException; +use Ivuorinen\BusinessDataFetcher\Http\AbstractClient; +use Ivuorinen\BusinessDataFetcher\v1\Dto\BisCompanyDetails; +use Ivuorinen\BusinessDataFetcher\v1\Exceptions\ApiResponseErrorException; use Psr\Http\Message\ResponseInterface; -/** - * Fetches and returns business data from avoindata - */ -class BusinessDataFetcher +/** Client for the PRH BIS v1 API (Finnish business data). */ +class BusinessDataFetcher extends AbstractClient { - /** - * @var \GuzzleHttp\Client - */ - private Client $httpClient; - - /** - * BusinessDataFetcher constructor. - */ - public function __construct() + /** @inheritDoc */ + protected function getBaseUri(): string { - $this->httpClient = new Client([ - 'base_uri' => 'https://avoindata.prh.fi', - 'timeout' => 2, - ]); + return 'https://avoindata.prh.fi'; + } + + /** @inheritDoc */ + protected function getTimeout(): int + { + return 2; } /** * Fetch Business Information. * - * @return BisCompanyDetails[] $response_data + * @return BisCompanyDetails[] * @throws \Exception|\GuzzleHttp\Exception\GuzzleException */ public function getBusinessInformation(string $businessId): array { - // Set request variables - $requestUrl = '/bis/v1'; - - // Get the business data try { - $uri = $requestUrl . '/' . $businessId; + $uri = '/bis/v1/' . rawurlencode($businessId); $response = $this->httpClient->get($uri); if ($response->getStatusCode() !== 200) { @@ -52,7 +42,7 @@ class BusinessDataFetcher ); } - $response_data = $this->parseResponse($response); + return $this->parseResponse($response); } catch (RequestException $exception) { throw new ApiResponseErrorException( $exception->getMessage(), @@ -60,8 +50,6 @@ class BusinessDataFetcher $exception ); } - - return $response_data; } /** @@ -69,8 +57,7 @@ class BusinessDataFetcher * * @return BisCompanyDetails[] * @throws \JsonException - * @throws \Spatie\DataTransferObject\Exceptions\UnknownProperties - * @throws \Ivuorinen\BusinessDataFetcher\Exceptions\ApiResponseErrorException + * @throws ApiResponseErrorException */ public function parseResponse(ResponseInterface $response): array { @@ -88,7 +75,7 @@ class BusinessDataFetcher ); } - if (!isset($data['results'])) { + if (!isset($data['results']) || !is_array($data['results'])) { throw new ApiResponseErrorException( 'Invalid response data', $response->getStatusCode() @@ -98,7 +85,7 @@ class BusinessDataFetcher $results = []; foreach ($data['results'] as $result) { - $results[] = new BisCompanyDetails($result); + $results[] = $this->mapper->map(BisCompanyDetails::class, $result); } return $results; diff --git a/src/Dto/BisAddress.php b/src/Dto/BisAddress.php deleted file mode 100644 index c3233e1..0000000 --- a/src/Dto/BisAddress.php +++ /dev/null @@ -1,56 +0,0 @@ -httpClient = $httpClient ?? HttpClientFactory::create( + $this->getBaseUri(), + $this->getTimeout() + ); + + $this->mapper = (new MapperBuilder()) + ->allowSuperfluousKeys() + ->mapper(); + } + + /** Get the base URI for the API. */ + abstract protected function getBaseUri(): string; + + /** Get the HTTP request timeout in seconds. */ + protected function getTimeout(): int + { + return 10; + } + + /** + * Perform a GET request and decode the JSON response. + * + * @param array $query + * @return array + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \JsonException + */ + protected function getJson(string $uri, array $query = []): array + { + $options = []; + if ($query !== []) { + $options['query'] = $query; + } + + $response = $this->httpClient->get($uri, $options); + + $data = json_decode( + $response->getBody()->getContents(), + true, + 512, + JSON_THROW_ON_ERROR + ); + + if (!is_array($data)) { + throw new \JsonException('Response is not a valid JSON object or array'); + } + + return $data; + } +} diff --git a/src/Http/HttpClientFactory.php b/src/Http/HttpClientFactory.php new file mode 100644 index 0000000..f3e1a43 --- /dev/null +++ b/src/Http/HttpClientFactory.php @@ -0,0 +1,18 @@ + $baseUri, + 'timeout' => $timeout, + ]); + } +} diff --git a/src/Traits/HasLanguage.php b/src/Traits/HasLanguage.php deleted file mode 100644 index 9929df8..0000000 --- a/src/Traits/HasLanguage.php +++ /dev/null @@ -1,26 +0,0 @@ -language) { - 'fi' => 'finnish', - 'en' => 'english', - 'sv' => 'swedish', - default => 'unknown:' . $this->language, - }; - } -} diff --git a/src/Traits/HasSource.php b/src/Traits/HasSource.php deleted file mode 100644 index 4315a3d..0000000 --- a/src/Traits/HasSource.php +++ /dev/null @@ -1,34 +0,0 @@ -source) { - 0 => 'common', - 1 => 'Finnish Patent and Registration Office', - 2 => 'Tax Administration', - 3 => 'Business Information System', - default => '', - }; - } -} diff --git a/src/Traits/HasVersion.php b/src/Traits/HasVersion.php deleted file mode 100644 index 19b308f..0000000 --- a/src/Traits/HasVersion.php +++ /dev/null @@ -1,11 +0,0 @@ -1 for historical contact details. - */ - public int $version = 0; -} diff --git a/src/v1/Dto/BisAddress.php b/src/v1/Dto/BisAddress.php new file mode 100644 index 0000000..5256c1e --- /dev/null +++ b/src/v1/Dto/BisAddress.php @@ -0,0 +1,27 @@ + $names + * @param list $auxiliaryNames + * @param list $addresses + * @param list $companyForms + * @param list $liquidations + * @param list $businessLines + * @param list $languages + * @param list $registeredOffices + * @param list $contactDetails + * @param list $registeredEntries + * @param list $businessIdChanges + */ + public function __construct( + public string $businessId = '', + public string $registrationDate = '', + public ?string $companyForm = null, + public ?string $detailsUri = null, + public string $name = '', + public array $names = [], + public array $auxiliaryNames = [], + public array $addresses = [], + public array $companyForms = [], + public array $liquidations = [], + public array $businessLines = [], + public array $languages = [], + public array $registeredOffices = [], + public array $contactDetails = [], + public array $registeredEntries = [], + public array $businessIdChanges = [], + ) { + } +} diff --git a/src/v1/Dto/BisCompanyForm.php b/src/v1/Dto/BisCompanyForm.php new file mode 100644 index 0000000..b7c120d --- /dev/null +++ b/src/v1/Dto/BisCompanyForm.php @@ -0,0 +1,23 @@ +authority) { diff --git a/src/Traits/HasChange.php b/src/v1/Traits/HasChange.php similarity index 63% rename from src/Traits/HasChange.php rename to src/v1/Traits/HasChange.php index 9ef68ae..5b1dd63 100644 --- a/src/Traits/HasChange.php +++ b/src/v1/Traits/HasChange.php @@ -1,19 +1,11 @@ change) { diff --git a/src/v1/Traits/HasLanguage.php b/src/v1/Traits/HasLanguage.php new file mode 100644 index 0000000..1b5b953 --- /dev/null +++ b/src/v1/Traits/HasLanguage.php @@ -0,0 +1,22 @@ +language === null) { + return 'unknown'; + } + + return match ($this->language) { + 'fi' => 'finnish', + 'en' => 'english', + 'sv' => 'swedish', + default => 'unknown:' . $this->language, + }; + } +} diff --git a/src/Traits/HasRegister.php b/src/v1/Traits/HasRegister.php similarity index 68% rename from src/Traits/HasRegister.php rename to src/v1/Traits/HasRegister.php index 9783b65..be671af 100644 --- a/src/Traits/HasRegister.php +++ b/src/v1/Traits/HasRegister.php @@ -1,18 +1,11 @@ register) { diff --git a/src/v1/Traits/HasSource.php b/src/v1/Traits/HasSource.php new file mode 100644 index 0000000..e75e062 --- /dev/null +++ b/src/v1/Traits/HasSource.php @@ -0,0 +1,19 @@ +source) { + 0 => 'common', + 1 => 'Finnish Patent and Registration Office', + 2 => 'Tax Administration', + 3 => 'Business Information System', + default => '', + }; + } +} diff --git a/src/v3/Client.php b/src/v3/Client.php new file mode 100644 index 0000000..02a59dd --- /dev/null +++ b/src/v3/Client.php @@ -0,0 +1,124 @@ + $name, + 'businessId' => $businessId, + 'location' => $location, + 'companyForm' => $companyForm, + 'mainBusinessLine' => $mainBusinessLine, + 'registrationDateStart' => $registrationDateStart, + 'registrationDateEnd' => $registrationDateEnd, + 'postCode' => $postCode, + 'businessIdRegistrationStart' => $businessIdRegistrationStart, + 'businessIdRegistrationEnd' => $businessIdRegistrationEnd, + 'page' => $page, + ], fn (string|int|null $v): bool => $v !== null); + + try { + $data = $this->getJson(self::API_PREFIX . '/companies', $query); + return $this->mapper->map(CompanySearchResult::class, $data); + } catch (RequestException | \JsonException $e) { + throw new V3ApiException($e->getMessage(), (int) $e->getCode(), $e); + } + } + + /** + * Retrieve code list description. + * + * @throws V3ApiException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getDescription(string $code, string $lang = 'en'): string + { + try { + $response = $this->httpClient->get(self::API_PREFIX . '/description', [ + 'query' => ['code' => $code, 'lang' => $lang], + ]); + + return $response->getBody()->getContents(); + } catch (RequestException $e) { + throw new V3ApiException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieve postal code details. + * + * @return PostCodeEntry[] + * @throws V3ApiException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getPostCodes(string $lang = 'en'): array + { + try { + $data = $this->getJson(self::API_PREFIX . '/post_codes', ['lang' => $lang]); + + $results = []; + foreach ($data as $entry) { + $results[] = $this->mapper->map(PostCodeEntry::class, $entry); + } + + return $results; + } catch (RequestException | \JsonException $e) { + throw new V3ApiException($e->getMessage(), (int) $e->getCode(), $e); + } + } + + /** + * Get all companies as a ZIP download stream. + * + * @throws V3ApiException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getAllCompanies(): StreamInterface + { + try { + $response = $this->httpClient->get(self::API_PREFIX . '/all_companies', [ + 'stream' => true, + ]); + + return $response->getBody(); + } catch (RequestException $e) { + throw new V3ApiException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/src/v3/Dto/Address.php b/src/v3/Dto/Address.php new file mode 100644 index 0000000..607fa7e --- /dev/null +++ b/src/v3/Dto/Address.php @@ -0,0 +1,28 @@ + $postOffices + */ + public function __construct( + public int $type = 0, + public string $source = '', + public ?string $street = null, + public ?string $postCode = null, + public array $postOffices = [], + public ?string $postOfficeBox = null, + public ?string $buildingNumber = null, + public ?string $entrance = null, + public ?string $apartmentNumber = null, + public ?string $apartmentIdSuffix = null, + public ?string $co = null, + public ?string $country = null, + public ?string $freeAddressLine = null, + public ?string $registrationDate = null, + ) { + } +} diff --git a/src/v3/Dto/BusinessId.php b/src/v3/Dto/BusinessId.php new file mode 100644 index 0000000..f4427a9 --- /dev/null +++ b/src/v3/Dto/BusinessId.php @@ -0,0 +1,14 @@ + $descriptions + */ + public function __construct( + public string $code, + public array $descriptions = [], + public ?string $typeCodeSet = null, + public ?string $registrationDate = null, + public ?string $source = null, + ) { + } +} diff --git a/src/v3/Dto/Company.php b/src/v3/Dto/Company.php new file mode 100644 index 0000000..f843266 --- /dev/null +++ b/src/v3/Dto/Company.php @@ -0,0 +1,32 @@ + $names + * @param list $companyForms + * @param list $companySituations + * @param list $registeredEntries + * @param list
$addresses + */ + public function __construct( + public BusinessId $businessId, + public string $tradeRegisterStatus = '', + public string $lastModified = '', + public ?EuId $euId = null, + public array $names = [], + public ?BusinessLine $mainBusinessLine = null, + public ?Website $website = null, + public array $companyForms = [], + public array $companySituations = [], + public array $registeredEntries = [], + public array $addresses = [], + public ?string $status = null, + public ?string $registrationDate = null, + public ?string $endDate = null, + ) { + } +} diff --git a/src/v3/Dto/CompanyForm.php b/src/v3/Dto/CompanyForm.php new file mode 100644 index 0000000..b261c6c --- /dev/null +++ b/src/v3/Dto/CompanyForm.php @@ -0,0 +1,20 @@ + $descriptions + */ + public function __construct( + public string $type = '', + public string $source = '', + public int $version = 0, + public array $descriptions = [], + public ?string $registrationDate = null, + public ?string $endDate = null, + ) { + } +} diff --git a/src/v3/Dto/CompanySearchResult.php b/src/v3/Dto/CompanySearchResult.php new file mode 100644 index 0000000..3e9c42f --- /dev/null +++ b/src/v3/Dto/CompanySearchResult.php @@ -0,0 +1,16 @@ + $companies + */ + public function __construct( + public int $totalResults = 0, + public array $companies = [], + ) { + } +} diff --git a/src/v3/Dto/CompanySituation.php b/src/v3/Dto/CompanySituation.php new file mode 100644 index 0000000..fc47b90 --- /dev/null +++ b/src/v3/Dto/CompanySituation.php @@ -0,0 +1,15 @@ + $descriptions + */ + public function __construct( + public string $type = '', + public string $register = '', + public string $authority = '', + public array $descriptions = [], + public ?string $registrationDate = null, + public ?string $endDate = null, + ) { + } +} diff --git a/src/v3/Dto/Website.php b/src/v3/Dto/Website.php new file mode 100644 index 0000000..a4a4952 --- /dev/null +++ b/src/v3/Dto/Website.php @@ -0,0 +1,14 @@ +in('Feature'); diff --git a/tests/Unit/BusinessDataFetcherTest.php b/tests/Unit/BusinessDataFetcherTest.php new file mode 100644 index 0000000..65c9ab6 --- /dev/null +++ b/tests/Unit/BusinessDataFetcherTest.php @@ -0,0 +1,52 @@ + HandlerStack::create($mock)]); + return new BusinessDataFetcher($client); +} + +it('returns BisCompanyDetails array on success', function () { + $json = file_get_contents(__DIR__ . '/../Fixtures/sample-response.json'); + $fetcher = createFetcherWithMock(new Response(200, [], $json)); + + $results = $fetcher->getBusinessInformation('1639413-9'); + + expect($results)->toBeArray() + ->and($results)->toHaveCount(1) + ->and($results[0])->toBeInstanceOf(BisCompanyDetails::class) + ->and($results[0]->businessId)->toBe('1639413-9'); +}); + +it('throws on non-200 status code', function () { + $fetcher = createFetcherWithMock( + new Response(500, [], '{"error": "Internal Server Error"}') + ); + + $fetcher->getBusinessInformation('1639413-9'); +})->throws(ApiResponseErrorException::class); + +it('throws on malformed JSON', function () { + $fetcher = createFetcherWithMock( + new Response(200, [], 'not-json') + ); + + $fetcher->getBusinessInformation('1639413-9'); +})->throws(JsonException::class); + +it('throws when results key is missing', function () { + $fetcher = createFetcherWithMock( + new Response(200, [], '{"type": "test"}') + ); + + $fetcher->getBusinessInformation('1639413-9'); +})->throws(ApiResponseErrorException::class); diff --git a/tests/Unit/v1/Dto/BisCompanyDetailsTest.php b/tests/Unit/v1/Dto/BisCompanyDetailsTest.php new file mode 100644 index 0000000..3967008 --- /dev/null +++ b/tests/Unit/v1/Dto/BisCompanyDetailsTest.php @@ -0,0 +1,43 @@ +allowSuperfluousKeys() + ->mapper(); + + $result = $mapper->map(BisCompanyDetails::class, $json['results'][0]); + + expect($result) + ->toBeInstanceOf(BisCompanyDetails::class) + ->and($result->businessId)->toBe('1639413-9') + ->and($result->registrationDate)->toBe('2001-04-03') + ->and($result->companyForm)->toBe('OY') + ->and($result->name)->toBe('Oy Example Ab') + ->and($result->names)->toHaveCount(1) + ->and($result->names[0]->name)->toBe('Oy Example Ab') + ->and($result->names[0]->getLanguageString())->toBe('finnish') + ->and($result->names[0]->getSourceText())->toBe('common') + ->and($result->addresses)->toHaveCount(1) + ->and($result->addresses[0]->street)->toBe('Testitie 1') + ->and($result->addresses[0]->postCode)->toBe('00100') + ->and($result->addresses[0]->city)->toBe('HELSINKI') + ->and($result->companyForms)->toHaveCount(1) + ->and($result->companyForms[0]->name)->toBe('Osakeyhtiö') + ->and($result->businessLines)->toHaveCount(1) + ->and($result->businessLines[0]->name)->toBe('Computer programming activities') + ->and($result->registeredEntries)->toHaveCount(1) + ->and($result->registeredEntries[0]->getAuthorityString())->toBe('Finnish Patent and Registration Office') + ->and($result->registeredEntries[0]->getRegisterString())->toBe('Trade Register') + ->and($result->contactDetails)->toHaveCount(1) + ->and($result->contactDetails[0]->value)->toBe('www.example.fi'); +}); diff --git a/tests/Unit/v1/Dto/DtoHydrationTest.php b/tests/Unit/v1/Dto/DtoHydrationTest.php new file mode 100644 index 0000000..132ac59 --- /dev/null +++ b/tests/Unit/v1/Dto/DtoHydrationTest.php @@ -0,0 +1,87 @@ +allowSuperfluousKeys() + ->mapper(); +} + +it('hydrates all DTOs from arrays', function (string $class, array $data, string $property, mixed $expected) { + $dto = valinorMapper()->map($class, $data); + expect($dto)->toBeInstanceOf($class) + ->and($dto->$property)->toBe($expected); +})->with([ + 'BisAddress' => [ + BisAddress::class, + ['type' => 1, 'street' => 'Katu 1', 'postCode' => '00100', 'city' => 'HELSINKI', 'source' => 0, 'version' => 1, 'language' => 'fi', 'registrationDate' => '2020-01-01'], + 'street', + 'Katu 1', + ], + 'BisCompanyName' => [ + BisCompanyName::class, + ['order' => 0, 'name' => 'Test Oy', 'source' => 1, 'version' => 1, 'language' => 'fi', 'registrationDate' => '2020-01-01'], + 'name', + 'Test Oy', + ], + 'BisCompanyForm' => [ + BisCompanyForm::class, + ['name' => 'Osakeyhtiö', 'type' => 'OY', 'source' => 0, 'version' => 1, 'language' => 'fi', 'registrationDate' => '2020-01-01'], + 'type', + 'OY', + ], + 'BisCompanyBusinessLine' => [ + BisCompanyBusinessLine::class, + ['order' => 0, 'name' => 'IT', 'source' => 2, 'version' => 1, 'language' => 'en', 'registrationDate' => '2020-01-01'], + 'name', + 'IT', + ], + 'BisCompanyLanguage' => [ + BisCompanyLanguage::class, + ['name' => 'Finnish', 'source' => 0, 'version' => 1, 'language' => 'fi', 'registrationDate' => '2020-01-01'], + 'language', + 'fi', + ], + 'BisCompanyRegisteredEntry' => [ + BisCompanyRegisteredEntry::class, + ['authority' => 2, 'register' => 1, 'status' => 2, 'description' => 'Registered', 'language' => 'en', 'registrationDate' => '2020-01-01'], + 'description', + 'Registered', + ], + 'BisCompanyLiquidation' => [ + BisCompanyLiquidation::class, + ['name' => 'Bankruptcy', 'type' => 'K', 'source' => 0, 'version' => 1, 'language' => 'fi', 'registrationDate' => '2020-01-01'], + 'name', + 'Bankruptcy', + ], + 'BisCompanyRegisteredOffice' => [ + BisCompanyRegisteredOffice::class, + ['order' => 0, 'name' => 'Helsinki', 'source' => 0, 'version' => 1, 'language' => 'fi', 'registrationDate' => '2020-01-01'], + 'name', + 'Helsinki', + ], + 'BisCompanyContactDetail' => [ + BisCompanyContactDetail::class, + ['value' => 'www.test.fi', 'type' => 'Website', 'source' => 0, 'version' => 1, 'language' => 'fi', 'registrationDate' => '2020-01-01'], + 'value', + 'www.test.fi', + ], + 'BisCompanyBusinessIdChange' => [ + BisCompanyBusinessIdChange::class, + ['description' => 'Changed', 'reason' => '1', 'oldBusinessId' => '1234567-8', 'newBusinessId' => '8765432-1', 'source' => 0, 'language' => 'fi', 'change' => 5], + 'oldBusinessId', + '1234567-8', + ], +]); diff --git a/tests/Unit/v1/Traits/HasAuthorityTest.php b/tests/Unit/v1/Traits/HasAuthorityTest.php new file mode 100644 index 0000000..e39938a --- /dev/null +++ b/tests/Unit/v1/Traits/HasAuthorityTest.php @@ -0,0 +1,30 @@ +getAuthorityString())->toBe('Tax Administration'); +}); + +it('returns Finnish Patent and Registration Office for authority 2', function () { + expect(makeAuthorityObject(2)->getAuthorityString())->toBe('Finnish Patent and Registration Office'); +}); + +it('returns Population Register for authority 3', function () { + expect(makeAuthorityObject(3)->getAuthorityString())->toBe('Population Register'); +}); + +it('returns unknown for unknown authority', function () { + expect(makeAuthorityObject(99)->getAuthorityString())->toBe('unknown:99'); +}); diff --git a/tests/Unit/v1/Traits/HasChangeTest.php b/tests/Unit/v1/Traits/HasChangeTest.php new file mode 100644 index 0000000..4e45f46 --- /dev/null +++ b/tests/Unit/v1/Traits/HasChangeTest.php @@ -0,0 +1,41 @@ +getChangeString())->toBe($expected); +})->with([ + [2, 'Business ID removal'], + [3, 'Combining of double IDs'], + [5, 'ID changed'], + [44, 'Fusion'], + [45, 'Operator continuing VAT activities'], + [46, 'Relation to predecessor'], + [47, 'Division'], + [48, 'Bankruptcy relationship'], + [49, 'Operations continued by a private trader'], + [57, 'Partial division'], +]); + +it('maps FUU string to Fusion', function () { + expect(makeChangeObject('FUU')->getChangeString())->toBe('Fusion'); +}); + +it('maps DIF string to Division', function () { + expect(makeChangeObject('DIF')->getChangeString())->toBe('Division'); +}); + +it('returns unknown for unrecognized change', function () { + expect(makeChangeObject(999)->getChangeString())->toBe('unknown:999'); +}); diff --git a/tests/Unit/v1/Traits/HasLanguageTest.php b/tests/Unit/v1/Traits/HasLanguageTest.php new file mode 100644 index 0000000..8d6b0f7 --- /dev/null +++ b/tests/Unit/v1/Traits/HasLanguageTest.php @@ -0,0 +1,30 @@ +getLanguageString())->toBe('finnish'); +}); + +it('returns english for en', function () { + expect(makeLanguageObject('en')->getLanguageString())->toBe('english'); +}); + +it('returns swedish for sv', function () { + expect(makeLanguageObject('sv')->getLanguageString())->toBe('swedish'); +}); + +it('returns unknown for unrecognized language', function () { + expect(makeLanguageObject('de')->getLanguageString())->toBe('unknown:de'); +}); diff --git a/tests/Unit/v1/Traits/HasRegisterTest.php b/tests/Unit/v1/Traits/HasRegisterTest.php new file mode 100644 index 0000000..2d90b92 --- /dev/null +++ b/tests/Unit/v1/Traits/HasRegisterTest.php @@ -0,0 +1,35 @@ +getRegisterString())->toBe($expected); +})->with([ + [1, 'Trade Register'], + [2, 'Register of Foundations'], + [3, 'Register of Associations'], + [4, 'Tax Administration'], + [5, 'Prepayment Register'], + [6, 'VAT Register'], + [7, 'Employer Register'], + [8, 'Register of bodies liable for tax on insurance premiums'], +]); + +it('returns unknown for unrecognized register', function () { + expect(makeRegisterObject(99)->getRegisterString())->toBe('unknown:99'); +}); + +it('returns unknown for null register', function () { + expect(makeRegisterObject(null)->getRegisterString())->toBe('unknown:'); +}); diff --git a/tests/Unit/v1/Traits/HasSourceTest.php b/tests/Unit/v1/Traits/HasSourceTest.php new file mode 100644 index 0000000..9ca83fc --- /dev/null +++ b/tests/Unit/v1/Traits/HasSourceTest.php @@ -0,0 +1,34 @@ +getSourceText())->toBe('common'); +}); + +it('returns Finnish Patent and Registration Office for source 1', function () { + expect(makeSourceObject(1)->getSourceText())->toBe('Finnish Patent and Registration Office'); +}); + +it('returns Tax Administration for source 2', function () { + expect(makeSourceObject(2)->getSourceText())->toBe('Tax Administration'); +}); + +it('returns Business Information System for source 3', function () { + expect(makeSourceObject(3)->getSourceText())->toBe('Business Information System'); +}); + +it('returns empty string for unknown source', function () { + expect(makeSourceObject(99)->getSourceText())->toBe(''); +}); diff --git a/tests/Unit/v3/ClientTest.php b/tests/Unit/v3/ClientTest.php new file mode 100644 index 0000000..848d8d7 --- /dev/null +++ b/tests/Unit/v3/ClientTest.php @@ -0,0 +1,73 @@ + HandlerStack::create($mock)]); + return new V3Client($client); +} + +it('searches companies successfully', function () { + $json = file_get_contents(__DIR__ . '/../../Fixtures/v3-search-response.json'); + $client = createV3ClientWithMock(new Response(200, [], $json)); + + $result = $client->searchCompanies(name: 'Example'); + + expect($result) + ->toBeInstanceOf(CompanySearchResult::class) + ->and($result->totalResults)->toBe(1) + ->and($result->companies)->toHaveCount(1) + ->and($result->companies[0]->businessId->value)->toBe('1639413-9') + ->and($result->companies[0]->names[0]->name)->toBe('Oy Example Ab') + ->and($result->companies[0]->tradeRegisterStatus)->toBe('2') + ->and($result->companies[0]->addresses[0]->street)->toBe('Testitie 1'); +}); + +it('throws V3ApiException on request failure for search', function () { + $client = createV3ClientWithMock(new Response(500, [], '{"message":"error"}')); + $client->searchCompanies(name: 'Test'); +})->throws(V3ApiException::class); + +it('retrieves description as plain text', function () { + $client = createV3ClientWithMock(new Response(200, [], 'Trade Register')); + $result = $client->getDescription('REK', 'en'); + + expect($result)->toBe('Trade Register'); +}); + +it('throws V3ApiException on description failure', function () { + $client = createV3ClientWithMock(new Response(400, [], '{"message":"bad request"}')); + $client->getDescription('INVALID'); +})->throws(V3ApiException::class); + +it('retrieves post codes', function () { + $json = (string) json_encode([ + ['postCode' => '00100', 'city' => 'HELSINKI', 'active' => true, 'languageCode' => '1', 'municipalityCode' => '091'], + ['postCode' => '00200', 'city' => 'HELSINKI', 'active' => true, 'languageCode' => '1', 'municipalityCode' => '091'], + ]); + $client = createV3ClientWithMock(new Response(200, [], $json)); + + $results = $client->getPostCodes('fi'); + + expect($results)->toHaveCount(2) + ->and($results[0])->toBeInstanceOf(PostCodeEntry::class) + ->and($results[0]->postCode)->toBe('00100') + ->and($results[0]->city)->toBe('HELSINKI') + ->and($results[1]->postCode)->toBe('00200'); +}); + +it('returns stream for all companies download', function () { + $client = createV3ClientWithMock(new Response(200, [], 'zip-content')); + $stream = $client->getAllCompanies(); + + expect($stream->getContents())->toBe('zip-content'); +}); diff --git a/tests/Unit/v3/Dto/CompanyTest.php b/tests/Unit/v3/Dto/CompanyTest.php new file mode 100644 index 0000000..830356f --- /dev/null +++ b/tests/Unit/v3/Dto/CompanyTest.php @@ -0,0 +1,53 @@ +allowSuperfluousKeys() + ->mapper(); + + $result = $mapper->map(CompanySearchResult::class, $json); + + expect($result->totalResults)->toBe(1) + ->and($result->companies)->toHaveCount(1); + + $company = $result->companies[0]; + + expect($company)->toBeInstanceOf(Company::class) + ->and($company->businessId->value)->toBe('1639413-9') + ->and($company->businessId->registrationDate)->toBe('2001-04-03') + ->and($company->euId)->not->toBeNull() + ->and($company->euId->value)->toBe('FIFOO123456') + ->and($company->names)->toHaveCount(1) + ->and($company->names[0]->name)->toBe('Oy Example Ab') + ->and($company->names[0]->type)->toBe('TOIM') + ->and($company->mainBusinessLine)->not->toBeNull() + ->and($company->mainBusinessLine->code)->toBe('62010') + ->and($company->mainBusinessLine->descriptions)->toHaveCount(1) + ->and($company->mainBusinessLine->descriptions[0]->description)->toBe('Computer programming activities') + ->and($company->website)->not->toBeNull() + ->and($company->website->url)->toBe('www.example.fi') + ->and($company->companyForms)->toHaveCount(1) + ->and($company->companyForms[0]->type)->toBe('OY') + ->and($company->companyForms[0]->descriptions)->toHaveCount(2) + ->and($company->registeredEntries)->toHaveCount(1) + ->and($company->registeredEntries[0]->register)->toBe('1') + ->and($company->registeredEntries[0]->authority)->toBe('2') + ->and($company->addresses)->toHaveCount(1) + ->and($company->addresses[0]->street)->toBe('Testitie 1') + ->and($company->addresses[0]->postOffices)->toHaveCount(1) + ->and($company->addresses[0]->postOffices[0]->city)->toBe('HELSINKI') + ->and($company->tradeRegisterStatus)->toBe('2') + ->and($company->status)->toBe('ACTIVE') + ->and($company->lastModified)->toBe('2023-06-15T10:30:00Z'); +});