Files
php-qml/framework/skeleton/README.md
magdev 1964a52f99
Some checks failed
CI / Quality (push) Failing after 1m50s
Phase 2 sub-commit 5: convention test passes, skeleton walkthrough, phase 2 closed
Runs `make:bridge:resource Todo` against the skeleton, then `make:migration`
+ `doctrine:migrations:migrate`, and verifies the round-trip end-to-end:

  - POST /api/todos creates a row with a UUIDv7 id
  - GET /api/todos returns the row
  - Mercure dual-publishes:
    - app://model/todo (collection topic)
    - app://model/todo/{uuid} (entity topic)
  - The published envelope shape matches PLAN.md §4 exactly:
    {op:"upsert", id:..., version:..., data:{...}, correlationKey:"..."}
  - correlationKey echoes the request's Idempotency-Key, ready to be
    matched by ReactiveListModel's pending state on the QML side.

Generated files committed as the regression baseline (Phase 3 will add
a CI check that re-running the maker reproduces these byte-for-byte):

  - framework/skeleton/symfony/src/Entity/Todo.php
  - framework/skeleton/symfony/src/Controller/TodoController.php
  - framework/skeleton/symfony/migrations/Version20260502004612.php
  - framework/skeleton/qml/TodoList.qml

framework/skeleton/README.md captures the three-command flow plus a
curl walkthrough so future readers can reproduce. Phase 2 done.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 02:49:23 +02:00

99 lines
3.7 KiB
Markdown

# php-qml skeleton
The framework's reference application: a minimal Symfony backend plus a Qt/QML host, wired together exactly the way `php-qml/bridge` is intended to be used. Use this as a starting point or copy parts into your own project.
## Prerequisites
- Linux (other platforms land in Phase 4)
- Qt 6.5+ dev packages (`qt6-base-devel`, `qt6-declarative-devel`, `qt6-quickcontrols2-devel`, `qt6-tools-devel`), CMake, gcc-c++
- PHP 8.3+
- [FrankenPHP](https://frankenphp.dev/) on PATH (or set `FRANKENPHP=/path/to/frankenphp`)
- Composer
## First run
```bash
make install # composer install in symfony/
make build # cmake + qt host
make doctor # bridge:doctor — readiness check
make dev # FrankenPHP --watch + Qt host, tears both down on Ctrl-C
```
`make dev` opens a Qt window, status dots flip to green, and the Ping button round-trips through `/api/ping` and back via Mercure SSE.
## Adding a reactive resource
The headline workflow — add a Doctrine entity that ends up reactive in QML with **three commands** and zero handwritten glue:
```bash
cd symfony
# 1) Generate entity + controller + QML snippet
bin/console make:bridge:resource Todo
# created: src/Entity/Todo.php # #[BridgeResource] + UUIDv7
# created: src/Controller/TodoController.php
# created: ../qml/TodoList.qml
# 2) Schema migration (Doctrine reads the entity)
bin/console make:migration
bin/console doctrine:migrations:migrate -n
# 3) Use the generated TodoList.qml from your QML window.
```
That's it. The bundle's Doctrine subscriber automatically dual-publishes
`postPersist`/`postUpdate`/`postRemove` events to:
- `app://model/todo` (collection topic, watched by `ReactiveListModel`)
- `app://model/todo/{id}` (entity topic, watched by `ReactiveObject` — Phase 3)
The `ReactiveListModel` in `TodoList.qml` does an initial `GET /api/todos`, subscribes to the collection topic, and applies diffs to its rows as they arrive. Adding `--int-id` switches the maker to auto-incrementing integer IDs.
### Verifying end-to-end
With `make dev` running, post a todo from another terminal and watch it appear:
```bash
curl -X POST http://127.0.0.1:8765/api/todos \
-H 'Authorization: Bearer devtoken' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: my-key-1' \
-d '{"title":"buy milk","done":false}'
```
The Mercure SSE stream receives a `correlationKey: my-key-1` envelope which the Qt host's `ReactiveListModel` matches against any in-flight optimistic mutation (PLAN.md §5).
## Quality checks
```bash
make quality # PHPStan + php-cs-fixer (check) + PHPUnit + qmllint
```
The same set CI runs (`.gitea/workflows/ci.yml`).
## Layout
```text
skeleton/
Caddyfile # FrankenPHP / Mercure config (dev mode)
Makefile # build / dev / doctor / quality
scripts/dev.sh # process-group teardown for FrankenPHP + Qt host
symfony/ # the Symfony app (composer project)
config/
src/Entity/ # filled by `make:bridge:resource`
src/Controller/ # filled by `make:bridge:resource`
public/index.php
bin/console
qml/ # the Qt host
CMakeLists.txt
main.cpp
Main.qml
<Name>List.qml # filled by `make:bridge:resource` (relative to symfony/)
```
## Where to go next
- The framework code lives one level up: [`framework/php`](../php) (the bundle) and [`framework/qml`](../qml) (the Qt module). Both are linked into this skeleton via Composer's path repository / CMake's `add_subdirectory`, so edits there are picked up live.
- The full design story is in [`PLAN.md`](../../PLAN.md).
- Phase 3 wires this skeleton into a real POC todo application with a multi-window test and packaging-CI dry runs.