PHPackages                             survos/fw-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. survos/fw-bundle

ActiveSymfony-bundle[Framework](/categories/framework)

survos/fw-bundle
================

Bundle with utilities for creating a Symfony-based mobile app with framework7

2.18.18(1w ago)0162MITPHPPHP ^8.5CI failing

Since Mar 8Pushed 1w ago2 watchersCompare

[ Source](https://github.com/survos/fw-bundle)[ Packagist](https://packagist.org/packages/survos/fw-bundle)[ GitHub Sponsors](https://github.com/kbond)[ RSS](/packages/survos-fw-bundle/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (217)Versions (229)Used By (0)

Survos Fw (Framework7) Bundle
=============================

[](#survos-fw-framework7-bundle)

A collection of tools to help create Symfony-based mobile apps.

- framework7
- pwa-bundle
- Dexie

Work in Progress. See  to see this in action.

See `docs/events.md` for how Framework7 v9's page/tab lifecycle events actually work (DOM events vs. F7's own internal pub/sub, and the real gotcha: they only fire when F7's router is driving the navigation) — read that before wiring up any new event listener in an app built on this bundle.

Adding fw7 to an existing PWA (simple, no Dexie)
------------------------------------------------

[](#adding-fw7-to-an-existing-pwa-simple-no-dexie)

Everything below the "Notes" heading documents the full Dexie-synced, multi-tab-store SPA pattern used by `framework7-bundle-demo`. If your app is just plain server-rendered Symfony pages (every route a real page load, not an in-app SPA router) and you want Framework7 purely as PWA chrome — navbar, tabbar, card/list/button styling — you don't need any of that. This is the simpler path, verified working end to end in [survos-sites/sos](https://github.com/survos-sites/sos).

### 1. Install and register

[](#1-install-and-register)

```
composer require survos/fw-bundle spomky-labs/pwa-bundle
```

```
// config/bundles.php
Survos\FwBundle\SurvosFwBundle::class => ['all' => true],
SpomkyLabs\PwaBundle\SpomkyLabsPwaBundle::class => ['all' => true],
```

`spomky-labs/pwa-bundle`'s recipe comes from `recipes-contrib` and gets silently skipped by Flex in non-interactive installs — if `cache:clear`throws about a missing `pwa.image_processor` or similar, just add the bundle line above by hand and write `config/packages/pwa.yaml` yourself (copy `sos`'s or `framework7-bundle-demo`'s as a starting point). Same story for `survos/auth-bundle` if you use it: it needs `KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class` registered too, also silently skipped for the same reason.

### 2. Pull in Framework7 via importmap

[](#2-pull-in-framework7-via-importmap)

```
bin/console importmap:require framework7/bundle@9.1.1 framework7/css/bundle@9.1.1 framework7-icons framework7-icons/css/framework7-icons.min.css
```

### 3. The Stimulus controller — two non-obvious gotchas

[](#3-the-stimulus-controller--two-non-obvious-gotchas)

```
// assets/controllers/f7_controller.js
import { Controller } from '@hotwired/stimulus';
import Framework7 from 'framework7/bundle';
import 'framework7/css/bundle';
import 'framework7-icons/css/framework7-icons.min.css';

export default class extends Controller {
    connect() {
        window.app = new Framework7({
            el: this.element,
            theme: 'auto',
            // Framework7 auto-creates a routed "main view" on .view-main
            // and hijacks every  click inside it, fetching the target
            // via its own AJAX router instead of a normal navigation.
            // Without this, EVERY link in the app silently stops working
            // the moment you're not building an actual F7 SPA.
            clicks: {
                externalLinks: 'a',
            },
        });
    }
}
```

```
{# templates/base.html.twig #}

```

The `data-turbo="false"` matters even if you never intentionally reach for Turbo: `symfony/ux-turbo` ships in the default `symfony new --webapp`skeleton and is enabled by default. Without disabling it, Turbo intercepts a form submit or link click, does its own DOM-morphing navigation, and Framework7's Stimulus controller reconnects on the un-reloaded page — throwing `Framework7 is already initialized and can't be initialized more than once`. Both of these were found the hard way building `sos`: the Settings tab (and every other in-app link) was completely dead until the `clicks.externalLinks` fix landed.

### 4. The page shell

[](#4-the-page-shell)

```
{# templates/base.html.twig #}

                    {% block navbar_title %}App Name{% endblock %}

                {% block body %}{% endblock %}

                        house_fill
                        Home

```

Every real page in the app just `{% extends 'base.html.twig' %}` and fills in `body`/`navbar_title` — no Dexie stores, no client-side routing, no `` component. Symfony's own routing and Twig rendering do all the work; Framework7 is purely CSS + the tabbar/navbar/card/list/button markup conventions.

Because `clicks.externalLinks: 'a'` routes every link through a real browser navigation instead of F7's own router, F7's page lifecycle events (`page:init`/`pageInit` and friends — see `docs/events.md`) never fire in this mode. That's expected, not a bug: there's no F7-managed page transition for them to fire *for*. Do data-loading in a normal Stimulus `connect()`/`initialize()` here, not an F7 event listener.

Multi-project apps: Dexie-synced, no full page loads
----------------------------------------------------

[](#multi-project-apps-dexie-synced-no-full-page-loads)

This is the pattern that actually delivers "installable app, not a website" — every tab switch and every detail-page navigation happens client-side, with zero server round-trip after the initial page load. It's real and working today in [survos-sites/framework7-bundle-demo](https://github.com/survos-sites/framework7-bundle-demo)(`chijal`/`modo`/`cmas` projects) — that repo is the canonical reference implementation; this section is the map of how its pieces fit together, since previously the only trace of it here was a partial, admittedly-unfinished note. If you're building a new multi-tenant app on this bundle, copy from that demo, not from scratch.

### The pieces, end to end

[](#the-pieces-end-to-end)

1. **`config/packages/survos_fw.yaml`** — one `projects:` entry per tenant. Each project is a `code`, `logo`, `name`, an ordered `tabs` list (each tab name maps to a `templates/tabs/.html.twig` include), a Dexie `database` name, and `stores` (the `{name, schema, url}` triplets Dexie syncs — `schema` is a Dexie index spec, `url` is the fetch source; `url: null` for a store that's purely local/client-written, e.g. a `checkins`/`claps` table nothing ever fetches):

    ```
    survos_fw:
      projects:
        chijal:
          code: chijal
          logo: /logos/chijal-logo.jpg
          name: Chijal
          tabs: [locations, map, artists, obras, info]
          database: chijal
          stores:
            - { name: artists, schema: code, url: https://chijal.org/api/artists }
            - { name: locations, schema: code, url: https://chijal.org/api/locations }
            - { name: checkins, schema: "locationCode,timestamp", url: null }
    ```
2. **`@SurvosFw/start.html.twig`** (this bundle's own template — extend or override, don't copy) renders **every tab's content into the DOM in one page load**:

    ```

        {% for t in config.tabs %}

                {{ include('tabs/%s.html.twig'|format(t), {t: t}) }}

        {% endfor %}

    ```

    Switching tabs is Framework7's own native tab mechanism — no navigation, no fetch. F7 fires `tabShow`/`tabHide`; the app controller (below) turns `tabShow` into a plain DOM `CustomEvent('tab-{id}-show')`. This re-dispatch is legitimate, not a workaround: F7's real `tab:show` DOM event already exists and fires fine on its own (see `docs/events.md`), but it's generic — the same name for every tab. Constructing a per-tab-id event name here is genuinely new information F7 doesn't provide, needed so each tab's own `` only re-renders itself, not every tab at once.
3. **Each `tabs/.html.twig`** wraps its content in ``, keyed to that same event, so the tab (re-)renders from whatever's already in IndexedDB every time it's shown — not on a timer, not on page load, on the F7 event:

    ```

            {% for row in rows %}
                {{ row.name }}
            {% endfor %}

    ```

    `rows` there comes from `window.db.table(t).toArray()`, filtered by `:filter` if given — see `assets/src/controllers/dexie_controller.js` in `survos/js-twig-bundle`.
4. **Detail pages** (`/pages/artist/{code}`) are plain `` links, but they resolve through **Framework7's own client-side router** (`routes.js`, `app.views.main.router`), not the browser — so this layer of navigation is app-like too, not just tab-switching. This is the part easiest to miss: there's nothing conspicuously "SPA" about the markup, it's just an ``, and the app-like behavior is entirely down to F7 owning routing for anything under its view root.
5. **The app Stimulus controller** (`_app_sc`, conventionally named `app` — see the Twig note above) does three things on `initialize()`: constructs `new Framework7({...el: '#app', routes...})`, listens for the `dbready` event dispatched once Dexie has finished its initial sync (see `survos/js-twig-bundle`'s `DbUtilities`) to settle the initial tab/route from the URL hash, and constructs `new DbUtilities(config.projects[configCode], locale)` inside F7's own `init:` callback — this is what actually triggers the Dexie sync for this project's configured `stores`. Copy `framework7-bundle-demo/assets/controllers/app_controller.js`wholesale as your starting point; it's short and every piece in it is load-bearing.

### Known limitation — projects are static config today

[](#known-limitation--projects-are-static-config-today)

Adding a new project means adding a YAML entry and redeploying. That's an accepted stopgap for getting navigation and dynamic rendering working, not the intended end state — a project is just a name, a logo, and a handful of endpoints, and that's a natural fit for a small admin-managed registry (a database table + a simple CRUD UI) instead of static YAML requiring a rebuild per addition. Not built yet; flagging it here so the next person who reaches for `survos_fw.yaml`doesn't assume static config is the permanent design.

Requirement
-----------

[](#requirement)

```
bin/console importmap:require stimulus-attributes
bin/console importmap:require fos-routing
composer req friendsofsymfony/jsrouting-bundle
```

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance98

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity75

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

228

Last Release

12d ago

Major Versions

1.0 → 2.0.72025-09-10

PHP version history (3 changes)1.0PHP ^8.3

2.0.7PHP ^8.4

2.8.2PHP ^8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/21b39551f92ed4143772c622f9e571589c5a72c96ab3c53fe67489ce0d83e806?d=identicon)[tacman1123](/maintainers/tacman1123)

---

Top Contributors

[![tacman](https://avatars.githubusercontent.com/u/619585?v=4)](https://github.com/tacman "tacman (36 commits)")

---

Tags

symfony-ux

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/survos-fw-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/survos-fw-bundle/health.svg)](https://phpackages.com/packages/survos-fw-bundle)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.3M430](/packages/easycorp-easyadmin-bundle)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k6.0M778](/packages/sylius-sylius)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.8M674](/packages/shopware-core)[contao/core-bundle

Contao Open Source CMS

1301.7M3.1k](/packages/contao-core-bundle)[chameleon-system/chameleon-base

The Chameleon System core.

1029.4k6](/packages/chameleon-system-chameleon-base)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
