Skip to content

fix: resolve string media keys in the glider component - #723

Merged
awcodes merged 1 commit into
5.xfrom
fix/glider-string-media-key
Aug 14, 2026
Merged

fix: resolve string media keys in the glider component#723
awcodes merged 1 commit into
5.xfrom
fix/glider-string-media-key

Conversation

@awcodes

@awcodes awcodes commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Fixes #719.

1. The reported bug: :media="$image" renders a placeholder, :media="(int) $image" renders the image

The reporter had it right in their third comment. Glider::__construct() only matched is_int(), so a string key fell through to handleString(), which reads the value as a path:

$extension = (string) Str::of('10')->afterLast('.'); // "10"

isPreviewable("10") is false, so the component rendered the document placeholder for a perfectly good image. Their data is ['banners' => ["10", "7"]] in a json settings column — no relationship or model override involved, which is what wasn't adding up in the thread. Any id that round-trips through json, a query string or a settings array arrives as a string.

A bare key is now looked up instead of being taken for a path:

if (is_a($media, Media::class)) {
    $this->handleMedia($media);
} elseif (is_int($media) || (is_string($media) && static::isMediaKey($media))) {
    $this->handleId($media);
} elseif (is_string($media) && filled($media)) {
    $this->handleString($media);
}

isMediaKey() matches the key shapes curator issues — digits, plus uuids and ulids, since curator:install --use-uuid writes $table->uuid('id')->primary(). A path always carries an extension, so the two shapes don't overlap; '10.jpg', 'banner.jpg' and 'media/2024/10' all still take the path branch, and there are tests pinning that.

handleInt() is kept as a deprecated delegate to the widened handleId(), so anything extending the component keeps working. A string key that doesn't resolve reaches the fallback, same as an int that doesn't.

2. The placeholder labels everything "PDF"

Worth fixing while in here, and it's half of what the reporter was looking at. resources/views/components/display/document.blade.php declares 'extension' => 'pdf' as its prop default, and glider.blade.php never passed one — so every non-previewable file the glider rendered came out labelled PDF, and the video branch in that component was unreachable. (display/index.blade.php was already doing this correctly with $item->ext.)

MediaDTO now carries ext, populated from all three sources — record, path, and fallback (via its type(), falling back to the source's extension) — and the hardcoded default is gone. A .docx now renders labelled docx.

3. The Glide token error

Docs for this landed in dafd5c2 already, so this is only the error itself. GlideManager::getToken(): string returned config('curator.glide_token') straight, so a checkout that never ran curator:install got:

Awcodes\Curator\Config\GlideManager::getToken(): Return value must be of type string, null returned

It now names the missing variable and the command that generates it. This is exactly the reporter's "1 pc has it, the other doesn't" situation.

Tests

tests/src/Feature/Components/GliderMediaKeyTest.php — 16 cases covering key resolution, the path branch staying put, fallback on an unresolvable string key, extension propagation from each source, and a rendered-html assertion that the placeholder says docx and not pdf. All but the "a path is still treated as a path" no-regression guard fail on 5.x.

composer test is green: 218 passed, PHPStan clean, no Pint or Rector drift.

🤖 Generated with Claude Code

A media id reaches `<x-curator-glider :media="...">` as a string whenever it
comes back out of a json column, a settings array or a query string. The
constructor only matched `is_int()`, so `"10"` fell through to handleString(),
was read as a path with extension `10`, failed the previewable check and
rendered the document placeholder instead of the image. Casting to `(int)` at
the call site was the reported workaround.

A bare key is now looked up rather than taken for a path. The check covers the
key shapes curator issues — digits, and uuids/ulids for installs that took the
`--use-uuid` option — and a path always carries an extension, so neither shape
is ambiguous. `handleInt()` stays as a deprecated delegate to `handleId()`.

That placeholder was also mislabelling every file it rendered: document.blade
defaults `extension` to `pdf` and glider.blade never passed one, so a .docx
came out labelled PDF. The extension now travels on MediaDTO from all three
sources (record, path, fallback), and the default is gone.

Also reported: a checkout that never ran `curator:install` has no Glide token,
and `GlideManager::getToken()` failed with a bare return type error. It now
names the missing variable and the command that generates it.

Fixes #719

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@awcodes
awcodes merged commit a8ef68a into 5.x Aug 14, 2026
11 checks passed
@awcodes
awcodes deleted the fix/glider-string-media-key branch August 14, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Component media attribute error

1 participant