|
| 1 | +# Windwalker Framework – Agent Guide |
| 2 | + |
| 3 | +## Architecture Overview |
| 4 | + |
| 5 | +**Monorepo of 26+ standalone PHP packages** under `packages/`. Each package is independently installable via Composer |
| 6 | +but shares a unified dev environment at the root. The root `composer.json` maps all namespace prefixes ( |
| 7 | +`Windwalker\{PackageName}\`) and autoloads each package's `src/bootstrap.php`. |
| 8 | + |
| 9 | +This repository ships the **components** consumed by the full Windwalker framework (`windwalker/windwalker`). It is not |
| 10 | +a runnable application. |
| 11 | + |
| 12 | +**PHP requirement:** ≥ 8.4.6. Code uses PHP 8.4 features (asymmetric visibility `public protected(set)`, named |
| 13 | +arguments, first-class callables). |
| 14 | + |
| 15 | +## Code Style |
| 16 | + |
| 17 | +- PSR-12 coding style. |
| 18 | +- Strict types (`declare(strict_types=1);` in all source files). |
| 19 | +- Docblocks only for non-obvious code; no redundant `@param`/`@return` when types are clear from signatures. |
| 20 | +- No global state or singletons; dependencies injected via constructors or method parameters. |
| 21 | +- No static methods except for pure utility functions (e.g. `StrInflector`, `Arr` or `Str`). |
| 22 | +- No facades or service locators; use explicit class references and dependency injection. |
| 23 | +- No global functions except for namespaced helpers defined in `functions.php` (e.g. `\Windwalker\collect()`, |
| 24 | + `\Windwalker\raw()`). These are autoloaded via Composer's `files` autoloading and are not procedural global functions. |
| 25 | +- No magic methods (`__call`, `__get`, etc.) – all behavior should be explicit and discoverable via class methods and |
| 26 | + properties. |
| 27 | +- No deprecated features or legacy patterns; the codebase is modern PHP 8.4+ and should not contain any legacy PHP 5/7 |
| 28 | + constructs. |
| 29 | +- Use PHP 8.5 property hooks with asymmetric visibility (`public protected(set)`) for properties prior than legacy |
| 30 | + getter/setter methods. This allows read-only public access while still allowing internal mutation when necessary. |
| 31 | + |
| 32 | +All code style instructions see: `/.github/instructions/cs.instructions.md`. |
| 33 | + |
| 34 | +All test code style instructions see: `/.github/instructions/test.instructions.md`. |
| 35 | + |
| 36 | +## Package Layout |
| 37 | + |
| 38 | +Every package follows this structure: |
| 39 | + |
| 40 | +``` |
| 41 | +packages/{name}/ |
| 42 | + src/ # PSR-4 source (Windwalker\{Name}\) |
| 43 | + src/bootstrap.php # Loaded by Composer autoload files – registers closures/helpers |
| 44 | + src/functions.php # Global helper functions (e.g. \Windwalker\collect(), \Windwalker\raw()) |
| 45 | + test/ # PHPUnit tests (Windwalker\{Name}\Test\) |
| 46 | + composer.json # Standalone package metadata |
| 47 | + phpunit.xml.dist # Per-package PHPUnit config |
| 48 | +``` |
| 49 | + |
| 50 | +All source files begin with `declare(strict_types=1);`. |
| 51 | + |
| 52 | +## Developer Workflows |
| 53 | + |
| 54 | +### Running Tests |
| 55 | + |
| 56 | +```bash |
| 57 | +# All enabled tests (edit phpunit.xml to uncomment suites) |
| 58 | +php vendor/bin/phpunit |
| 59 | + |
| 60 | +# Single package suite |
| 61 | +php vendor/bin/phpunit --configuration packages/orm/phpunit.xml.dist |
| 62 | + |
| 63 | +# Database/HTTP tests require setup first: |
| 64 | +php -S localhost:8000 bin/test-server.php # HTTP test server |
| 65 | +# Set WINDWALKER_TEST_DB_DSN_MYSQL in phpunit.xml |
| 66 | +``` |
| 67 | + |
| 68 | +The root `phpunit.xml` is copied from `phpunit.xml.dist` and can be edited to enable/disable test suites. Each package |
| 69 | +also has its own `phpunit.xml.dist` for package-specific configuration (e.g. database DSN). |
| 70 | + |
| 71 | +### Test Base Classes |
| 72 | + |
| 73 | +- DB tests extend `AbstractDatabaseTestCase` (in `packages/database/src/Test/`). |
| 74 | +- ORM tests extend `AbstractORMTestCase` which wires `ORM` to a live DB adapter. |
| 75 | +- Executed SQL is logged to `packages/database/tmp/test-sql.sql` during test runs. |
| 76 | + |
| 77 | +## Project-Specific Conventions |
| 78 | + |
| 79 | +- **Global helpers** are namespaced functions, not procedural: e.g. `\Windwalker\collect([...])`, |
| 80 | + `\Windwalker\raw($sql)`. Defined in `functions.php`, auto-loaded. |
| 81 | +- **Bootstrap files** (`src/bootstrap.php`) use autoload `files` – do not put heavy logic there; they mostly declare |
| 82 | + global function aliases. |
| 83 | +- **Deprecated options key** for some array or int options has moved to `***Options` classes (e.g. `ORM::FOR_UPDATE` → |
| 84 | + `new ORMOptions(forUpdate: true)`) – the old constants still exist but are marked deprecated. |
| 85 | +- **StrInflector** (`packages/utilities/src/StrInflector.php`) is used project-wide for singular/plural table alias |
| 86 | + resolution (e.g. `Table` attribute alias defaults to `StrInflector::toSingular($tableName)`). |
| 87 | +- Each package's `composer.json` is also listed under `"replace"` in the root – this lets Composer treat the monorepo |
| 88 | + root as all packages simultaneously. |
0 commit comments