modufolio / media
Album and media management for Appkit portfolio sites: nested-set albums, the media library, upload processing and the album integrity triggers (SQLite, MySQL, PostgreSQL, SQL Server).
Requires
- php: >=8.4
- claviska/simpleimage: ^4.0
- doctrine/orm: ^3.0
- kornrunner/blurhash: ^1.2
- modufolio/appkit: ^0.20
- ramsey/uuid: ^4.0
- ramsey/uuid-doctrine: ^2.0
- symfony/validator: ^7.0
Requires (Dev)
- phpstan/phpstan: ^2.2
- phpstan/phpstan-doctrine: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-09-14 11:28:01 UTC
README
Album and media management for Appkit portfolio sites: nested-set albums, the media library, upload processing (slugging, sharding, downscaling, blurhash, checksums) and the triggers that guard album integrity — on SQLite, MySQL, PostgreSQL and SQL Server.
What the application provides
The package names no application classes. Four small contracts cover the seams:
| Contract | The app wires |
|---|---|
UploaderInterface |
its user entity, via Doctrine's ResolveTargetEntityListener in config/doctrine.php |
AlbumTreeInterface |
nothing — AlbumRepository implements it; site code duck-checks it when walking the album tree as pages |
MediaJobsInterface |
its image-job repository, so deleting media retires processing jobs |
FocusStoreInterface |
(optional) where analysed focus/saliency features land — the autofocus pipeline's entity stays app-side |
Tag-slug filters (tag:<slug>) resolve through
MediaRepository::useTagEntity(App\Entity\Tag::class), called once at boot —
tags are polymorphic app-level data this package cannot name.
Wiring
// composer require modufolio/media // config/doctrine.php $orm->entities($projectDir . '/src/Entity', $projectDir . '/vendor/modufolio/media/src/Entity') ->addSubscriber($resolveTargetListener); // UploaderInterface => App\Entity\User // config/repositories.php maps the package repositories to the package entities.
AlbumTriggerAdapterFactory::forPlatform($connection->getDatabasePlatform())->install()
must run against every database the entities live in — apply via a migration
in the app (and in test bootstraps).
Each engine's rules live in their own AlbumTriggerAdapterInterface
implementation (src/Database/Trigger/) — see
AlbumTriggerAdapterInterface
for what an adapter is responsible for and why MySQL's differs structurally
from the other three (a MySQL trigger can't modify the table that fired it).
AlbumModel/MediaModel resolve the right adapter from the entity
manager's connection and go through it — repositionMedia(),
removeMediaEverywhere() — rather than relying on raw SQL or FK cascades,
so application behaviour is identical across engines.
Tests
composer install && vendor/bin/phpunit
Runs against an in-memory SQLite database by default. CI also runs the suite
against real MySQL, PostgreSQL and SQL Server instances on every push; see
docker-compose.yml to reproduce that locally.
Requirements
- PHP 8.4 or later
- Composer
- An Appkit application, for the
entity manager, the
UploaderInterface/AlbumTreeInterface/MediaJobsInterfacecontracts it resolves, and (optionally)FocusStoreInterface - Extensions:
curl,dom,exif,fileinfo,gd,intl,libxml,pdo,simplexml,sqlite3,zip
See composer.json for the canonical dependency list.
License
MIT. See LICENSE.