The README still framed the project as "Phase 5 / pre-v0.1.0" and the docs predated the v0.2.0 surface (typed BridgeOp, public service interfaces, port negotiation, pre-migration auto-backup, bridge:export, periodic auto-update, two new makers, qmltestrunner). Bring them in line with what's actually shipped, and add badges (release, license, PHP, Symfony, Qt, FrankenPHP, CI, platform) to the README so the status is legible at a glance. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
114 lines
6.7 KiB
Markdown
114 lines
6.7 KiB
Markdown
# php-qml
|
|
|
|
A framework for native desktop applications with a **Symfony / FrankenPHP** backend and a **Qt / QML** frontend, packaged as a single distributable per OS.
|
|
|
|
[](https://src.bundespruefstelle.ch/magdev/php-qml/releases/tag/v0.2.0)
|
|
[](LICENSE)
|
|
[](https://www.php.net/)
|
|
[](https://symfony.com/)
|
|
[](https://www.qt.io/)
|
|
[](https://frankenphp.dev/)
|
|
[](https://src.bundespruefstelle.ch/magdev/php-qml/actions/workflows/ci.yml)
|
|
[](docs/packaging-linux.md)
|
|
|
|
> **Status:** v0.2.0 (2026-05-03). Linux AppImage is the only packaged target; macOS and Windows packaging are tracked under [PLAN.md §13](PLAN.md#13-roadmap-to-poc) Phases 4b/4c. Pre-v1.0 SemVer permits API breaks on minor bumps — see [CHANGELOG.md](CHANGELOG.md).
|
|
|
|
---
|
|
|
|
## What it is
|
|
|
|
php-qml lets a PHP developer write a desktop app using ordinary Symfony on the backend and ordinary QML on the frontend. The two halves run as a **process pair** inside one bundled binary:
|
|
|
|
- A Qt/QML host owns the window, input, and rendering.
|
|
- A bundled FrankenPHP child runs a Symfony app in worker mode.
|
|
- They communicate over a local socket — HTTP for commands and queries, Mercure SSE for state push.
|
|
|
|
It is **not** a PHP↔Qt language binding — the languages run in separate processes; the bridge is a wire protocol, not an FFI layer. That deliberately avoids the failure mode that left php-gtk and php-qt unmaintained.
|
|
|
|
## 60-second tour
|
|
|
|
```bash
|
|
git clone https://src.bundespruefstelle.ch/magdev/php-qml && cd php-qml
|
|
|
|
# Scaffold a fresh app
|
|
./bin/php-qml-init my-app
|
|
|
|
# Run it
|
|
cd my-app
|
|
make doctor # readiness check
|
|
make dev # FrankenPHP --watch + Qt host
|
|
```
|
|
|
|
Add a reactive resource (entity + REST controller + QML snippet) with one maker:
|
|
|
|
```bash
|
|
cd my-app/symfony
|
|
bin/console make:bridge:resource Todo # add --with-dto for #[MapRequestPayload] + RFC 7807 errors
|
|
bin/console make:migration && bin/console doctrine:migrations:migrate -n
|
|
```
|
|
|
|
`make dev` opens the Qt window, connection state flips to **Online**, and the generated `TodoList.qml` shows a list whose `ReactiveListModel` is auto-subscribed to `app://model/todo` over Mercure. There is no handwritten cross-side glue.
|
|
|
|
The maker family covers the four common shapes: [`make:bridge:resource`](docs/makers.md#makebridgeresource) (CRUD), [`make:bridge:command`](docs/makers.md#makebridgecommand) (non-CRUD action), [`make:bridge:event`](docs/makers.md#makebridgeevent) (domain event → QML signal), [`make:bridge:read-model`](docs/makers.md#makebridgeread-model) (query-only projection), and [`make:bridge:window`](docs/makers.md#makebridgewindow) (second window).
|
|
|
|
For a non-trivial app with a multi-window test, crash-recovery test, and AppImage packaging, see [`examples/todo/`](examples/todo/README.md).
|
|
|
|
## Documentation
|
|
|
|
The full developer documentation lives under [`docs/`](docs/README.md):
|
|
|
|
- **[Getting started](docs/getting-started.md)** — prerequisites by distro, first project, troubleshooting.
|
|
- **[Architecture](docs/architecture.md)** — process pair, transport, dev vs bundled mode.
|
|
- **[Update semantics](docs/update-semantics.md)** — connection state machine, optimistic mutations, idempotency.
|
|
- **[Reactive models](docs/reactive-models.md)** — `ReactiveListModel`, `ReactiveObject`, Mercure dual-publish.
|
|
- **[Makers](docs/makers.md)** — `make:bridge:resource` / `command` / `event` / `read-model` / `window`.
|
|
- **[Dev workflow](docs/dev-workflow.md)** — hot reload, dev console, editor setup, `bridge:doctor`, `make qmltest`.
|
|
- **[Bundled mode](docs/bundled-mode.md)** — supervisor, per-session secret rotation, port negotiation, pre-migration auto-backup, first-launch migrations.
|
|
- **[Linux packaging](docs/packaging-linux.md)** — `make appimage`, auto-update (launch + 6h poll), performance budgets.
|
|
- **[Native dialogs](docs/native-dialogs.md)** — file pickers, message boxes, system tray; the QML/PHP boundary.
|
|
- **[Configuration reference](docs/configuration.md)** — env vars, CLI flags.
|
|
- **[QML API reference](docs/qml-api.md)** / **[PHP API reference](docs/php-api.md)** — singletons, components, attributes, services, interfaces.
|
|
|
|
Design rationale and roadmap live in [PLAN.md](PLAN.md). User-facing changes per release are in [CHANGELOG.md](CHANGELOG.md).
|
|
|
|
## Tech stack
|
|
|
|
PHP 8.4+ · Symfony 8 · Doctrine ORM 3 · FrankenPHP 1.12+ (worker mode) · Mercure · Qt 6.5+ · CMake · Composer · Gitea Actions
|
|
|
|
## Roadmap
|
|
|
|
- **Phase 0** ✅ throwaway transport spike.
|
|
- **Phase 1** ✅ framework skeleton, dev mode, single-instance lock, CI quality gate.
|
|
- **Phase 2** ✅ reactive models, update semantics, headline maker.
|
|
- **Phase 3** ✅ POC todo app, integration + snapshot tests.
|
|
- **Phase 4a** ✅ bundled mode, Linux AppImage, release CI, AppImageUpdate.
|
|
- **Phase 5** ✅ DX polish — dev console, init script, hot-reload docs (shipped with v0.1.0).
|
|
- **v0.2.0** ✅ post-v0.1 architecture audit + operations row: typed `BridgeOp` enum, public service interfaces, port negotiation, pre-migration auto-backup, `bridge:export`, periodic auto-update check, two new makers (`event`, `read-model`), `qmltestrunner` in CI.
|
|
- **Phase 4b/4c** ⏳ macOS / Windows packaging.
|
|
- **v1.0.0** ⏳ API stabilisation; pre-1.0 minor bumps may still break.
|
|
|
|
## Tested platforms
|
|
|
|
| OS | Packaging | CI |
|
|
| --------------- | --------- | -------------------------- |
|
|
| Linux x86_64 | AppImage | Gitea Actions (every push) |
|
|
| macOS / Windows | not yet | — |
|
|
|
|
## Contributing
|
|
|
|
Active development happens on the `dev` branch; `main` only carries release commits. Pull requests target `dev`.
|
|
|
|
```bash
|
|
cd framework/php && composer quality # PHPStan + cs-fixer + PHPUnit
|
|
cd framework/skeleton && make qmltest # qmltestrunner unit tests (Quick Test)
|
|
cd examples/todo && make quality # adds qmllint + integration test
|
|
```
|
|
|
|
## Versioning
|
|
|
|
[Semantic Versioning](https://semver.org/) — `MAJOR.MINOR.BUGFIX`. Pre-v1.0.0, minor bumps may break public API; bugfix bumps don't.
|
|
|
|
## License
|
|
|
|
[**LGPL-3.0-or-later**](LICENSE) — chosen to align with Qt 6's LGPLv3 licensing. The bundled AppImage honours the relinkability obligations (Qt libs are shipped as separate `.so`s, not statically linked); see [PLAN.md §12](PLAN.md#12-open-questions-and-risks) for the full rationale.
|