{"id":36971843,"url":"https://github.com/mbolli/php-via","last_synced_at":"2026-04-02T10:30:37.489Z","repository":{"id":326511988,"uuid":"1104692016","full_name":"mbolli/php-via","owner":"mbolli","description":"Real-time engine for building reactive web applications in PHP with Swoole.","archived":false,"fork":false,"pushed_at":"2025-12-21T12:46:40.000Z","size":1411,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-23T03:19:18.215Z","etag":null,"topics":["datastar","php-framework","reactive","swoole"],"latest_commit_sha":null,"homepage":"https://via.zweiundeins.gmbh","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mbolli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-26T14:56:39.000Z","updated_at":"2025-12-21T12:46:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mbolli/php-via","commit_stats":null,"previous_names":["mbolli/php-via"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mbolli/php-via","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbolli%2Fphp-via","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbolli%2Fphp-via/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbolli%2Fphp-via/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbolli%2Fphp-via/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mbolli","download_url":"https://codeload.github.com/mbolli/php-via/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbolli%2Fphp-via/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28401608,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["datastar","php-framework","reactive","swoole"],"created_at":"2026-01-13T21:54:45.785Z","updated_at":"2026-04-02T10:30:37.474Z","avatar_url":"https://github.com/mbolli.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# php-via\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/mbolli/php-via.svg?style=flat-square)](https://packagist.org/packages/mbolli/php-via)\n[![Total Downloads](https://img.shields.io/packagist/dt/mbolli/php-via.svg?style=flat-square)](https://packagist.org/packages/mbolli/php-via)\n[![License](https://img.shields.io/packagist/l/mbolli/php-via.svg?style=flat-square)](https://packagist.org/packages/mbolli/php-via)\n[![PHP Version](https://img.shields.io/packagist/php-v/mbolli/php-via.svg?style=flat-square)](https://packagist.org/packages/mbolli/php-via)\n[![CI](https://img.shields.io/github/actions/workflow/status/mbolli/php-via/ci.yml?branch=master\u0026style=flat-square\u0026label=CI)](https://github.com/mbolli/php-via/actions)\n[![PHPStan](https://img.shields.io/badge/PHPStan-level%206-brightgreen.svg?style=flat-square)](https://phpstan.org/)\n[![Docs](https://img.shields.io/badge/docs-via.zweiundeins.gmbh-blue?style=flat-square)](https://via.zweiundeins.gmbh)\n\n\u003ca href=\"https://via.zweiundeins.gmbh\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/mbolli/php-via/master/logo.png\" alt=\"php-via\"\u003e\u003c/a\u003e\n\nReal-time reactive web framework for PHP. Server-side reactive UIs with zero JavaScript, using [OpenSwoole](https://openswoole.com/) for async PHP, [Datastar](https://data-star.dev) (RC.8) for SSE + DOM morphing, and [Twig](https://twig.symfony.com/) for templating.\n\n**[Documentation \u0026 Live Examples](https://via.zweiundeins.gmbh)**\n\n## Why php-via?\n\n- **No JavaScript to write** — Datastar handles client-side reactivity, SSE, and DOM morphing\n- **Twig templates** — familiar, powerful server-side templating\n- **No build step** — no transpilation, no bundling, no node_modules\n- **Real-time by default** — every page gets a live SSE connection\n- **Scoped state** — TAB, ROUTE, SESSION, GLOBAL, and custom scopes control who shares what\n- **Single SSE stream** — extremely efficient with Brotli compression\n\n## Requirements\n\n- PHP 8.4+\n- OpenSwoole extension\n- Composer\n\n## Installation\n\n```\ncomposer require mbolli/php-via\n```\n\n## Quick Start\n\n```php\n\u003c?php\nrequire 'vendor/autoload.php';\n\nuse Mbolli\\PhpVia\\Via;\nuse Mbolli\\PhpVia\\Config;\nuse Mbolli\\PhpVia\\Context;\n\n$config = new Config();\n$config-\u003ewithTemplateDir(__DIR__ . '/templates');\n$app = new Via($config);\n\n$app-\u003epage('/', function (Context $c): void {\n    $count = $c-\u003esignal(0, 'count');\n    $step  = $c-\u003esignal(1, 'step');\n\n    $increment = $c-\u003eaction(function () use ($count, $step, $c): void {\n        $count-\u003esetValue($count-\u003eint() + $step-\u003eint());\n        $c-\u003esyncSignals();\n    }, 'increment');\n\n    $c-\u003eview('counter.html.twig', [\n        'count'     =\u003e $count,\n        'step'      =\u003e $step,\n        'increment' =\u003e $increment,\n    ]);\n});\n\n$app-\u003estart();\n```\n\n**counter.html.twig:**\n\n```twig\n\u003cdiv id=\"counter\"\u003e\n    \u003cp\u003eCount: \u003cspan data-text=\"${{ count.id }}\"\u003e{{ count.int }}\u003c/span\u003e\u003c/p\u003e\n    \u003clabel\u003eStep: \u003cinput type=\"number\" data-bind=\"{{ step.id }}\"\u003e\u003c/label\u003e\n    \u003cbutton data-on:click=\"@post('{{ increment.url }}')\"\u003eIncrement\u003c/button\u003e\n\u003c/div\u003e\n```\n\n```\nphp app.php\n# → http://localhost:3000\n```\n\n## Core Concepts\n\nFull documentation at **[via.zweiundeins.gmbh/docs](https://via.zweiundeins.gmbh/docs)**\n\n### Signals — reactive state that syncs between server and client\n\n```php\n$name = $c-\u003esignal('Alice', 'name');\n$name-\u003estring();          // read\n$name-\u003esetValue('Bob');    // write → auto-pushes to browser\n```\n\n```twig\n\u003cinput data-bind=\"{{ name.id }}\"\u003e\n\u003cspan data-text=\"${{ name.id }}\"\u003e{{ name.string }}\u003c/span\u003e\n```\n\n### Actions — server-side functions triggered by client events\n\n```php\n$save = $c-\u003eaction(function () use ($c): void {\n    $c-\u003esync();\n}, 'save');\n```\n\n```twig\n\u003cbutton data-on:click=\"@post('{{ save.url }}')\"\u003eSave\u003c/button\u003e\n```\n\n### Scopes — control who shares state and receives broadcasts\n\n| Scope | Sharing | Use Case |\n|-------|---------|----------|\n| `Scope::TAB` | Isolated per tab (default) | Personal forms, settings |\n| `Scope::ROUTE` | All users on same route | Shared boards, multiplayer |\n| `Scope::SESSION` | All tabs in same session | Cross-tab state |\n| `Scope::GLOBAL` | All users everywhere | Notifications, announcements |\n| Custom (`\"room:lobby\"`) | All contexts in that scope | Chat rooms, game lobbies |\n\n### Views — Twig template files or inline strings\n\n```php\n$c-\u003eview('dashboard.html.twig', ['user' =\u003e $user]);\n```\n\n### Path Parameters — auto-injected by name\n\n```php\n$app-\u003epage('/blog/{year}/{slug}', function (Context $c, string $year, string $slug): void {\n    // ...\n});\n```\n\n### Components — reusable sub-contexts with isolated state\n\n```php\n$a = $c-\u003ecomponent($counterWidget, 'a');\n$b = $c-\u003ecomponent($counterWidget, 'b');\n```\n\n### Lifecycle Hooks\n\n```php\n$c-\u003eonDisconnect(fn() =\u003e /* cleanup */);\n$c-\u003esetInterval(fn() =\u003e $c-\u003esync(), 2000);  // auto-cleaned on disconnect\n$app-\u003eonClientConnect(fn(string $id) =\u003e /* ... */);\n```\n\n### Broadcasting — push updates to other connected clients\n\n```php\n$c-\u003ebroadcast();                    // same scope\n$app-\u003ebroadcast(Scope::GLOBAL);     // all contexts\n$app-\u003ebroadcast('room:lobby');      // custom scope\n```\n\n## How it Works\n\n```\n1. Browser requests page     →  Server renders HTML, opens SSE stream\n2. User clicks button        →  Datastar POSTs signal values + action ID\n3. Server executes action    →  Modifies signals / state\n4. Server pushes patches     →  HTML fragments + signal updates via SSE\n5. Datastar morphs DOM       →  UI updates without page reload\n```\n\n## Development\n\n```\ngit clone https://github.com/mbolli/php-via.git\ncd php-via \u0026\u0026 composer install\n\ncd website \u0026\u0026 php app.php    # run website + examples on :3000\n\nvendor/bin/pest              # 101 tests, 258 assertions\ncomposer phpstan             # PHPStan level 6\ncomposer cs-fix              # code style\n```\n\n## Deployment\n\nSingle OpenSwoole process behind a reverse proxy. See [deploy/](deploy/) for systemd + Caddy configs.\n\n```\nBrowser → Caddy (TLS + Brotli) → OpenSwoole :3000\n```\n\n## Roadmap\n\n- [ ] Route groups (`$app-\u003egroup('/prefix', fn)`)\n- [ ] `initAtBoot()` — explicit hook for boot-time shared state initialisation\n- [ ] Global intervals (`$app-\u003esetInterval()` — one shared timer per server process)\n\n## Credits\n\n- [Datastar](https://data-star.dev/) — SSE + DOM morphing\n- [OpenSwoole](https://openswoole.com/) — Async PHP\n- [Twig](https://twig.symfony.com/) — Templating\n- [go-via/via](https://github.com/go-via/via) — Original Go inspiration\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmbolli%2Fphp-via","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmbolli%2Fphp-via","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmbolli%2Fphp-via/lists"}