Skip to content

features.media_library requires Post model to implement HasMedia — not wired #13

Description

@ManukMinasyan

Summary

The features.media_library flag in config/ink.php switches the featured-image field on PostResource from FileUpload to SpatieMediaLibraryFileUpload. However, the package's Post model does not implement Spatie\MediaLibrary\HasMedia or use InteractsWithMedia — so enabling the flag with spatie/laravel-medialibrary installed will crash at upload time (no getMedia() / addMediaFromRequest() etc.).

Repro

In a host app:

```bash
composer require relaticle/ink spatie/laravel-medialibrary
```

```php
// config/ink.php
'features' => [
'media_library' => true,
],
```

Open Filament admin → create post → attach featured image → save. Crashes:

```
Method Relaticle\Ink\Models\Post::addMediaFromRequest does not exist
```

Why it's tricky

You can't conditionally implement an interface in PHP. Three options:

Option A — always implement HasMedia (simplest, most invasive)

Add implements HasMedia + use InteractsWithMedia to Models\Post.php and add spatie/laravel-medialibrary to `composer.json`'s `require` (or at least `suggest` + a hard runtime check).

Pros: zero-config for users who enable the flag.
Cons: forces medialibrary as a hard dep on all consumers (a few MB of vendor) even when they don't use it.

Option B — provide a swappable model

Introduce `Ink::usePostModel(YourPost::class)` (mirrors how `Sanctum::usePersonalAccessTokenModel()` works). Consumers who want MediaLibrary extend the base `Post` and add the trait themselves:

```php
class Post extends \Relaticle\Ink\Models\Post implements HasMedia
{
use InteractsWithMedia;
}
```

Pros: clean architecture, no forced dep, consistent with Laravel ecosystem patterns.
Cons: users have to write 6 lines of glue to enable a "feature flag."

Option C — remove the flag, document the override

Drop `features.media_library` from config. Document that consumers who want MediaLibrary should override `PostResource::featuredImageField()` (or the whole resource) in their app.

Pros: least invasive.
Cons: loses the drop-in story.

Recommendation

Option B. Patterns like `Sanctum::usePersonalAccessTokenModel()` and `Jetstream::useTeamModel()` are well-established in Laravel-land. The 6 lines of glue are the right place to pay the conditional-trait cost.

Sketch

```php
// src/Ink.php (new)
namespace Relaticle\Ink;

class Ink
{
public static string $postModel = Models\Post::class;
public static string $categoryModel = Models\Category::class;
public static string $tagModel = Models\Tag::class;

public static function usePostModel(string \$model): void
{
    static::\$postModel = \$model;
}

}
```

Then PostResource / MCP tools / etc. read `Ink::$postModel` instead of hardcoding `Models\Post::class`.

Discovered while

Wiring `relaticle/ink` into Relaticle (`relaticle/relaticle` PR #210). We have `spatie/laravel-medialibrary` installed and would benefit from `SpatieMediaLibraryFileUpload` for featured images, but the flag isn't usable as-is.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions