Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2109f10
Introduce Draft-based architecture (Phase 1)
Mar 26, 2026
116291f
Implement Phase 2 & 3: eliminate PropertyMetaDataCollection, refine D…
Mar 27, 2026
e8053b4
docs
Mar 27, 2026
3bec251
Implement Phase 4: migrate scalar/array/universal keyword validators …
Mar 27, 2026
997b639
Implement Phase 5: eliminate MultiTypeProcessor
Mar 27, 2026
f8be759
Implement Phase 6: migrate object keyword processing to Draft modifie…
Mar 28, 2026
f104e77
Implement Phase 7: composition validator factories; eliminate Compose…
Mar 29, 2026
ab9ae62
Implement Phase 8: eliminate all legacy processor classes; introduce …
Mar 30, 2026
cb1babc
cleanup
Mar 30, 2026
0d6e126
Merge remote-tracking branch 'origin/master' into drafts
Mar 30, 2026
a742e56
Merge remote-tracking branch 'refs/remotes/origin/drafts' into attrib…
wol-soft Apr 2, 2026
383e15c
Implement attributes
wol-soft Apr 2, 2026
ac60b0f
Implement attributes
wol-soft Apr 2, 2026
6ad41c4
attribute tests
Apr 3, 2026
5ae2a81
docs
Apr 3, 2026
2f9538a
make JSON_POINTER and SCHEMA_NAME always-enabled attributes to be abl…
Apr 7, 2026
cf79340
Fix serialization to use original JSON Schema property names as outpu…
wol-soft Apr 8, 2026
cf90b44
Replace underscore naming convention with #[Internal] attribute for g…
wol-soft Apr 8, 2026
ef5550c
CI
wol-soft Apr 8, 2026
72e9e53
Revert "CI"
wol-soft Apr 8, 2026
b7180bb
Index Type validators by key; add draft extensibility, composition, a…
wol-soft Apr 9, 2026
081401c
Phase 1: deferred untyped-property filter compatibility check in Filt…
wol-soft Apr 9, 2026
f8cc527
Phase 2: simplify filter compatibility check to zero-overlap rule
wol-soft Apr 10, 2026
ebb8d9b
Phase 3: allow 'mixed' in filter acceptedTypes; reject mixed+other co…
wol-soft Apr 10, 2026
596e2da
Phase 4a: filters silently skip non-matching types instead of throwing
wol-soft Apr 10, 2026
d0c1bed
Phase 4b: replace getAcceptedTypes() with reflection on callable's fi…
wol-soft Apr 10, 2026
34f7757
Phases 4b+4c: reflection-based accepted types and deferred output type
wol-soft Apr 13, 2026
2c2675d
Phase 4d+5: tests, SingleFileProvider, and filter doc/exception cleanup
wol-soft Apr 17, 2026
2728773
cleanup
wol-soft Apr 17, 2026
385143b
additional test cases
wol-soft Apr 17, 2026
33e8a84
additional test cases
wol-soft Apr 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@
"Bash(gh issue:*)",
"WebFetch(domain:github.com)",
"Bash(find:*)",
"Bash(cd C:/git/php-json-schema-model-generator && /c/PHP84/php.exe ./vendor/bin/phpunit 2>&1)",
"Bash(find C:\\\\git\\\\php-json-schema-model-generator:*)",
"Bash(tail:*)",
"Bash(cd:*)",
"WebFetch(domain:api.github.com)",
"Bash(head:*)",
"Bash(grep:*)",
"WebFetch(domain:wiki.php.net)",
"Bash(cd /c/git/php-json-schema-model-generator && ./vendor/bin/phpunit 2>&1)",
"Bash(./vendor/bin/phpunit:*)",
"Bash(php:*)",
"Bash(cat:*)",
Expand All @@ -28,10 +25,18 @@
"Bash(gh api:*)",
"Bash(git restore:*)",
"Bash(git stash:*)",
"Bash(git status:*)",
"Bash(composer show:*)",
"Bash(php -r \":*)",
"Bash(gh pr:*)",
"Bash(xargs wc:*)"
"Bash(xargs wc:*)",
"Bash(tee /tmp/phpunit-output.txt)",
"Read(//tmp/**)",
"WebFetch(domain:json-schema.org)",
"WebFetch(domain:datatracker.ietf.org)",
"Bash(for f:*)",
"Bash(do)",
"Bash(done)"
]
}
}
211 changes: 0 additions & 211 deletions .claude/topics/issue-101/analysis.md

This file was deleted.

78 changes: 73 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ user to resolve it.

Rules:

- Ask all foreseeable clarifying questions upfront in a single batch before work begins.
- When there are multiple clarifying questions to ask, ask them **one at a time**, in order of
dependency (earlier answers may resolve later questions). Wait for the answer before asking the
next question. This allows the user to discuss each point in depth without being overwhelmed by
a wall of questions.
- If new ambiguities emerge during execution that were not foreseeable upfront, pause and ask
follow-up questions before proceeding past that decision point.
- For high-stakes decisions (architecture, scope, data model, API shape, behaviour changes) always
Expand All @@ -19,6 +22,9 @@ Rules:
visible so the user can correct it.
- There must be no silent interpretation or interpolation of under-specified tasks. If something is
unclear, ask. Do not guess and proceed.
- For multi-phase implementations, **never start the next phase without an explicit go-ahead from
the user**. After completing a phase, summarise what was done and wait for confirmation before
proceeding.

When generating a new CLAUDE.md for a repository, include this clarification policy verbatim as a
preamble before all other content.
Expand Down Expand Up @@ -48,6 +54,20 @@ composer update

Tests write generated PHP classes to `sys_get_temp_dir()/PHPModelGeneratorTest/Models/` and dump failed classes to `./failed-classes/` (auto-cleaned on bootstrap).

### Running the full test suite

When running the full test suite, always save output to a file so the complete
output is available for analysis without re-running. Use `--display-warnings` to capture warning
details and `--no-coverage` to skip slow coverage collection:

```bash
php -d memory_limit=128M ./vendor/bin/phpunit --no-coverage --display-warnings 2>&1 | sed 's/\x1b\[[0-9;]*m//g' > /tmp/phpunit-output.txt; tail -5 /tmp/phpunit-output.txt
```

Then analyse with: `grep -E "FAIL|ERROR|WARN|Tests:" /tmp/phpunit-output.txt`

After analysis is complete, delete the file: `rm /tmp/phpunit-output.txt`

## Architecture

This library generates PHP model classes from JSON Schema files. The process is a 4-step pipeline:
Expand All @@ -72,15 +92,25 @@ This library generates PHP model classes from JSON Schema files. The process is
### Schema Processing

`SchemaProcessor` (`src/SchemaProcessor/SchemaProcessor.php`) orchestrates property parsing:
- Uses `PropertyProcessorFactory` to instantiate the correct processor by JSON type (String, Integer, Number, Boolean, Array, Object, Null, Const, Any, Reference)
- Convention: processor class name is `PHPModelGenerator\PropertyProcessor\Property\{Type}Processor`
- Uses `PropertyFactory` (`src/PropertyProcessor/PropertyFactory.php`) to create and configure each property
- `PropertyFactory` resolves `$ref` references, delegates `object` types to `processSchema`, and for all other types constructs a `Property` directly and applies Draft modifiers
- `ComposedValueProcessorFactory` handles `allOf`, `anyOf`, `oneOf`, `if/then/else`, `not`
- `SchemaDefinitionDictionary` tracks `$ref` definitions to avoid duplicate processing

### Draft System (`src/Draft/`)

The Draft system defines per-type modifier and validator registrations:
- **`DraftInterface`** / **`DraftBuilder`** / **`Draft`** — Draft definition, builder, and built (immutable) registry
- **`Draft_07.php`** — The JSON Schema Draft 7 definition; registers all types, modifiers, and validator factories
- **`Element/Type`** — One entry per JSON Schema type; holds an ordered list of `ModifierInterface` instances
- **`Modifier/`** — `TypeCheckModifier`, `ConstModifier`, `NumberModifier`, `NullModifier`, `ObjectType/ObjectModifier`, `DefaultValueModifier`, `DefaultArrayToEmptyArrayModifier`; each implements `ModifierInterface::modify()`
- **`Model/Validator/Factory/`** — `AbstractValidatorFactory` subclasses keyed to schema keywords (e.g. `MinLengthPropertyValidatorFactory` for `minLength`); run as modifiers when a matching key exists in the schema

`PropertyFactory::applyDraftModifiers` resolves `getCoveredTypes($type)` (which always includes `'any'`) and runs every modifier for each covered type in order.

### Property Processors (`src/PropertyProcessor/`)

- `Property/` — One processor per JSON Schema type
- `ComposedValue/` — Processors for composition keywords
- `ComposedValue/` — Processors for composition keywords (`allOf`, `anyOf`, `oneOf`, `if/then/else`, `not`)
- `Filter/` — Custom filter processing
- `Decorator/` — Property decorators (ObjectInstantiation, PropertyTransfer, IntToFloatCast, etc.)

Expand All @@ -104,6 +134,17 @@ Implement `SchemaProviderInterface` to supply schemas from custom sources. Built

`AbstractPHPModelGeneratorTestCase` is the base class for all tests. Tests generate model classes into a temp directory and then instantiate/exercise them to verify validation behavior. The `tests/manual/` directory contains standalone scripts excluded from the test suite.

#### Test case consolidation

Each call to `generateClassFromFile` triggers a code generation pass, which is the dominant cost in the test suite. **Minimise the number of distinct `generateClassFromFile` calls** by combining assertions that share the same schema file and `GeneratorConfiguration` into a single test method.

Rules:

- Group assertions by `(schema file, GeneratorConfiguration)` pair. All assertions that can use the same generated class belong in one test method.
- A single test method may cover multiple behaviours (e.g. key naming, round-trip, `$except`, custom serializer) as long as they all operate on the same generated class. Use clear inline comments to separate the logical sections.
- Only split into separate test methods when the behaviours require genuinely different configurations, or when combining them would make the test too complex to understand at a glance.
- The goal is the balance between runtime efficiency (fewer generations) and readability (each method remains comprehensible). Avoid both extremes: a single monolithic test and a proliferation of single-assertion tests.

### JSON Schema style

In test schema files (`tests/Schema/**/*.json`), every object value must be expanded across multiple lines — never written inline. Use this style:
Expand Down Expand Up @@ -131,6 +172,33 @@ property, duplicate property names with unresolvable type conflicts, and any oth
that cannot produce a correct PHP model. Fail loudly at generation time so the developer sees the
problem immediately rather than receiving silently incorrect generated code.

### Filter callable classes must be in the production library

A `FilterInterface::getFilter()` callable is embedded verbatim in generated PHP code and is
called at runtime — without the generator package being present. Any class referenced in
`getFilter()` must therefore live in `php-json-schema-model-generator-production`, not in this
generator package. Using a generator-package class as a filter callable will produce generated
code that fails at runtime whenever the generator is not installed.

If a production-library class lacks the required type hints (needed for reflection-based type
derivation), the fix is to add or update the callable in the production library, not to create
a wrapper class here.

### Staging changes

After finishing an implementation task, always stage all relevant changed files for commit using
`git add`. Do not wait for the user to ask — stage immediately when the work is done.

### Reading files

Always use the dedicated `Read` tool to read file contents. Never use `sed`, `head`, `tail`, `cat`, or `awk` to read or extract portions of files. The `Read` tool supports `offset` and `limit` parameters for reading partial files when needed.

### Variable naming

Never use single-character variable names. All variables must have meaningful, descriptive names
that convey their purpose. For example, use `$typeName` instead of `$t`, `$validator` instead of
`$v`, `$property` instead of `$p`.

### PHP import style

Always add `use` imports for every class referenced in a file, including global PHP classes such as
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
}
],
"require": {
"wol-soft/php-json-schema-model-generator-production": "^0.21.1",
"wol-soft/php-json-schema-model-generator-production": "dev-master",
"wol-soft/php-micro-template": "^1.10.2",

"php": ">=8.4",
Expand Down
Binary file modified docs/requirements.txt
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = 'en'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
Expand Down
Loading
Loading