Skip to content

Commit 1d2480c

Browse files
authored
Symfony postgresql / filsystem bundle (#2335)
* feature: generated bridges skeletons * feature: postgresql symfony cache bridge * feauture: symfony session postgresql brideg * feature: dont resue session/cache connection * chore: cleanup fragile tests, contexts, bundle configs * refactor: unify symfony service id's across all bundles
1 parent 65a48d3 commit 1d2480c

102 files changed

Lines changed: 6443 additions & 146 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codecov.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,26 @@ component_management:
104104
name: bridge-symfony-filesystem-bundle
105105
paths:
106106
- src/bridge/symfony/filesystem-bundle/**
107+
- component_id: bridge-symfony-filesystem-cache
108+
name: bridge-symfony-filesystem-cache
109+
paths:
110+
- src/bridge/symfony/filesystem-cache/**
107111
- component_id: bridge-symfony-postgresql-bundle
108112
name: bridge-symfony-postgresql-bundle
109113
paths:
110114
- src/bridge/symfony/postgresql-bundle/**
115+
- component_id: bridge-symfony-postgresql-cache
116+
name: bridge-symfony-postgresql-cache
117+
paths:
118+
- src/bridge/symfony/postgresql-cache/**
111119
- component_id: bridge-symfony-postgresql-messenger
112120
name: bridge-symfony-postgresql-messenger
113121
paths:
114122
- src/bridge/symfony/postgresql-messenger/**
123+
- component_id: bridge-symfony-postgresql-session
124+
name: bridge-symfony-postgresql-session
125+
paths:
126+
- src/bridge/symfony/postgresql-session/**
115127
- component_id: bridge-symfony-telemetry-bundle
116128
name: bridge-symfony-telemetry-bundle
117129
paths:

.github/workflows/monorepo-split.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,20 @@ jobs:
9494
split_repository: 'psr18-telemetry-bridge'
9595
- local_path: 'src/bridge/symfony/filesystem-bundle'
9696
split_repository: 'symfony-filesystem-bundle'
97+
- local_path: 'src/bridge/symfony/filesystem-cache'
98+
split_repository: 'symfony-filesystem-cache-bridge'
9799
- local_path: 'src/bridge/symfony/http-foundation'
98100
split_repository: 'symfony-http-foundation-bridge'
99101
- local_path: 'src/bridge/symfony/http-foundation-telemetry'
100102
split_repository: 'symfony-http-foundation-telemetry-bridge'
101103
- local_path: 'src/bridge/symfony/postgresql-bundle'
102104
split_repository: 'symfony-postgresql-bundle'
105+
- local_path: 'src/bridge/symfony/postgresql-cache'
106+
split_repository: 'symfony-postgresql-cache-bridge'
103107
- local_path: 'src/bridge/symfony/postgresql-messenger'
104108
split_repository: 'symfony-postgresql-messenger-bridge'
109+
- local_path: 'src/bridge/symfony/postgresql-session'
110+
split_repository: 'symfony-postgresql-session-bridge'
105111
- local_path: 'src/bridge/symfony/telemetry-bundle'
106112
split_repository: 'symfony-telemetry-bundle'
107113
- local_path: 'src/bridge/telemetry/otlp'

composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,13 @@
110110
"flow-php/psr18-telemetry-bridge": "self.version",
111111
"flow-php/snappy": "self.version",
112112
"flow-php/symfony-filesystem-bundle": "self.version",
113+
"flow-php/symfony-filesystem-cache-bridge": "self.version",
113114
"flow-php/symfony-http-foundation-bridge": "self.version",
114115
"flow-php/symfony-http-foundation-telemetry-bridge": "self.version",
115116
"flow-php/symfony-postgresql-bundle": "self.version",
117+
"flow-php/symfony-postgresql-cache-bridge": "self.version",
116118
"flow-php/symfony-postgresql-messenger-bridge": "self.version",
119+
"flow-php/symfony-postgresql-session-bridge": "self.version",
117120
"flow-php/symfony-telemetry-bundle": "self.version",
118121
"flow-php/telemetry": "self.version",
119122
"flow-php/telemetry-otlp-bridge": "self.version",
@@ -150,10 +153,13 @@
150153
"src/bridge/psr7/telemetry/src/Flow",
151154
"src/bridge/psr18/telemetry/src/Flow",
152155
"src/bridge/symfony/filesystem-bundle/src/Flow",
156+
"src/bridge/symfony/filesystem-cache/src/Flow",
153157
"src/bridge/symfony/http-foundation-telemetry/src/Flow",
154158
"src/bridge/symfony/http-foundation/src/Flow",
155159
"src/bridge/symfony/postgresql-bundle/src/Flow",
160+
"src/bridge/symfony/postgresql-cache/src/Flow",
156161
"src/bridge/symfony/postgresql-messenger/src/Flow",
162+
"src/bridge/symfony/postgresql-session/src/Flow",
157163
"src/bridge/symfony/telemetry-bundle/src/Flow",
158164
"src/bridge/telemetry/otlp/src/Flow",
159165
"src/bridge/phpunit/postgresql/src/Flow",
@@ -256,10 +262,13 @@
256262
"src/bridge/psr7/telemetry/tests/Flow",
257263
"src/bridge/psr18/telemetry/tests/Flow",
258264
"src/bridge/symfony/filesystem-bundle/tests/Flow",
265+
"src/bridge/symfony/filesystem-cache/tests/Flow",
259266
"src/bridge/symfony/http-foundation-telemetry/tests/Flow",
260267
"src/bridge/symfony/http-foundation/tests/Flow",
261268
"src/bridge/symfony/postgresql-bundle/tests/Flow",
269+
"src/bridge/symfony/postgresql-cache/tests/Flow",
262270
"src/bridge/symfony/postgresql-messenger/tests/Flow",
271+
"src/bridge/symfony/postgresql-session/tests/Flow",
263272
"src/bridge/symfony/telemetry-bundle/tests/Flow",
264273
"src/bridge/telemetry/otlp/tests/Flow",
265274
"src/bridge/phpunit/postgresql/tests/Flow",
@@ -337,10 +346,13 @@
337346
"@test:bridge:psr7-telemetry",
338347
"@test:bridge:psr18-telemetry",
339348
"@test:bridge:symfony-filesystem-bundle",
349+
"@test:bridge:symfony-filesystem-cache",
340350
"@test:bridge:symfony-http-foundation",
341351
"@test:bridge:symfony-http-foundation-telemetry",
342352
"@test:bridge:symfony-postgresql-bundle",
353+
"@test:bridge:symfony-postgresql-cache",
343354
"@test:bridge:symfony-postgresql-messenger",
355+
"@test:bridge:symfony-postgresql-session",
344356
"@test:bridge:symfony-telemetry-bundle",
345357
"@test:bridge:telemetry-otlp"
346358
],
@@ -438,6 +450,10 @@
438450
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-filesystem-bundle-unit --log-junit ./var/phpunit/logs/bridge-symfony-filesystem-bundle-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-filesystem-bundle-unit.coverage.xml",
439451
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-filesystem-bundle-integration --log-junit ./var/phpunit/logs/bridge-symfony-filesystem-bundle-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-filesystem-bundle-integration.coverage.xml"
440452
],
453+
"test:bridge:symfony-filesystem-cache": [
454+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-filesystem-cache-unit --log-junit ./var/phpunit/logs/bridge-symfony-filesystem-cache-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-filesystem-cache-unit.coverage.xml",
455+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-filesystem-cache-integration --log-junit ./var/phpunit/logs/bridge-symfony-filesystem-cache-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-filesystem-cache-integration.coverage.xml"
456+
],
441457
"test:bridge:symfony-http-foundation": [
442458
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-http-foundation-unit --log-junit ./var/phpunit/logs/bridge-symfony-http-foundation-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-http-foundation-unit.coverage.xml",
443459
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-http-foundation-integration --log-junit ./var/phpunit/logs/bridge-symfony-http-foundation-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-http-foundation-integration.coverage.xml"
@@ -450,10 +466,18 @@
450466
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-bundle-unit --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-bundle-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-bundle-unit.coverage.xml",
451467
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-bundle-integration --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-bundle-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-bundle-integration.coverage.xml"
452468
],
469+
"test:bridge:symfony-postgresql-cache": [
470+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-cache-unit --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-cache-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-cache-unit.coverage.xml",
471+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-cache-integration --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-cache-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-cache-integration.coverage.xml"
472+
],
453473
"test:bridge:symfony-postgresql-messenger": [
454474
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-messenger-unit --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-messenger-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-messenger-unit.coverage.xml",
455475
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-messenger-integration --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-messenger-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-messenger-integration.coverage.xml"
456476
],
477+
"test:bridge:symfony-postgresql-session": [
478+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-session-unit --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-session-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-session-unit.coverage.xml",
479+
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-postgresql-session-integration --log-junit ./var/phpunit/logs/bridge-symfony-postgresql-session-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-postgresql-session-integration.coverage.xml"
480+
],
457481
"test:bridge:symfony-telemetry-bundle": [
458482
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-telemetry-bundle-unit --log-junit ./var/phpunit/logs/bridge-symfony-telemetry-bundle-unit.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-telemetry-bundle-unit.coverage.xml",
459483
"tools/phpunit/vendor/bin/phpunit --testsuite=bridge-symfony-telemetry-bundle-integration --log-junit ./var/phpunit/logs/bridge-symfony-telemetry-bundle-integration.junit.xml --coverage-clover=./var/phpunit/coverage/clover/bridge-symfony-telemetry-bundle-integration.coverage.xml"

documentation/components/bridges/symfony-filesystem-bundle.md

Lines changed: 120 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ This bundle integrates Flow PHP's Filesystem library with Symfony applications.
3232
- **Pluggable filesystem factories** — register custom backends with the `#[AsFilesystemFactory]` attribute or a DI tag
3333
- **Built-in factories**`file`, `memory`, `stdout`, `aws_s3`, and `azure_blob` ship out of the box
3434
- **Console commands**`flow:filesystem:*` (alias `flow:fs:*`) for `ls`, `cat`, `cp`, `mv`, `rm`, `stat`, `touch` against any configured filesystem
35+
- **Symfony Cache pools** — register PSR-6 cache pools backed by any mounted filesystem (local disk, S3, Azure Blob …) when [flow-php/symfony-filesystem-cache-bridge](/documentation/components/bridges/symfony-filesystem-cache-bridge.md) is installed
3536
- **Telemetry integration** — wrap every filesystem in `TraceableFilesystem` via OpenTelemetry
3637
- **Multi-fstab support** *(advanced)* — configure several independent `FilesystemTable` services when you really need them
3738

@@ -119,7 +120,7 @@ flow_filesystem:
119120
client_service_id: app.s3_client
120121
```
121122

122-
The fstab is wired as a private `.flow_filesystem.fstab.<name>` service and aliased to
123+
The fstab is wired as a private `.flow.filesystem.fstab.<name>` service and aliased to
123124
`Flow\Filesystem\FilesystemTable` for autowiring.
124125

125126
### Default Fstab
@@ -393,6 +394,119 @@ Remote object stores (S3, Azure Blob, …) do not have a real concept of directo
393394
keyspaces with `/` as a convention. Rather than emulate `mkdir` inconsistently across backends, the bundle
394395
omits the command entirely. Directories appear when files appear inside them.
395396

397+
## Symfony Cache Integration
398+
399+
The bundle integrates with [flow-php/symfony-filesystem-cache-bridge](/documentation/components/bridges/symfony-filesystem-cache-bridge.md) to provide PSR-6 / Symfony Cache pools backed by any filesystem already mounted in a fstab — local disk, S3, Azure Blob, anything the bundle's factories can build. The adapter implements `PruneableInterface`, so `cache:pool:prune` works out of the box.
400+
401+
Each pool resolves its filesystem **through a fstab mount**, not by referencing a service id directly. Filesystems must already be declared under `flow_filesystem.fstabs.<fstab>.filesystems.<protocol>` before a cache pool can target them. This keeps fstab the single place where filesystems live and avoids the cache and the rest of the app drifting into separate filesystem definitions.
402+
403+
### Setup
404+
405+
1. Install the cache bridge:
406+
407+
```bash
408+
composer require flow-php/symfony-filesystem-cache-bridge:~--FLOW_PHP_VERSION--
409+
```
410+
411+
2. Define one or more pools under `flow_filesystem.cache.pools`. Each pool names a fstab mount (the YAML key under `filesystems:`) and a base path inside it:
412+
413+
```yaml
414+
# config/packages/flow_filesystem.yaml
415+
flow_filesystem:
416+
fstabs:
417+
default:
418+
filesystems:
419+
file:
420+
type: file
421+
422+
cache:
423+
pools:
424+
app:
425+
filesystem: file # mount protocol from the default fstab
426+
path: '%kernel.project_dir%/var/cache/flow/app'
427+
default_lifetime: 3600
428+
429+
sessions:
430+
filesystem: file
431+
path: '%kernel.project_dir%/var/cache/flow/sessions'
432+
namespace: 'sess.'
433+
default_lifetime: 86400
434+
```
435+
436+
`fstab` is optional and defaults to the bundle's resolved default fstab — same rule the `flow:filesystem:*` CLI commands follow. Set it explicitly when you want a pool to use a non-default fstab:
437+
438+
```yaml
439+
flow_filesystem:
440+
default_fstab: primary
441+
fstabs:
442+
primary:
443+
filesystems:
444+
file:
445+
type: file
446+
archive:
447+
filesystems:
448+
aws-s3:
449+
type: aws_s3
450+
bucket: '%env(ARCHIVE_BUCKET)%'
451+
452+
cache:
453+
pools:
454+
cold_storage:
455+
fstab: archive
456+
filesystem: aws-s3
457+
path: '/cache/cold'
458+
default_lifetime: 86400
459+
```
460+
461+
Each pool registers as `flow.filesystem.cache.pool.<name>` (public).
462+
463+
3. Wire the pools into Symfony's cache framework via `cache.adapter.psr6`:
464+
465+
```yaml
466+
# config/packages/framework.yaml
467+
framework:
468+
cache:
469+
pools:
470+
cache.app_fs:
471+
adapter: cache.adapter.psr6
472+
provider: flow.filesystem.cache.pool.app
473+
474+
cache.sessions_fs:
475+
adapter: cache.adapter.psr6
476+
provider: flow.filesystem.cache.pool.sessions
477+
```
478+
479+
The `cache.adapter.psr6` wrapper is required because Symfony's `CachePoolPass` overwrites the first constructor argument of any service used directly as `adapter:`, which conflicts with this bridge's strict `Filesystem` typing on argument 0.
480+
481+
### Configuration Options (per pool)
482+
483+
| Option | Default | Description |
484+
|--------------------------|----------------|--------------------------------------------------------------------------------------------------------|
485+
| `fstab` | default fstab | Fstab name. Defaults to the bundle's resolved default fstab when omitted. |
486+
| `filesystem` | *required* | Mount protocol within the chosen fstab (the YAML key under `filesystems:`). |
487+
| `path` | *required* | Base directory inside the chosen filesystem where cache files are stored. |
488+
| `namespace` | `''` | Cache pool namespace; chars in `[-+.A-Za-z0-9]` only. |
489+
| `default_lifetime` | `0` | Default TTL in seconds; `0` means no expiry. |
490+
| `marshaller_service_id` | `null` | Service ID of a custom `MarshallerInterface`. |
491+
492+
Validation runs at container compile time:
493+
494+
- A pool referencing a missing fstab fails with `flow_filesystem.cache.pools.<name>: fstab "<x>" is not declared. Available fstabs: [...]`.
495+
- A pool referencing a mount protocol that is not registered in the chosen fstab fails with `flow_filesystem.cache.pools.<name>: filesystem "<x>" is not mounted in fstab "<y>". Available mounts: [...]`.
496+
- `flow_filesystem.cache.pools` is configured but `flow-php/symfony-filesystem-cache-bridge` is not installed → fails fast with a message pointing at the missing package.
497+
498+
### Pruning
499+
500+
Schedule the standard Symfony command on a cron to remove expired files:
501+
502+
```bash
503+
php bin/console cache:pool:prune
504+
```
505+
506+
Without pruning, expired files accumulate under each pool's directory. They are filtered out on read but only deleted when either the same key is fetched again or `cache:pool:prune` runs.
507+
508+
For full documentation, see the [Symfony Filesystem Cache Bridge](/documentation/components/bridges/symfony-filesystem-cache-bridge.md).
509+
396510
## Multi-Fstab Support
397511

398512
> **Advanced.** Most applications should stick to a single fstab with multiple filesystems mounted under
@@ -425,7 +539,7 @@ flow_filesystem:
425539
bucket: '%env(ARCHIVE_BUCKET)%'
426540
```
427541

428-
Each fstab gets its own `.flow_filesystem.fstab.<name>` service. The default fstab is automatically aliased
542+
Each fstab gets its own `.flow.filesystem.fstab.<name>` service. The default fstab is automatically aliased
429543
to `Flow\Filesystem\FilesystemTable`, allowing direct type-hint injection without specifying a fstab name.
430544
Each named fstab is also aliased as `Flow\Filesystem\FilesystemTable $<camelCasedName>Fstab` for
431545
named-argument autowiring:
@@ -507,7 +621,7 @@ final class MyFilesystemFactory implements FilesystemFactory
507621
```
508622

509623
As long as your service is autoconfigured (the default in `services.yaml` for everything under your `App\`
510-
namespace), the bundle automatically attaches the `flow_filesystem.factory` tag with the right `type`
624+
namespace), the bundle automatically attaches the `flow.filesystem.factory` tag with the right `type`
511625
attribute.
512626

513627
### Explicit Tag
@@ -517,10 +631,10 @@ namespaces, manual definitions):
517631

518632
```yaml
519633
services:
520-
app.flow_filesystem.factory.my_backend:
634+
app.flow.filesystem.factory.my_backend:
521635
class: App\Flow\MyFilesystemFactory
522636
tags:
523-
- { name: flow_filesystem.factory, type: my_backend }
637+
- { name: flow.filesystem.factory, type: my_backend }
524638
```
525639
526640
Either way, you can then mount the backend under any protocol in any fstab:
@@ -551,7 +665,7 @@ flow_filesystem:
551665
- **Mount-protocol routing:** filesystems inside a fstab are resolved at runtime via
552666
`$table->for('warehouse')` / `$table->for($path)`, so application code can hand-off across protocols
553667
without knowing service ids.
554-
- **Factory tag:** filesystem types are pluggable via a standard `flow_filesystem.factory` DI tag;
668+
- **Factory tag:** filesystem types are pluggable via a standard `flow.filesystem.factory` DI tag;
555669
third-party libraries can ship their own factory without bundle changes.
556670
- **CLI commands:** `flow:filesystem:*` ship with the bundle and operate on any configured fstab.
557671
Flysystem Bundle does not ship any console commands.

0 commit comments

Comments
 (0)