If == The keywords `if`, `then` and `else` can be used to conditionally combine multiple subschemas. Conditional compositions can be used on property level and on object level. .. code-block:: json { "$id": "example", "type": "object", "properties": { "example": { "type": "number", "if": { "multipleOf": 5 }, "then": { "minimum": 100 }, "else": { "maximum": 100 } } } } Valid values are eg. 100, 105, 99. Invalid values are eg. 50, 101 or any non numeric values. Generated interface: .. code-block:: php public function setExample(float $example): static; public function getExample(): ?float; Possible exception (in this case 50 was provided so the if condition succeeds but the then branch failed): .. code-block:: none Invalid value for example declined by conditional composition constraint - Condition: Valid - Conditional branch failed: * Value for example must not be smaller than 100 Another example exception with 101 as value for the property: .. code-block:: none Invalid value for example declined by conditional composition constraint - Condition: Failed * Value for example must be a multiple of 5 - Conditional branch failed: * Value for example must not be larger than 100 The thrown exception will be a *PHPModelGenerator\\Exception\\ComposedValue\\ConditionalException* which provides the following methods to get further error details: .. code-block:: php // get the exception which triggered the condition to fail // if error collection is enabled an ErrorRegistryException will be returned public function getIfException(): ?Exception // get the exception which triggered the conditional branch to fail // if error collection is enabled an ErrorRegistryException will be returned public function getThenException(): ?Exception public function getElseException(): ?Exception // get the name of the property which failed public function getPropertyName(): string // get the value provided to the property public function getProvidedValue() An object level composition will result in an object which contains all properties contained in the three possible blocks of the condition. .. code-block:: json { "$id": "customer", "type": "object", "properties": { "country": { "enum": ["United States of America", "Canada"] } }, "if": { "type": "object", "properties": { "country": { "const": "United States of America" } } }, "then": { "type": "object", "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } } }, "else": { "type": "object", "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } } } } Generated interface: .. code-block:: php public function setCountry(string $country): static; public function getCountry(): ?string; public function setPostalCode(string $country): static; public function getPostalCode(): ?string; When the ``then`` and ``else`` branches define the same property with **different types**, the generator produces a union type hint — consistent with the behaviour of ``anyOf``/``oneOf``: .. code-block:: json { "$id": "example", "type": "object", "if": { "properties": { "name": { "const": "Alice" } } }, "then": { "properties": { "age": { "type": "integer" } } }, "else": { "properties": { "age": { "type": "string" } } } } Generated interface: .. code-block:: php public function setAge(int | string | null $age): static; public function getAge(): int | string | null; When only a ``then`` block is present (no ``else``), the branch may not apply at runtime, so the property is always nullable: .. code-block:: php public function setAge(?int $age): static; public function getAge(): ?int; .. note:: Any of the three branches (``if``, ``then``, ``else``) can be the boolean literal ``true`` or ``false``. The generator resolves these statically at generation time: - ``if: false`` — condition never matches; ``else`` (if present) is applied unconditionally, ``then`` is ignored. - ``if: true`` — condition always matches; ``then`` (if present) is applied unconditionally, ``else`` is ignored. - ``if: false, else: false`` or ``if: true, then: false`` — the composition is always unsatisfiable; providing any value raises a ``ConditionalException`` at runtime. The generator also emits a warning at generation time. - ``then: false`` / ``else: false`` (with a real schema for ``if``) — when the relevant branch is entered, the value would always be invalid; the generator throws a ``SchemaException`` at generation time. - ``then: true`` / ``else: true`` — when the relevant branch is entered, any value is accepted; treated as absent (no additional constraint). .. hint:: The union-widening and nullability rules for ``if``/``then``/``else`` follow the same logic as ``anyOf``/``oneOf``. See `Cross-typed compositions `__ for the full explanation. .. note:: For object-level ``if``/``then``/``else`` compositions, when a property appears in the ``required`` array of **both** ``then`` and ``else``, the generator promotes that property to non-nullable. Exactly one of the two branches applies at runtime, and both guarantee the property's presence. If there is no ``else`` block, the property is never promoted — the schema is silent when the condition fails, so the property may be absent. See `Cross-typed compositions `__ for the full promotion rules. .. note:: Properties in object-level ``then`` or ``else`` branches may carry a ``"default"`` value. The generator applies the branch default only when the relevant branch is active — the ``then`` default applies when the ``if`` condition is satisfied, and the ``else`` default applies when it is not. A user-supplied value always overrides the branch default. Branch defaults are **not** included in ``getRawModelDataInput()``. When a ``then`` or ``else`` branch default conflicts with a root ``properties`` default or a ``patternProperties`` default for the same property, the generator throws a ``SchemaException`` at generation time. See `Default values <../generic/default.html#branch-defaults-in-compositions>`__ for the full explanation.