magdev 2f4766c7cb
Some checks failed
CI / Quality (push) Successful in 5m4s
Release / Linux AppImage (push) Failing after 5m36s
bridge: fix doubled bin/ in bundled-mode frankenphp path resolution
resolveFrankenphpBin() returned `applicationDirPath() + "/bin/frankenphp"`,
but applicationDirPath() inside an AppImage is already `usr/bin/` —
where the host binary itself runs from. The "/bin/" prefix produced
the doubled path, e.g.:

  /tmp/appimage_extracted_<hash>/usr/bin/bin/frankenphp

…which doesn't exist. The supervisor logged the lookup failure and
kept retrying, eventually hitting the perfsmoke 8s cold-start
deadline.

build-appimage.sh:148 installs frankenphp at `usr/bin/frankenphp`
(sibling of the host binary, per the layout comment at line 18). The
fix is to drop the spurious `/bin/`. Other resolvers in the same
file (resolveSymfonyDir, resolveCaddyfilePath) already use the
correct `here + "/<file>"` pattern.

Bug shipped since the bundled-mode supervisor was added — would
have hit anyone running the AppImage. Local `make quality` only
exercises dev mode (BRIDGE_URL set), so the integration test loop
never reached this codepath; CI's perfsmoke against the actual
AppImage is the only thing that catches it. Manual test would be:
launch the AppImage with BRIDGE_FRANKENPHP_BIN unset and watch the
phpqml.bridge.bundled log.

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

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.

Status: Phase 5 / pre-v0.1.0. Phases 04a are merged (working framework, real POC, Linux AppImage, auto-update, release CI). macOS and Windows packaging are deferred to 4b/4c. See 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

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:

cd my-app/symfony
bin/console make:bridge:resource Todo
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.

For a non-trivial app with a multi-window test, crash-recovery test, and AppImage packaging, see examples/todo/.

Documentation

The full developer documentation lives under docs/:

Design rationale and roadmap live in PLAN.md. User-facing changes per release are in 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 4b/4c macOS / Windows packaging.
  • Phase 5 🚧 DX polish — dev console, init script, hot-reload docs, v0.1.0 prep.

Contributing

Active development happens on the dev branch; main only carries release commits. Pull requests target dev.

cd framework/php && composer quality   # PHPStan + cs-fixer + PHPUnit
cd examples/todo  && make quality      # adds qmllint + integration test

A dedicated CONTRIBUTING.md arrives with Phase 5's wrap-up.

Versioning

Semantic VersioningMAJOR.MINOR.BUGFIX. Pre-v1.0.0, minor bumps may break public API.

License

To be decided before v0.1.0 is tagged. The framework's own code will be permissively licensed; Qt is shipped under LGPL with relinkability obligations — see PLAN.md §12.

Description
Bridge to run Symfony applications with native QML interfaces
Readme 503 KiB
v0.1.0 Latest
2026-05-03 10:21:14 +00:00
Languages
PHP 44.4%
C++ 34.4%
Shell 10.3%
QML 8.1%
CMake 1.4%
Other 1.4%