You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
[JsonSchema] [OpenApi] New default-additional-properties option: decides how a schema that leaves additionalProperties unspecified is treated, across every component. null (default) keeps each component's own behavior — closed models for the JsonSchema component and OpenAPI 2, open models (unknown keys captured through the AdditionalAndPatternProperties trait) for OpenAPI 3 / 3.1; true treats unspecified additionalProperties as open everywhere; false treats it as closed everywhere, letting users keep closed models without editing their specification when migrating from older Jane versions where unspecified meant closed. An explicit additionalProperties value in the specification always wins over the option. The generated Symfony validation Collection constraint (allowExtraFields) follows the same resolution: while the option is unset it keeps its previous behavior (extra fields allowed for schemas without additionalProperties / patternProperties), and once the option is set — or the specification sets additionalProperties: false — it matches the generated model
[JsonSchema] [OpenApi] New external-ref-follow-redirects option: when enabled, fetching a remote reference follows HTTP redirects instead of aborting on a 3xx response. Disabled by default (an allowlisted host cannot bounce the fetch to an arbitrary host); the redirect target host is not re-checked against external-ref-allowed-hosts, so only enable it for remote documents you fully trust. Companion to the Reference::setFollowRedirects() runtime switch
[JsonSchemaRuntime] ReferenceResolveException (unfetchable / unparsable reference documents) and the new MalformedJsonException (malformed JSON response body in generated endpoints) now join the Jane error taxonomy: they implement the JaneExceptionInterface marker, which moved to Jane\Component\JsonSchemaRuntime\Exception\ so runtime exceptions can be user-facing without inverting the component dependency direction. The historical Jane\Component\JsonSchema\Exception\JaneExceptionInterface is kept as a deprecated extending alias, and generation commands render these failures as clean [ERROR] blocks per ADR 0002
[OpenApi3] [OpenApi31] GH#1036 Generated multipart/form-data request bodies now send binary (type: string + format: binary) properties with a filename in their Content-Disposition part header, and honor a concrete contentType declared through the media type's encoding object by emitting a Content-Type part header (wildcard and comma-separated contentType values are match constraints and stay ignored). The filename defaults to the property name and only applies when none can be derived from the value: a stream or resource backed by a real file keeps its actual file name (and the extension based Content-Type guessing) exactly as before, so string and in-memory payloads — which previously produced a filename-less part that servers like FastAPI or Spring reject as "not a file" — are the ones gaining the fallback. Plain scalar form fields are sent unchanged, and endpoints without binary properties or encoding entries generate byte-identical code
[OpenApi31] Support inheritance and polymorphism through the OpenAPI Discriminator Object: schemas are now parsed into a dedicated Jane\Component\OpenApi31\JsonSchema\Model\Schema (extending the generic JSON Schema 2020-12 model) that carries discriminator. A schema combining discriminator + mapping with allOf children generates a parent/child model hierarchy (extends, inherited properties) whose normalizer delegates normalization to the matching child and dispatches denormalization to the mapped child class; oneOf / anyOf unions with a discriminated property generate value-based denormalization conditions. Mapping-only by design: OAS 3.1 makes mapping the canonical way to bind discriminator values, so the OpenApi3 enum-values fallback is intentionally not ported
[OpenApi] GH#838 New x-namespace Specification Extension: declaring it on an operation moves its Endpoint (and inline request / response models) to a sub-namespace, declaring it on a schema moves its Model, Normalizer & Validator there. Artifacts without the attribute keep the flat layout
[OpenApi31] The internal 3.1 models now capture x-* specification extensions on the Operation object and on schemas, matching what OpenAPI 2.0 / 3.0 already preserved
[JsonSchema] New <Namespace>\Runtime\JsonObject runtime class shipped with every generated library, used to represent objects & maps in normalized payloads
[OpenApi] GH#832 New operation-namings option to customize client method names and endpoint class names through Jane\Component\OpenApiCommon\Naming\OperationNamingInterface instances. Providing an empty array (the default) keeps the built-in chain (operationId based naming with URL based fallback). As a side effect, an operation named exactly '0' is now consistently treated as a valid name by the naming chain instead of being skipped
[JsonSchema] GH#865 New enums-as-objects option to generate native PHP backed enums for schemas with an enum keyword (string / integer types)
[OpenApi3] GH#771 Report clean generation errors for non-body parameters using an unsupported schema.type (or no type/enum) instead of crashing
[JsonSchema] GH#752 Validate format: date / format: date-time string properties when the validation option is enabled (Symfony Date / DateTime constraints, honoring the full-date-format, date-format and date-input-format options)
[OpenApi] GH#844 The generated UnexpectedStatusCodeException now stores the PSR-7 response it was built from (new optional third constructor argument) and exposes it through getResponse(): ?\Psr\Http\Message\ResponseInterface; a new generated WithResponseInterface marker (single getResponse(): ?\Psr\Http\Message\ResponseInterface method) is implemented by every response-carrying generated exception (UnexpectedStatusCodeException, status-level & per-operation exceptions), so consumers can check $e instanceof WithResponseInterface instead of method_exists($e, 'getResponse'). BadResponseException now delegates the response storage to its parent
[JsonSchema] [OpenApi] GH#588 New allowed-local-ref-roots option: declare additional directory roots that local $refs may resolve into, unlocking split-spec layouts where referenced documents live outside the referencing document's directory (e.g. a specification in doc/api/openapi.yaml referencing ../schema/institution.yaml). Default behavior is unchanged: without the option, a local reference may still only resolve within the referencing document's directory. The rejection message now names the offending path and points to this new option
Changed
BC-breaking [OpenApi] The OpenAPI 2.0 / 3.0 / 3.1 document models (src/Component/OpenApi{2,3,31}/JsonSchema/Model/, e.g. OpenApi, Components, Responses) no longer extend \ArrayObject: like the models carrying additionalProperties / patternProperties (GH#867), they now implement a per-library <Namespace>\Runtime\AdditionalPropertiesInterface backed by the <Namespace>\Runtime\AdditionalAndPatternProperties trait. Array access, iteration (foreach), count(), getArrayCopy() / toArray() and json_encode() keep working (empty maps now encode as {} instead of breaking); constructing these models with an array argument is gone — populate them through their setters (or offsetSet()) instead. Normalizer normalize() signatures are unchanged
BC-breaking [JsonSchema] GH#867 Models carrying additionalProperties / patternProperties no longer extend \ArrayObject: they now use a per-library <Namespace>\Runtime\AdditionalAndPatternProperties trait paired with an <Namespace>\Runtime\AdditionalPropertiesInterface interface, so iteration (foreach), count(), toArray(), getArrayCopy() and json_encode finally expose every value — defined properties (through their accessors) as well as additional / pattern-matched ones — instead of silently skipping defined properties. Migration table:
Before
After
$model instanceof \ArrayObject
$model instanceof AdditionalPropertiesInterface
$model->getArrayCopy() (extras only)
$model->toArray() or keep getArrayCopy() (now complete)
(array) $model / $model->getArrayCopy() for extras
Note the widened output: `json_encode($model)` now encodes the full object (defined + additional values) instead of extras only; empty models encode as `{}`. Pure-map models (no defined properties) are affected by the same type break although their iteration behavior is unchanged
[OpenApi] GH#789 The host / base path plugins built from the specification (AddHostPlugin, AddPathPlugin) are now also applied around a caller-provided PSR-18 client in the generated Client::create(): your client may now be wrapped in a PluginClient carrying the specification's server URL, so server URLs containing a path (e.g. https://server.localhost/api/v3) work with custom clients. Generated clients whose specification declares a server URL accept a fourth bool $applyServerPlugins = true argument to opt out and keep using your client as-is.
[OpenApi] GH#752 Denormalizing an invalid date / date-time value now throws a dedicated <Namespace>\Runtime\Normalizer\InvalidDateException with the offending value and expected format, instead of failing with a raw TypeError on the model setter. A latent fatal (setTime() called on false) in multi-typed date properties was fixed at the same time
[JsonSchema] Fetching a reference document over HTTP(S) no longer follows HTTP redirects: an allowlisted host could previously answer with a 302 and have Jane fetch the target of the redirect from a non allowlisted host. Redirect responses (3xx) now abort the resolution with a ReferenceResolveException pointing at the offending document
Fixed
[JsonSchema] Building Jane::build() with a minimal options array no longer crashes on the missing strict key: it now defaults to true, matching the documented configuration default
[JsonSchema] SimpleTypeGuesser now actually excludes the configured formats (e.g. string + format: date-time): the exclusion looked the schema type up as a value of the type => formats map, making the branch dead code (generated output is unchanged since DateTimeGuesser claims such schemas earlier in the chain)
[JsonSchemaRuntime] Resolving a reference over an unreadable document (missing file, network failure) now throws the new Jane\Component\JsonSchemaRuntime\Exception\ReferenceResolveException (extends \RuntimeException) instead of crashing with a TypeError; content that is neither valid JSON nor valid YAML throws the same exception, and valid JSON roots evaluating falsy ([], 0, "0", null) are no longer misrouted through the YAML parser (scalar roots previously crashed on doResolve()'s return type as well)
[OpenApiCommon] Reading the OpenAPI registry options (whitelistedPaths, customQueryResolver, throwUnexpectedStatusCode, generateErrorExceptions, openApiClass) before the matching setter runs no longer fatals with an uninitialized typed property: they now carry defaults matching the generate command's fallbacks
[OpenApi2] The shipped ReferenceNormalizer implements the current NormalizerInterface ($context parameter on supportsNormalization(), getSupportedTypes()): loading it fataled with symfony/serializer >= 6.1
[OpenApi] Path parameter values are now URL-encoded (rawurlencode) when substituted into the request URI by the generated getUri(): values containing reserved characters (/, ?, #, spaces, ...) previously produced invalid or semantically different URLs, consistently for OpenAPI 2 / 3 / 3.1
[OpenApi] Generated endpoints returning a raw json_decode() of the response body no longer silently return null on malformed JSON: the decode now uses JSON_THROW_ON_ERROR and a \JsonException is converted into the new dedicated Jane\Component\JsonSchemaRuntime\Exception\MalformedJsonException (Malformed JSON response body., chained to the original exception, user-facing error per ADR 0002) instead of a bare RuntimeException — which it still extends, so existing catch (\RuntimeException) blocks keep working; consistently for OpenAPI 2 / 3 / 3.1
[OpenApi] Generated endpoints sniff response content types with stripos() instead of mb_strpos(): the mbstring extension was never required, so generated clients crashed on hosts without it (content types are ASCII, the haystack is lowercased)
[JsonSchema] GH#1047 Doc blocks for anyOf / oneOf unions no longer repeat identical type hints (e.g. @var string|string|string for a union of single-value string enum branches, the pattern FastAPI emits for Literal unions): the branch hints are deduplicated before joining, generating @var string (or string|null) instead. Purely a doc-block change — native type hints and generated behavior are untouched
[OpenApi] GH#1051 Path parameters constrained with a regex in the path template (e.g. /cluster/{id:.+}) no longer leak the constraint into generated PHP variable names (string $id:.+ — a syntax error): the variable name is now sanitized (string $id) in endpoint constructors, client methods and docblocks, consistently for OpenAPI 2 / 3 / 3.1. URL building still replaces the raw {id:.+} placeholder
[JsonSchema] GH#1051 Schemas named parent or self no longer generate reserved PHP class names (class Parent is a fatal error): they are now prefixed like other reserved words (_Parent, _Self), consistently wherever class names are derived (models, endpoints, operation naming)
[JsonSchema] GH#1038 Properties declared as anyOf / oneOf with a date branch (e.g. anyOf: [<date-time string>, null]) no longer pass strings that match no branch raw into the ?\DateTime typed setter (a TypeError at runtime): an empty string resolves to null when the union explicitly admits null (a deliberate leniency — an empty string is the common wire encoding of an absent date), and any other non-parsing string is reported with the same InvalidDateException the plain date property path throws since GH#764
[JsonSchema] GH#1034toArray(), json_encode(), count(), iteration and offsetExists() on generated open models no longer throw a TypeError when a defined property with a non-nullable getter was never initialized (e.g. denormalized from a payload missing that property): the AdditionalAndPatternProperties runtime trait now reads the backing property directly instead of calling the typed getter before the initialization check. Properties carrying a generated default value are still exposed unchanged
[OpenApi] GH#823 Operations resolving to the same generated name no longer produce broken clients (duplicated client methods / endpoint classes): colliding names are disambiguated with an incrementing suffix (getApiUser, getApiUser2, ...), consistently for client methods and endpoint classes. This notably occurred when a specification contains both a singular and a plural path (e.g. GET /api/user and GET /api/users) whose response is not an array
[OpenApi] GH#833 A 200 response declaring an empty content map (content: {}) no longer aborts generation with "Call to a member function getSchema() on null"; it is now treated as a body-less response
[OpenApi] GH#763 Generate models referenced by the default response when using whitelisted-paths (the default response is not part of the iterated status codes, so its models were filtered out)
[JsonSchema] GH#585 Reference normalizers of models from other mapped schemas (transitively) used by a schema's models in its generated JaneObjectNormalizer, so multi-namespace mappings no longer fail at runtime with "no supporting normalizer found"
[JsonSchema] GH#700GH#680 Empty objects and maps (additionalProperties, patternProperties, nested models) are now serialized as JSON objects ({}) instead of arrays ([]), and normalization/denormalization are symmetric. Upgrade note: map/object values in normalized payloads are now JsonObject instances instead of plain arrays or \ArrayObject; use ->toArray() / (array) casts when post-processing raw payloads. Nullable properties explicitly set to null normalize to null (or are omitted with skip-null-values) instead of emitting an empty collection
[OpenApi] GH#826 When using whitelisted-paths, schemas that cannot be guessed no longer abort generation if they are not needed by any whitelisted operation (they are simply not generated); guessing errors in models used by whitelisted operations still fail generation
[OpenApi] GH#680 Empty object JSON request bodies are now sent on the wire as {} instead of []: when an operation's JSON request body resolves to a generated model class, the endpoint serializes it through the new per-library <Namespace>\Runtime\Client\JsonPayload helper. Only generated endpoint code changes (mechanical regeneration); direct consumers of normalizers' normalize() are not affected
[OpenApi] GH#963 Support JSON content types with parameters (e.g. application/json;schema=...) when generating response transformations and operation/model relations
[OpenApi3] GH#310 Respect nullable: true declared inside an allOf member (the canonical OpenAPI 3.0 pattern for making a $ref'd schema nullable), generating null-safe models, normalizers and denormalizers
[OpenApi] GH#963 Generate models for allOf schemas whose members omit an explicit type: object
[OpenApi31] GH#848 Support nullable dates and datetimes expressed as type: ["string", "null"] with a format: date / date-time (OAS 3.1 style), generating the same null-safe normalization code as OpenAPI 3.0's nullable: true
[OpenApi31] GH#946 Generate response models and correct transformResponseBody return types for inline response schemas (array responses are typed as Model[] again)
[OpenApi31] GH#1007 A schema without an additionalProperties keyword is now treated as open (the JSON Schema 2020-12 default), matching OpenApi3: unknown JSON keys are preserved through denormalize/normalize instead of being silently dropped. Upgrade note: generated 3.1 models for such schemas now use the <Namespace>\Runtime\AdditionalAndPatternProperties trait with the <Namespace>\Runtime\AdditionalPropertiesInterface interface (see GH#867); declare additionalProperties: false to keep a closed schema and a plain model class
[OpenApi31] GH#1006 A property schema using $ref with sibling keys (e.g. type: object next to the $ref, allowed by JSON Schema 2020-12) now resolves to the referenced model again: typed getter/setter and recursive (de)normalization instead of an untyped mixed property whose value was passed through raw. Schemas declaring their own properties or allOf next to a $ref keep their inline handling
[OpenApi31] Keep endpoint names plural for operations returning an array response
[OpenApi] Support union types (e.g. type: ["array", "null"]) when detecting array schemas
[OpenApi3] GH#803 Fix fatal error when a non-required query/header parameter references a schema defining a default (the default is now applied to the generated options resolver)
[Jane] Wrap unexpected generation-phase errors in a clean GenerationFailedException instead of letting raw PHP errors reach the console
[OpenApi] GH#831 Take PHP reserved words into account when generating endpoint class names: an operation whose operationId is a reserved word (e.g. list) now generates a valid Endpoint\_List class instead of the unparseable class List. Client method names keep the original operationId (reserved words are valid PHP method names)
[JsonSchema] Object schemas declaring only patternProperties (no properties) are matched by the PatternPropertiesGuesser again: its schema check had gone dead when model getters moved from \ArrayObject hints to iterable hints, so such schemas silently fell back to a generic type and generated wrong property docblocks / types for affected JSON-Schema inputs (e.g. string|mixed instead of the pattern union like string|object|null[], with no patternProperties handling in the normalizers)