Skip to content

v6.0.0#137

Merged
usernane merged 37 commits into
mainfrom
dev
Jun 1, 2026
Merged

v6.0.0#137
usernane merged 37 commits into
mainfrom
dev

Conversation

@usernane

@usernane usernane commented Jun 1, 2026

Copy link
Copy Markdown
Member

Release v6.0.0

Breaking Changes

  • Validation errors now return HTTP 422 instead of 404
  • Validation response format changed: more-info contains {"errors": {"field": "message"}} instead of {"invalid": [...]} / {"missing": [...]}
  • WebServicesManager deprecated — use RequestProcessor instead

New Features

  • RequestProcessor — process a single service without a manager
  • Content negotiation#[Produces] attribute + MediaType constants + 406 support
  • Cross-field validationvalidate() method + #[Validate] attribute
  • Reusable parameter setsParameterSet interface + #[UseParameterSet] attribute
  • Allowed-values and patternParamOption::ALLOWED_VALUES and ParamOption::PATTERN
  • Custom error messagesParamOption::MESSAGE per parameter
  • isAuthorized() string return — return denial reason as string
  • #[RequiresAuth] checks SecurityContext — no more boilerplate override
  • #[PatchMapping] — PATCH method support via attributes
  • ServiceTestCase + TestResponse — new fluent testing API
  • ErrorResponse — standalone error response helper
  • OpenAPIGenerator — standalone OpenAPI spec generation

Bug Fixes

Refactoring (ADR-0005)

  • PUT/PATCH body parsing moved to Request class
  • ErrorResponse extracted from WebServicesManager
  • OpenAPIGenerator extracted from WebServicesManager
  • RequestProcessor created as the primary processing entry point
  • WebServicesManager deprecated with migration guide
  • OpenAPIObject base class reduces duplication in OpenAPI objects

Infrastructure

  • Unified PHPUnit config (dropped PHPUnit 9 support)
  • CI workflows updated to WebFiori/workflows@v1.2.5
  • SonarCloud duplication exclusions for tests/examples
  • actions/checkout@v6

Test Coverage

588 tests, 1735 assertions across PHP 8.1–8.5

Migration Guide

See ADR-0007 for validation error changes.
See WebServicesManager class docblock for RequestProcessor migration.

Ibrahim BinAlshikh and others added 30 commits June 1, 2026 11:36
applyJsonBasicFilter compared ParamType ('email'/'url') against PHP
gettype ('string'), which never matched. EMAIL and URL values were
set to null and flagged as invalid.

Fix: treat EMAIL and URL as string types in the JSON filter matching
condition and route them through cleanJsonStr for proper validation.
fix(#112): EMAIL param injection returns null for JSON body requests
…eter

- Add ParamOption::ALLOWED_VALUES and ParamOption::PATTERN constants
- Add allowedValues/pattern properties, getters, setters to RequestParameter
- Add allowedValues/pattern params to #[RequestParam] attribute
- Wire attribute properties in WebService::configureParametersFromMethod()
- Add checkAllowedAndPattern() in APIFilter for both form-encoded and JSON paths
- Generate OpenAPI enum/pattern in Schema::fromRequestParameter()
- 34 new tests covering all paths: unit, filter, JSON, attributes, OpenAPI, edge cases
…eter

- Add ParamOption::ALLOWED_VALUES and ParamOption::PATTERN constants
- Add allowedValues/pattern properties, getters, setters to RequestParameter
- Add allowedValues/pattern params to #[RequestParam] attribute
- Wire attribute properties in WebService::configureParametersFromMethod()
- Add checkAllowedAndPattern() in APIFilter for both form-encoded and JSON paths
- Generate OpenAPI enum/pattern in Schema::fromRequestParameter()
- 34 new tests covering all paths: unit, filter, JSON, attributes, OpenAPI, edge cases
feat(#114): add allowed-values and pattern validation to RequestParameter
- Change WebService::isAuthorized() return type from bool to string|bool
- Update WebServicesManager::isAuth() to capture string result
- Update notAuth() to accept optional custom message parameter
- Existing bool returns remain fully backward compatible
- 4 new tests covering string denial, bool denial, true pass, multiple reasons
…ason

feat(#111): allow isAuthorized() to return string as denial reason
- Add Request::parsePutPatchBody() for url-encoded and multipart bodies
- Called automatically from Request::createFromGlobals() for PUT/PATCH
- Remove populatePutData() calls from WebServicesManager
- Deprecate WebServicesManager::populatePutData() as no-op stub
- 7 new tests for url-encoded, multipart, file uploads, edge cases
- Step 1 of 5 in ADR-0005 (RequestProcessor refactor)
…to-request

refactor(#118): move PUT/PATCH body parsing into Request class
- Create ErrorResponse class with static methods for all error types
- Each method returns ['json' => Json, 'code' => int] for flexibility
- Deprecate WebServicesManager error methods, delegate to ErrorResponse
- 12 new unit tests covering all error response types
- Step 2 of 5 in ADR-0005 (RequestProcessor refactor)
…onse

refactor(#119): extract ErrorResponse helper class
- Create standalone OpenAPI\OpenAPIGenerator class
- Accepts array of WebService instances, description, version, basePath
- Deprecate WebServicesManager::toOpenAPI(), delegate to generator
- Add example in examples/04-advanced/02-openapi-docs/
- Update README with ErrorResponse and OpenAPIGenerator in key classes
- 6 new tests covering single/multiple services, basePath, empty, legacy
- Step 3 of 5 in ADR-0005 (RequestProcessor refactor)
…nerator

refactor(#120): extract OpenAPIGenerator from WebServicesManager
- Add RequestProcessor for standalone service processing without a manager
- Accepts WebService + optional Request + optional output stream
- Handles full pipeline: content type, method check, params, auth, invocation
- Internally uses WebServicesManager (single-service auto-select)
- Add example in examples/04-advanced/04-request-processor/
- 6 new tests covering GET, POST, auth denial, method not allowed, content type
- Step 4 of 5 in ADR-0005 (RequestProcessor refactor)
…cessor

feat(#121): create RequestProcessor class
- Add @deprecated to class docblock with migration guide to RequestProcessor
- Add @deprecated to process() and sendResponse() methods
- Update README Quick Start to show RequestProcessor as primary approach
- All existing tests pass unchanged (full backward compatibility)
- Step 5 of 5 in ADR-0005 (RequestProcessor refactor) — COMPLETE
…ices-manager

deprecate(#122): mark WebServicesManager as deprecated
- Create ParameterSet interface with getParameters() method
- Add #[UseParameterSet] attribute for declarative usage on methods
- Add WebService::addParameterSet() for traditional usage
- Update getMethodParameters() to handle positional injection from sets
- Sets are processed before #[RequestParam], enabling combined usage
- Add example in examples/01-core/07-reusable-parameter-sets/
- Update README with parameter sets documentation
- 12 new tests covering interface, attribute, validation, edge cases
- Create OpenAPIObject with shared description property and addIfNotNull/addIfTruthy helpers
- HeaderObj and ParameterObj extend OpenAPIObject, removing duplicate description property/methods
- Refactor toJSON() methods to use helpers instead of repeated if-null-add blocks
- Reduces ~60 lines of duplicated code
feat(#116): add reusable parameter sets with ParameterSet interface
… directly

- Method-level #[RequiresAuth] now checks SecurityContext instead of isAuthorized()
- Class-level #[RequiresAuth] with no method annotations checks SecurityContext
- checkMethodAuthorization() falls back to class-level check before isAuthorized()
- Add hasClassLevelRequiresAuth() helper method
- Services without auth attributes still use isAuthorized() (unchanged)
- 8 new tests covering method-level, class-level, AllowAnonymous override, fallback
…-context

feat(#117): #[RequiresAuth] checks SecurityContext::isAuthenticated() directly
- Add boolean type check before urldecode in filter() method
- Add boolean early return before strip_tags in applyBasicFilterOnly()
- Native false was being cast to empty string by urldecode/strip_tags
- 2 new regression tests for native true/false
…ting

- Create WebFiori\Http\Test\ServiceTestCase with fluent API
- Create WebFiori\Http\Test\TestResponse with assertion methods
- Deprecate APITestCase, switch its internals to tempnam (no more hardcoded file)
- ServiceTestCase uses RequestProcessor directly — no manager needed
- Convenience methods: get(), post(), put(), patch(), delete()
- TestResponse assertions: assertOk(), assertStatus(), assertJsonEquals(), etc.
- 12 new tests demonstrating the new testing API
Ibrahim BinAlshikh and others added 6 commits June 1, 2026 18:59
- Add overridable validate(array $inputs): array on WebService (service-wide)
- Add #[Validate('methodName')] attribute for method-specific validation
- Both run: service-wide first, then method-specific, errors merged
- Returns 422 with error details if validation fails
- Missing validator method throws InvalidArgumentException (caught as 500)
- Uses reflection to invoke private validator methods
- Update README with cross-field validation documentation
- 10 new tests covering all paths
feat(#115): add cross-field validation with #[Validate] attribute
…ages

BREAKING CHANGE: Validation error responses now return HTTP 422 instead of 404.

- Change ErrorResponse::invalidParams() and missingParams() from 404 to 422
- Add ParamOption::MESSAGE for custom per-parameter error messages
- Add RequestParameter::getMessage()/setMessage()
- Add 'message' param to #[RequestParam] attribute
- Response format: {message, type, http-code: 422, more-info: {errors: {field: msg}}}
- If no custom message: auto-generates 'Invalid value for parameter X' or 'Required parameter X is missing'
- WebServicesManager now passes RequestParameter objects to ErrorResponse
- Update existing tests for new 422 status code and response format
- 9 new tests covering all message scenarios
…e constants

- Add #[Produces] attribute to declare supported response content types
- Add MediaType class with constants (JSON, XML, HTML, PLAIN, etc.)
- Add WebService::getNegotiatedContentType() for methods to read the result
- Add ErrorResponse::notAcceptable() for 406 responses
- Negotiation runs after auth, before validation in processWithAutoHandling()
- No #[Produces] = no negotiation (100% backward compatible)
- Accept: */* or missing = server's first preference
- No match = 406 Not Acceptable with supported types listed
- Update README with content negotiation documentation
- 14 new tests covering all negotiation paths
…-messages

feat!(#113): change validation errors to 422 and add custom error messages
feat: add content negotiation with #[Produces] attribute
@codecov

codecov Bot commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.91304% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.79%. Comparing base (b9ce95e) to head (2b9a2e3).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
WebFiori/Http/WebService.php 98.31% 2 Missing ⚠️
WebFiori/Http/Request.php 97.82% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #137      +/-   ##
============================================
+ Coverage     92.34%   93.79%   +1.45%     
- Complexity     1302     1347      +45     
============================================
  Files            39       39              
  Lines          3147     3273     +126     
============================================
+ Hits           2906     3070     +164     
+ Misses          241      203      -38     
Flag Coverage Δ
php-8.1 93.79% <98.91%> (+1.68%) ⬆️
php-8.2 93.67% <98.91%> (+1.49%) ⬆️
php-8.3 93.67% <98.91%> (+1.49%) ⬆️
php-8.4 93.67% <98.91%> (+1.49%) ⬆️
php-8.5 93.67% <98.91%> (+1.49%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

PHPUnit 12 no longer passes return values as arguments to dependent
tests. Refactored 7 test methods to be self-contained instead of
relying on @Depends parameter injection.
@sonarqubecloud

sonarqubecloud Bot commented Jun 1, 2026

Copy link
Copy Markdown

@sonarqubecloud

sonarqubecloud Bot commented Jun 1, 2026

Copy link
Copy Markdown

@usernane usernane merged commit 6270fa0 into main Jun 1, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant