Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Vendra Multimedia Api Laravel Package

misaf/vendra-multimedia-api

A Laravel/PHP package that wraps the Vendra multimedia API in a simple integration layer, helping developers fetch and manage multimedia resources with less boilerplate. It provides a convenient way to add Vendra multimedia support to Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Understand what you're actually installing. Despite the description's talk of "uploading" and "custom storage and response formats," the package as documented is the read-only API Platform layer for misaf/vendra-multimedia. It exposes Multimedia domain models as JSON:API-ish HTTP resources. Uploads, transformations, and storage live in the sibling domain package misaf/vendra-multimedia — not here. Plan your day-to-day work accordingly: this is a consumption surface, not an ingestion pipeline.

Install. This is a subtree split of the Vendra monorepo, published read-only. You do not PR here; changes go to misaf/vendra and get split out. Pin explicitly:

composer require misaf/vendra-multimedia-api:^1.12.3

It is designed to run inside a Vendra host application, not as a standalone Laravel package. The module's service provider registers src/ApiResource into api-platform.resources and tags its state providers as ProviderInterface; API Platform generates the routes from the resource operations. There are no route files to publish — and you should not add any.

Where to look first, in order:

  1. composer.json — the real dependency contract, including which Vendra platform packages are transitively exposed.
  2. src/ApiResource/MultimediaResource.php — the public contract. A final readonly DTO annotated with #[ApiResource], declaring Get/GetCollection with explicit uriTemplate paths and a provider.
  3. src/State/ — the links handler (e.g. MultimediaLinksHandler) and the mapper (e.g. MultimediaMapper). All Eloquent querying, hydration, filtering, and pagination happens here.
  4. The module ServiceProvider — bootstrapping is deliberately minimal; read it once and you know the whole wiring.
  5. tests/ including tests/ArchTest.php — the architecture rules are encoded as tests, which is the fastest way to learn what you must not do.

First use case. Hit GET /content/multimedia with pagination and a filter, then GET /content/multimedia/{id}. Confirm the shortName and URI path (/content/multimedia, kebab-case) against the DTO before you write any client code — these are the contract, and they are stable only because the tests enforce it.

Implementation Patterns

Consuming it from a front end or mobile client. The DTO is the contract. Treat it as such:

  • Translated columns (title, description) come back as array<string, string> locale maps, not scalars. Your client-side deserializer must handle a map, and your UI picks a locale or falls back.
  • Raw foreign keys and internal columns are deliberately not on the DTO. If you need a join, look for a ResourceReference rather than expecting an embedded foreign model. Related resources are referenced, not inlined.
  • Public media URLs are returned relative to the API origin. If your front end runs on a different host, you resolve them client-side against the API base URL. Do not assume absolute URLs.

Adding a query parameter. This is the most common day-to-day change and it has a fixed three-part shape:

  1. Declare it on the resource operation as a QueryParameter with an API Platform filter (EqualsFilter, BooleanFilter, …) and Laravel constraints.
  2. Set the parameter's property to the model column the state provider will filter on.
  3. Apply the declared parameter inside the state provider when building the Eloquent query.

Doing 1 and 2 without 3 produces a parameter that is documented but silently ignored — the classic failure mode here.

Translated-column filters. Filter on the active-locale JSON path, not the bare column. WHERE title = ? against a JSON column will not do what you want. The provider reads Laravel's current locale, so the host app can resolve locale however it likes — the module stays localization-package agnostic, and you should keep it that way.

Adding an exposed field. Touch three places: the DTO property (with an explicit type), the mapper that serializes it, and a test asserting the shape. If the field is translatable, it must be in the model's $translatable array and backed by a JSON column — and then the DTO type is array<string, string>. If it is not in $translatable, it must be a scalar column with a scalar DTO type. Do not half-translate a field.

Adding a mutation. Resist it. Resources are read-only unless a write is an explicit product decision. If you genuinely need one, that decision belongs in the domain package with the persistence rules, and the API module only surfaces it.

Testing workflow. From the host app:

php artisan test --compact --testsuite=vendra-multimedia-api
composer stan
vendor/bin/pint --dirty --format agent   # only if PHP files changed

Add tests for every new operation, query parameter, and any change to resource shape, shortName, or URI path. Keep the Pest arch presets in tests/ArchTest.php intact, including the expectation that the module does not use Misaf\VendraTenant. If you're changing Blade markup, the Tailwind skill applies; otherwise leave front-end concerns out of this package entirely.

Isolating yourself as a consumer. If your app depends on this API, put your own client/gateway interface in front of it and write contract tests against your interface, not against the package's internals. Single-maintainer namespace, thin release notes, no SLA — the adapter boundary is what keeps a future swap or a direct-HTTP fallback a container rebinding rather than a refactor.

Gotchas and Tips

tenant_id must be in the selected columns for public media URLs. This is the single most likely source of a subtle production bug: URLs render for some records and come back broken or unscoped for others, and it only reproduces once real multi-tenant data exists. If you change the provider's select, you can break URL generation without breaking the response shape. Test it with a tenant-scoped fixture.

Do not add tenancy to this module. Production API code must be tenant-provider agnostic — inherit tenancy from the domain models. No API tenant toggle, no Misaf\VendraTenant references in resources, state providers, or query parameters. Feature tests may use a concrete tenant factory purely to establish context; that exception is for tests only, and ArchTest.php enforces it.

Keep shortName and URI paths stable. Renaming content/multimedia or its shortName is a breaking change for every consumer, even though the package version won't say so. Add a test whenever they change, and treat any such change as a coordinated release.

Filters can be documented and inert. See above — declaration and application are separate steps in separate files. When a filter "doesn't work," check the state provider before you check the annotation.

Translatable vs. scalar is a domain decision, not a convenience. A field in $translatable must be JSON-columned end to end: model traits/casts, factories, validation, Filament locale UI (in the domain package), API serialization, and tests. A field not in $translatable must be scalar and must not pick up Spatie Translatable, translatable slug traits, locale switchers, or translation-shaped array data. Mixed state here produces data that serializes fine and queries wrong.

The description over-promises. "Uploading," "custom storage," and "extensible response formats" are not what the code does. Scope estimates off the source and the skill doc, not the README blurb. If you were brought in expecting an upload endpoint, that work lives in the domain package or doesn't exist yet.

Respect the Vendra transitive API policy. A Vendra dependency intentionally exposed through the public API of a directly required platform package is part of that package's supported contract — do not add a redundant direct composer.json requirement just because you import a type from it. This applies only to Vendra platform packages under require, never to require-dev, suggest, incidental implementation deps, or third-party packages. And keep self.version aligned across the Vendra package graph; skew between sibling modules is a nasty, non-obvious class of failure.

Don't hand-register routes for resource endpoints. Routes come from API Platform resource operations. A manually registered route will shadow or duplicate the generated one and the failure looks like a routing bug rather than a config bug.

No Filament or admin UI in this module. Keep API resource DTOs, state providers, query parameters, service providers, and API tests here; import domain models from Misaf\VendraMultimedia rather than duplicating them. When in doubt about whether something belongs, the arch tests are the arbiter.

Release notes carry no information. v1.12.3 publishes a bare auto-generated compare link. Before upgrading across minors (v1.10.0 → v1.12.3 is two of them), read the diff yourself and specifically check for signature changes on public methods, config key renames, and exception type changes — the three categories that break a wrapper even within semver. Schedule it as routine maintenance, but do not merge on the assumption that "minor means additive."

Debugging checklist, in order: is the parameter applied in the state provider? is tenant_id selected? is the filter hitting the active-locale JSON path? is the field actually in $translatable and JSON-columned? is the URL relative and being resolved client-side? Ninety percent of "the API is wrong" reports land in one of those five.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect