Download the PHP package survos/media-bundle without Composer

On this page you can find all versions of the php package survos/media-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package media-bundle

Survos Media Bundle

A client for mediary, the central media server — not a general-purpose media manager. An application installs this bundle to register the images it knows about, hand them to mediary, and receive back what mediary learned. mediary owns the binaries, the S3 archive, the AI, and the canonical URLs; the application owns only its own rows.

Renaming. The package is scheduled to be renamed survos/mediary-bundle, which is what it has actually been for a while. The name media-bundle predates the split and reads like generic media management, which is the one thing this is not.

This mirrors babel-bundle ↔ lingua-server: applications own their tables, a central service owns the heavy lifting.


Two encodings, and they are not the same thing

This trips people up, so it is spelled out. There are two derivations from a URL, both live, both deliberate.

1. The imgproxy-style key — reversible

URL-safe base64: base64_encode, then +/ → -_, then padding stripped. This is the same philosophy imgproxy uses, and it is reversible on purpose — a resize URL carries its own source, so no lookup is needed to render one. MediaUrlGenerator::resize() uses it whenever it is handed a bare URL string rather than a Media row.

2. The asset id — not reversible

xxh3 of the trimmed URL. This is Media::$id and mediary's Asset::$id — the primary key both sides agree on. Fixed width, so it is safe in a column, a Meilisearch id, and a directory name; the URL is not recoverable from it, and nothing should try.

MediaKeyService::archivePathFromKey() uses both: it hashes the key to pick a bucket, then stores the key itself as the filename — o/<1 hex>/<2 hex>/<key>.<ext>, so the stored path is still reversible to the source URL. Note the bucket split is one char then two (16 × 256), not the symmetric aa/bb the name suggests.

This is not the layout mediary uses for archived originals, which are orig/<2>/<2>/<long hex>.<ext>. Two different schemes; don't assume one function produces the other.

The MediaRegistry::idFromUrl() example that used to head this README does not exist — the method was never added or was removed. tests/Service/MediaRegistryTest.php:75 still calls it.

Why both live in data-contracts

mediary computes the same values from the same URL without depending on this bundle, and this bundle computes them without depending on mediary. Two copies of either algorithm would be free to drift, and a drift looks like "mediary answered about an image we never asked about."

Same rule for the preset names (MediaPreset), the batch payload shape (BatchPayloadDto / BatchItemDto), and the sync protocol keys (MediaSyncKeys).

Why it matters


The Media workflow — how rows actually reach mediary

This is the supported path. Registering a Media row is the only manual step.

BaseMedia carries a marking, and the app declares a workflow for it:

An empty body is the normal case — you inherit new → dispatch → dispatched → sync → synced (plus failed). MediaWorkflowDefinition deliberately carries no #[AsWorkflow] attribute, so the base never self-registers; the app decides. An app that needs its own steps redeclares just the constant it wants to re-point (ssai, for instance, gives PLACE_NEW a next that runs triage before dispatch), and gets application-specific behaviour without forking the definition.

PLACE_NEW declares next: [TRANSITION_DISPATCH], so workflow-extras' WorkflowKickoffListener queues the dispatch on postFlush. Persist a row and the rest runs unattended:

supports is BaseMedia rather than Photo so Video and Audio get the same lifecycle; Symfony matches by instanceof and the marking lives on the base.

Requires Symfony 8.2, workflow-extras, and workflow-messenger. State-bundle is no longer required. The persisted marking remains the same nullable string column, with the same new, dispatched, synced, and failed values. Remote status is still independent.

Configure the queue explicitly (choose the transport appropriate to the application):

Enable native attribute discovery with workflow: ~. Consume media.dispatch to process newly persisted media. Application-specific dispatch listeners still perform the actual Mediary request; this definition supplies the lifecycle, not an HTTP client side effect. Menus use AsMenuListener(MenuSlot::ADMIN_NAVBAR_MENU) when Tabler is installed.

What this replaces

media:ensure + media:sync, where "which media still needs pushing" was a WHERE status='new' scan and a foreground batch loop. Those commands remain for one-off debugging (media:sync --url=… to push a single image through), but a pipeline that calls them is doing it the old way.


Registering media


Receiving mediary's callback

mediary POSTs a signed asset.analyzed webhook to /webhook/mediary when an image finishes analysis. This bundle supplies the two pieces that belong to it — a request parser (Survos\MediaBundle\Webhook\MediaWebhookRequestParser) and a consumer that calls MediaUpdateApplier. It contributes no route and no controller; the endpoint is FrameworkBundle's own.

Set MEDIARY_WEBHOOK_SECRET to the same value mediary signs with, and point MEDIA_CALLBACK_URL at https://your-app/webhook/mediary.

To react to updates, listen for MediaUpdatedEvent — mediary never learns your entity shape.

Run a consumer for that transport. A queued callback that nobody consumes looks exactly like a mediary that never answered: rows stay at their pre-callback status indefinitely, with the evidence sitting in a queue table rather than in a log.

Full contract, including how to run several webhooks on separate queues: kit-bundle/docs/webhooks.md.

Replaced the unauthenticated MediaCallbackController at /media/callback, where anyone who could reach the URL could rewrite a media row. See survos-sites/mediary#8.


AI-task sidecars (SidecarClient)

Cached AI-task results are read and written through mediary, over JSON-RPC:

SidecarService used to live here and be injected directly, which made every client a second writer into mediary's bucket namespace — its own S3 credentials, its own copy of the path convention, its own idea of when a sidecar was stale. That is the same shape as an app keeping a Media table beside mediary's Asset: two owners of one thing, each free to drift. The service now lives in mediary behind sidecarGet / sidecarPut, so caching, batching or a Redis layer can appear there without any client changing.

Two deliberate exceptions:


Probing mediary (polling fallback)

When webhooks are unavailable — a local dev tunnel is down, say — poll mediary directly:

Both go through JSON-RPC probeAssets on POST /api/v1, and both need MEDIARY_API_TOKEN to match mediary's.

They used to call GET /fetch/media/{id} and POST /fetch/media/by-ids, which no API client could reach. mediary's security.yaml grants PUBLIC_ACCESS to only ^/[^/]+/batch$, ^/api/v1$ and ^/api/claim-store/; everything else falls through - { path: ^/, roles: ROLE_USER } and 302s to /login. That failed in the least legible way possible — Symfony's HttpClient follows redirects, so the call returned 200 with the login page's HTML and threw inside toArray() as a JSON parse error, which looks like mediary sent garbage rather than like the client was never admitted.

/api/v1 is public at the firewall precisely so unauthenticated clients can reach it, with each method authenticating on a token in its params. Same rows either way: mediary serves both transports from one AssetProbeService.

The payload includes mediary's workflow state (marking), variants/thumb URLs, metadata, and any OCR/AI context written so far.

Recovering rows whose callback never arrived

When the webhook could not be delivered at all — the laptop was off, podman was not started after a reboot, the tunnel moved — mediary's retries end in its failed transport and the local row keeps whatever status it last heard. media:reconcile probes those rows and applies the answer through the same applier the callback uses:

Recovery only, not a scheduled job. See docs/reconcile.md.


Publishing claims to mediary

Apps run AI with survos/ai-workflow-bundle and store tracked metadata as claims. Publishing sends the image plus selected source/AI/human claims to mediary, while mediary stays responsible for global media access and canonical image URLs. See docs/publishing.md.


Optional dependencies

survos/tabler-bundle is a suggest, not a require. MediaMenuSubscriber and the search/UI templates are registered only when TablerBundle is present, so a headless or CLI-only client — a consumer that does nothing but register rows and drain queues — needs no theme.


What this bundle does not do

Those belong to mediary and imgproxy.


Status

Known rough edges, recorded rather than hidden:


All versions of media-bundle with dependencies

PHP Build Version
Package Version
Requires php Version ^8.5
doctrine/dbal Version ^4.3.2
doctrine/doctrine-bundle Version ^3.0
league/flysystem Version ^3.0
survos/data-contracts Version ^2.27.1
survos/field-bundle Version ^2.5
survos/iiif-bundle Version ^2.7
survos/imgproxy-bundle Version ^2.28.6
survos/kit-bundle Version ^2.5
symfony/config Version 8.2.*@dev
symfony/dependency-injection Version 8.2.*@dev
symfony/http-kernel Version 8.2.*@dev
symfony/messenger Version 8.2.*@dev
symfony/remote-event Version 8.2.*@dev
symfony/ux-twig-component Version ^3.0
symfony/webhook Version 8.2.*@dev
twig/twig Version ^3.4|^4.0
survos/workflow-extras-bundle Version ^2.42.8
survos/workflow-messenger-bundle Version ^2.42.9
survos/menu-bundle Version ^2.42.7
symfony/workflow Version 8.2.*@dev
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package survos/media-bundle contains the following files

Loading the files please wait ...