API Reference

Auto-gegenereerd via Reflection — blijft altijd in sync met src/.

Filter: alleAppCacheCmsDbDebugDynamicEventsFilesFormHtmlHttpImageLogMediaSecuritySessionStdlibSupportView

AbstractSource

Framework\Media\AbstractSource
abstract class

Abstract base voor alle media-bronnen. Subclasses
(`Source\Image`, `Source\Video`, `Source\YouTube`, `Source\Vimeo`) weten hoe
je hun URL embed't en welke HTML-attrs relevant zijn voor hun type. De main
`Renderer` orchestreert ze; per-type detail leeft binnen de subclass — geen
centrale type-match.

Constructor blijft compatibel: alle subclasses accepteren `url`, optioneel
`width` en `height`. URL-validatie is **lazy** — een `Source\YouTube` met
een onparsebare URL gooit niet bij constructie maar bij `videoId()` (of
geeft null terug). CMS-content is soms placeholder; we vallen niet om.

Naamgeving: project-conventie is `Abstract`-prefix voor base-classes
waarvan je niet zelf een instance maakt.

__construct(string $url, ?int $width = NULL, ?int $height = NULL)
2 public methods
isEmpty(): bool
render(\Variant $variant, \RenderOptions $options): \El

Render deze bron als inner-element (`<img>`, `<video>`, `<iframe>`, …).
De main Renderer wrapt 'm vervolgens in z'n variant-container met
overlay/play-button/aspect-ratio. Variant geeft toegang tot
posterUrl/overlayUrl/hoverUrl en variant-specifieke options.

Breakpoints

Framework\Media\Breakpoints
final class

Bekende variant-keys met hun default CSS media-query.

Een `Variant` heeft een optionele `when:` (eigen CSS media query string).
Is die null en is de variant-key bekend, dan wordt de default uit deze tabel
gebruikt. Onbekende keys zonder eigen `when:` matchen nooit — dat dwingt
callers om voor custom-keys (bv. `'compact'`) expliciet een query mee te
geven.

`desktop` is hier expliciet een variant zoals elke andere (geen impliciete
"altijd zichtbaar"-default). Dat voorkomt het 769–1024px gat waarin een
desktop-video per ongeluk op tablet zou kunnen lekken.

2 public methods
static knownKeys(): array
static resolve(string $key, ?string $when): ?string

Geeft de effectieve CSS media-query voor een variant.
Eigen `$when` wint; anders fallback op {@see self::DEFAULTS}; anders null.

Decoder

Framework\Media\Decoder
final class

Mixed input → `Media`.

Eén plek waar alle alias-mapping uit legacy CMS-content gebeurt.
`Decoder::decode()` accepteert:
- `null` of `''` → lege Media (geen variants)
- `string` JSON → decoded en doorgereikt
- `string` URL → image (of video/youtube/vimeo via auto-detect),
onder `variants['desktop']`
- `array` / `object` → key-mapping (zie hieronder)
- `Media` → as-is (idempotent)

Geaccepteerde keys** (snake_case én camelCase, eerste match wint):
type 'image'|'video'|'youtube'|'vimeo'
src / image / image_src
image_mobile / imageMobile
video / youtube / vimeo
width / height
poster / video_poster / videoPoster
overlay / overlay_url
hover / hover_url
desktop, mobile, tablet, dark, print, ... genest object (variant-shorthand)

Variant-shorthand**: zodra de input minimaal één breakpoint-key bevat
(een key die in `Breakpoints::DEFAULTS` staat), worden die keys
recursief gedecoded en geplaatst onder `Media::variants[<key>]`.

Platte input** (zonder breakpoint-keys) wordt geplaatst onder
`variants['desktop']` — desktop is gewoon een eersterangs variant zoals
elke andere, geen impliciete fallback.

1 public method
static decode(?mixed $input): \Media

DisplayMode

Framework\Media\DisplayMode
enum

Hoe de media past binnen z'n container.

- Fit: proportioneel binnen de container, hele beeld zichtbaar (`object-fit: contain`)
- Cover: vult de container, kan croppen (`object-fit: cover`)
- Resize: fysiek geresized naar exacte width/height (server-side url-transform; alleen
bruikbaar via een MediaTransformer — anders gedraagt 'ie zich als Cover)

3 public methods
static cases(): array
static from(string|int $value): static
static tryFrom(string|int $value): ?static
Cases: Fit, Cover, Resize

Media

Framework\Media\Media
final class

Een set `Variant`s die samen "de media" vormen voor één content-item.

Een Media heeft N variants, elk gekoppeld aan een breakpoint-key:
`'desktop'`, `'mobile'`, `'tablet'`, `'dark'`, `'print'`, of een custom
key zoals `'compact'`. De Renderer toont per viewport/context één variant
via een scoped `<style>`-block dat z'n CSS media queries genereert uit
`Variant::$when` (of `Breakpoints::DEFAULTS` voor bekende keys).

Callers werken zelden direct met `Variant` — bijna alles loopt via
`Media::from()` (decoder) en `Media::render()` (decode + render in één call).

echo Media::render($cmsRow, width: 1600, aspectRatio: '16/9');

$media = Media::from($cmsRow);
echo $media->render(width: 800); // instance helper
echo $media->getVariant('mobile')?->source->url;

Manuele constructie blijft beschikbaar voor volledige controle:

use Framework\Media\Source\{Image, Video};

$media = new Media([
'desktop' => new Variant(new Video('/promo.mp4')),
'mobile' => new Variant(new Image('/hero-mobile.jpg')),
'dark' => new Variant(new Image('/hero-dark.jpg')),
]);

Readonly value-object — geen mutators in v1. Als je variants moet kunnen
uitbreiden na constructie, voegen we later `withVariant()` toe.

__construct(array $variants = array ( ))
7 public methods
static element(?mixed $input, ?int $width = NULL, ?int $height = NULL, \DisplayMode|string|null $mode = NULL, ?string $aspectRatio = NULL, \PosterMode|string $poster = \Framework\Media\PosterMode::Default, ?string $posterUrl = NULL, bool $showPlayButton = false, bool $autoplay = false, bool $loop = false, bool $controls = true, bool $muted = true, bool $lazy = true, ?string $fetchPriority = NULL, ?string $alt = NULL, ?string $cssClass = NULL): \El

Zoals `render()` maar returnt het `El`-object zodat caller er nog op
kan doorbouwen.

static from(?mixed $input): self

Decode mixed input (string URL / JSON / array / object / Media) naar
een Media. Zie {@see Decoder::decode()} voor de geaccepteerde shapes.

getDefaultVariant(): ?\Variant

Eén variant terug die "altijd" zichtbaar zou moeten zijn — handig voor
fallback-rendering, og-image-extractie, alt-text, etc.

Strategie: 'desktop' wint, anders eerste niet-lege variant, anders null.

getVariant(string $key): ?\Variant
hasVariant(string $key): bool
isEmpty(): bool
static render(?mixed $input, ?int $width = NULL, ?int $height = NULL, \DisplayMode|string|null $mode = NULL, ?string $aspectRatio = NULL, \PosterMode|string $poster = \Framework\Media\PosterMode::Default, ?string $posterUrl = NULL, bool $showPlayButton = false, bool $autoplay = false, bool $loop = false, bool $controls = true, bool $muted = true, bool $lazy = true, ?string $fetchPriority = NULL, ?string $alt = NULL, ?string $cssClass = NULL): string

Convenience: decode + render in één call. De named args mappen 1-op-1
op `RenderOptions`. Voor cross-type/per-variant overrides bouw je een
`Media` expliciet en roep je `$media->render(...)` aan.

echo Media::render($cmsRow,
width: 1600, height: 600, mode: 'cover', aspectRatio: '16/9',
autoplay: true, muted: true, poster: 'thumbnail',
);

PosterMode

Framework\Media\PosterMode
enum

Hoe de Renderer een poster (placeholder) bepaalt voor een video-source.

- None: géén poster — `<video>` toont de eerste frame zelf
- Default: gebruik wat op `MediaItem::$poster` gezet is (anders fallback per type)
- Thumbnail: forceer auto-thumbnail (YouTube hqdefault.jpg, video → /original/→/thumbnail/.jpg)
- Custom: expliciet gezette URL (dat is wat al op `RenderOptions::$posterUrl` staat)

3 public methods
static cases(): array
static from(string|int $value): static
static tryFrom(string|int $value): ?static
Cases: None, Default, Thumbnail, Custom

RenderOptions

Framework\Media\RenderOptions
final class

Render-instellingen — gewoon een readonly bag van display-opties.

Defaults zijn bewust *conservatief*: lazy-load aan, geen autoplay, controls
voor zelf-gehoste video aan, gemute uit. Dit volgt browser-defaults waar
mogelijk en blijft accessible (geen surprise-audio).

__construct(?int $width = NULL, ?int $height = NULL, ?\DisplayMode $mode = NULL, ?string $aspectRatio = NULL, \PosterMode $poster = \Framework\Media\PosterMode::Default, ?string $posterUrl = NULL, bool $showPlayButton = false, bool $autoplay = false, bool $loop = false, bool $controls = true, bool $muted = true, bool $lazy = true, ?string $fetchPriority = NULL, ?string $alt = NULL, ?string $cssClass = NULL)
1 public method
with(?int $width = NULL, ?int $height = NULL, ?\DisplayMode $mode = NULL, ?string $aspectRatio = NULL, ?\PosterMode $poster = NULL, ?string $posterUrl = NULL, ?bool $showPlayButton = NULL, ?bool $autoplay = NULL, ?bool $loop = NULL, ?bool $controls = NULL, ?bool $muted = NULL, ?bool $lazy = NULL, ?string $fetchPriority = NULL, ?string $alt = NULL, ?string $cssClass = NULL): self

Kleine fluent helpers — handig voor templates die er één optie aan willen
zetten zonder de hele constructor opnieuw te tikken.

Renderer

Framework\Media\Renderer
final class

`Media` + `RenderOptions` → `Framework\Html\El`-tree.

Per-type rendering wordt gedelegeerd naar `Source::render()`. De Renderer
doet alleen het orchestratie-werk:
- Per variant een wrapper-element met `data-variant="<key>"`,
eigen `aspect-ratio` (uit Variant.options of defaults), play-button,
overlay, hover.
- Alle variants samen in een `mm-media-stack`-container met daarin een
scoped `<style>`-block dat per breakpoint toggelt welke variant
`display: block` krijgt.

Single-variant short-circuit: als er maar één variant is, geen stack/style
— gewoon de variant-wrapper teruggeven.

Wrap-structuur — meerdere variants:

<div class="mm-media-stack" data-mm-id="m-7f3a" data-mm-component="media">
<style>...</style>
<div class="mm-media" data-variant="desktop" style="aspect-ratio:16/9">...</div>
<div class="mm-media" data-variant="mobile" style="aspect-ratio:1/1">...</div>
<div class="mm-media" data-variant="dark">...</div>
</div>

Wrap-structuur — single variant:

<div class="mm-media" data-mm-component="media" data-variant="desktop"
style="aspect-ratio:..."> ... </div>

__construct(?\Image $imageBuilder = NULL)
1 public method
render(\Media $media, ?\RenderOptions $defaults = NULL): \El

Image

Framework\Media\Source\Image
final class

Image bron — rendert een `<img>`-element. Ondersteunt `loading="lazy"`,
`fetchpriority`, `width`/`height`, `alt`. Geen poster (heeft geen video).

__construct(string $url, ?int $width = NULL, ?int $height = NULL)
1 public method
render(\Variant $variant, \RenderOptions $options): \El

Video

Framework\Media\Source\Video
final class

Self-hosted video — rendert een `<video>`-element met optionele autoplay,
loop, controls, muted, preload en poster.

Poster-resolutie:
- `PosterMode::None` → geen poster
- `PosterMode::Custom` → `RenderOptions::$posterUrl` (verplicht set)
- `PosterMode::Thumbnail` → forceer auto-poster via legacy-conventie
`/original/...mp4` → `/thumbnail/...mp4.jpg`
- `PosterMode::Default` → `Variant::$posterUrl` als die er is, anders auto

__construct(string $url, ?int $width = NULL, ?int $height = NULL)
1 public method
render(\Variant $variant, \RenderOptions $options): \El

Vimeo

Framework\Media\Source\Vimeo
final class

Vimeo embed — rendert een `<iframe>` met de embed-URL via `Url::vimeoEmbed()`.

Poster-resolutie:
- `PosterMode::None` → geen poster
- `PosterMode::Custom` → `$options->posterUrl`
- `PosterMode::Default` → `Variant::$posterUrl` (geen auto — Vimeo
vereist een API-call die niet in de renderer
hoort; caller of een PosterResolver-service
moet 'm vooraf invullen)
- `PosterMode::Thumbnail` → idem als Default (geen auto beschikbaar)

__construct(string $url, ?int $width = NULL, ?int $height = NULL)
3 public methods
posterUrl(\Variant $variant, \RenderOptions $options): ?string
render(\Variant $variant, \RenderOptions $options): \El
videoId(): ?string

Lazy-parse: Vimeo video-id of null als URL niet parsebaar is.

YouTube

Framework\Media\Source\YouTube
final class

YouTube embed — rendert een `<iframe>` met de embed-URL via `Url::youTubeEmbed()`.
Honoreert autoplay/loop/muted/controls. Loop vereist `playlist={id}` (dat
regelt `Url::youTubeEmbed()`).

Poster-resolutie:
- `PosterMode::None` → geen poster
- `PosterMode::Custom` → `$options->posterUrl`
- `PosterMode::Thumbnail` → `Url::youTubePoster($url)` (hqdefault)
- `PosterMode::Default` → `Variant::$posterUrl` als die er is, anders
`Url::youTubePoster($url)`

Note: een `<iframe>` heeft géén native `poster=`-attribuut. De Renderer
tekent de poster zelf als overlay-image als 'ie wordt teruggegeven.
Daarom hangt de poster-resolutie hier op de Source en niet hard in de
iframe-element.

__construct(string $url, ?int $width = NULL, ?int $height = NULL)
3 public methods
posterUrl(\Variant $variant, \RenderOptions $options): ?string

Auto-poster URL (hqdefault.jpg). Wordt door de Renderer als overlay-image
gebruikt voor het 'klik-om-te-spelen'-pattern.

render(\Variant $variant, \RenderOptions $options): \El
videoId(): ?string

Lazy-parse: geeft het YouTube video-id of null als de URL niet parsebaar is.
Wordt niet in de constructor gevalideerd zodat placeholder-URLs uit het
CMS geen exceptions veroorzaken.

Url

Framework\Media\Url
final class

Pure URL-helpers voor YouTube/Vimeo embedding + thumbnail-detectie.
Geen IO, geen statefull dependencies. Alle functies zijn deterministisch.

6 public methods
static videoThumbnail(string $videoUrl): string

Auto-thumbnail voor zelf-gehoste video's volgens legacy-conventie:
`/original/{path}.mp4` → `/thumbnail/{path}.mp4.jpg`. Werkt alleen als
de server zo'n endpoint heeft; geen garantie dat 't bestaat.

static vimeoEmbed(string $urlOrId, bool $autoplay = false, bool $loop = false, bool $muted = true): string

Bouw een Vimeo `<iframe>` embed-URL.

static vimeoId(string $url): ?string

Extract de Vimeo video-ID uit een URL.

static youTubeEmbed(string $urlOrId, bool $controls = true, bool $autoplay = false, bool $loop = false, bool $muted = true): string

Bouw een YouTube `<iframe>` embed-URL met opties.

static youTubeId(string $url): ?string

Extract de YouTube video-ID uit een URL.

Ondersteunt:
- youtu.be/{id}
- youtube.com/watch?v={id}
- youtube.com/embed/{id}
- youtube.com/v/{id}
- youtube.com/shorts/{id}

static youTubePoster(string $urlOrId, string $quality = 'hqdefault'): ?string

YouTube poster (default kwaliteit). `hqdefault` (480×360) is altijd
beschikbaar; `maxresdefault` (1280×720) niet voor elke video.

Variant

Framework\Media\Variant
final class

Eén concrete media-variant zoals 'ie binnen een bepaald breakpoint
gerenderd wordt. Hangt typisch onder een `MediaItem` met een key (bv.
`'desktop'`, `'mobile'`, `'dark'`).

Een Variant bevat alles wat per breakpoint kan verschillen:
- `source` — URL + type (image/video/youtube/vimeo/raw) + dimensions
- `when` — CSS media query (`(max-width: 768px)`, `print`, …);
null = laat `Breakpoints` de default voor de key kiezen
- `options` — per-variant render-overrides (eigen aspect-ratio,
autoplay, controls, etc.)
- `posterUrl` — placeholder voor video-types
- `overlayUrl` — image die over de media heen ligt (badge/logo)
- `hoverUrl` — image die op hover wordt getoond (alleen images)

Geen recursie: een Variant bevat geen sub-variants. De volledige set zit op
`MediaItem.variants`. Callers maken zelden zelf een Variant aan — meestal
loopt alles via `MediaItem::from()` → `Decoder`.

__construct(\AbstractSource $source, ?string $when = NULL, ?\RenderOptions $options = NULL, ?string $posterUrl = NULL, ?string $overlayUrl = NULL, ?string $hoverUrl = NULL)
1 public method
isEmpty(): bool