Weave Code
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

Laravel Mediable Laravel Package

plank/laravel-mediable

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require plank/laravel-mediable
    

    Publish the config and migrations:

    php artisan vendor:publish --provider="Plank\Mediable\MediableServiceProvider"
    php artisan migrate
    
  2. First Use Case: Upload a file and attach it to a model (e.g., Post):

    use Plank\Mediable\HasMediable;
    use Plank\Mediable\MediaUploader;
    
    class Post extends Model
    {
        use HasMediable;
    }
    
    // In your controller:
    $post = Post::find(1);
    $media = MediaUploader::fromRequest($request, 'image')
        ->toDestination('public', 'posts/thumbnails')
        ->upload();
    $post->addMedia($media)->usingCollection('thumbnails')->save();
    
  3. Key Files:

    • config/mediable.php: Configure disks, allowed MIME types, and default settings.
    • app/Models/Media.php: Base model for media records (extend if needed).
    • app/Models/Mediable.php: Trait for polymorphic media relationships.

Implementation Patterns

Core Workflows

1. Uploading Media

  • Basic Upload:
    $media = MediaUploader::fromRequest($request, 'image')
        ->toDestination('public', 'uploads')
        ->upload();
    
  • Custom Validation:
    ->validate(function ($file) {
        return $file->isValidImage() && $file->size() < 5120; // <5MB
    });
    
  • Batch Upload:
    $request->file('images')->each(function ($file) use ($post) {
        $media = MediaUploader::fromSource($file)
            ->toDestination('public', 'gallery')
            ->upload();
        $post->addMedia($media)->usingCollection('gallery')->save();
    });
    

2. Attaching Media to Models

  • Polymorphic Relationships:
    $post->addMedia($media); // Attaches to default collection
    $post->addMedia($media)->usingCollection('featured')->save();
    
  • Tagging Media:
    $media->tags()->sync(['thumbnail', 'primary']);
    

3. Retrieving Media

  • By Collection:
    $post->getMedia('thumbnails'); // Collection of media
    $post->getFirstMedia('featured'); // Single media
    
  • By Tag:
    $post->getMedia('thumbnail'); // Media tagged 'thumbnail'
    
  • URL Generation:
    $media->getUrl(); // Full URL
    $media->getPath(); // Filesystem path
    

4. Image Manipulation (Integration with intervention/image)

  • Generate Variants:
    $media->setCustomProperty('width', 300)->setCustomProperty('height', 200);
    $media->generateVariant();
    
  • Access Variants:
    $media->getVariantUrl('thumbnail'); // URL to generated variant
    

5. Deleting Media

  • From Model:
    $post->deleteMedia($media); // Removes from all collections
    $post->deleteMedia($media, 'thumbnails'); // Removes from specific collection
    
  • Purge All:
    $post->clearMediaCollections();
    

Integration Tips

1. Customizing Media Model

Extend the Media model to add custom fields:

class CustomMedia extends \Plank\Mediable\Models\Media
{
    protected $casts = [
        'is_primary' => 'boolean',
    ];
}

Update config/mediable.php to point to your custom model.

2. Custom Upload Logic

Override the upload method in a service class:

class CustomMediaUploader extends MediaUploader
{
    public function upload()
    {
        // Custom logic (e.g., pre-process files)
        return parent::upload();
    }
}

3. Filesystem Configuration

Configure multiple disks in config/mediable.php:

'disks' => [
    'public' => 'public',
    's3' => 's3',
],

Use them in uploads:

->toDestination('s3', 'backups')

4. API Responses

Serialize media with relationships:

return PostResource::make($post)->additional([
    'media' => $post->getMedia()->map(fn ($m) => [
        'url' => $m->getUrl(),
        'tags' => $m->tags,
    ]),
]);

5. Testing

Use MediaUploader in tests:

$media = MediaUploader::fromSource(fake()->image())
    ->toDestination('public', 'tests')
    ->upload();
$this->assertDatabaseHas('media', ['path' => 'tests/...']);

Gotchas and Tips

Pitfalls

  1. Filesystem Permissions:

    • Ensure the configured disk (e.g., public) has write permissions.
    • For s3, verify AWS credentials and bucket policies.
  2. MIME Type Restrictions:

    • Default config blocks many MIME types. Update config/mediable.php:
      'allowed_mime_types' => [
          'image/jpeg', 'image/png', 'image/gif',
          'application/pdf', 'application/zip',
      ],
      
  3. Polymorphic Conflicts:

    • If multiple models use HasMediable, ensure the mediable_type column in the media table doesn’t cause collisions (unlikely, but possible with custom table names).
  4. Variant Generation:

    • intervention/image must be installed (composer require intervention/image).
    • Variants are generated on-demand; cache them for performance:
      $media->generateVariant(['width' => 300, 'height' => 300], 'thumbnail');
      
  5. Large Files:

    • Laravel’s default max_file_size in php.ini may block uploads. Adjust as needed.
    • For chunked uploads, consider libraries like spatie/laravel-medialibrary or custom solutions.
  6. Tagging Quirks:

    • Tags are case-sensitive. Use constants or helpers to standardize:
      const TAG_THUMBNAIL = 'thumbnail';
      
  7. Model Events:

    • Media deletion triggers deleting events on the model. Override if needed:
      protected static function bootHasMediable()
      {
          static::deleting(function ($model) {
              $model->clearMediaCollections();
          });
      }
      

Debugging Tips

  1. Log Uploads: Add a logging middleware to MediaUploader:

    ->beforeUpload(function ($file) {
        \Log::debug('Uploading', ['file' => $file->getClientOriginalName()]);
    });
    
  2. Check Disk Contents: Manually verify files exist in the configured disk:

    ls storage/app/public/uploads
    
  3. Validate MIME Types: Use dd($request->file('image')->getMimeType()) to debug rejected uploads.

  4. Query Media: Inspect the media table directly:

    \DB::table('media')->where('model_id', $post->id)->get();
    
  5. Clear Cached Variants: Delete storage/framework/cache/ if variants aren’t regenerating.


Extension Points

  1. Custom Storage Engines: Extend Plank\Mediable\Contracts\MediaUploader to support non-filesystem storage (e.g., database blobs).

  2. Hooks: Override methods in MediaUploader:

    • beforeUpload: Pre-process files.
    • afterUpload: Post-upload actions (e.g., send notifications).
    • beforeDelete: Cleanup logic.
  3. Custom Collections: Add logic to HasMediable trait:

    public function addMedia($media, $collection = 'default')
    {
        if ($collection === 'custom') {
            // Custom logic
        }
        return parent::addMedia($media, $collection);
    }
    
  4. API Resources: Create a MediaResource for consistent API responses:

    class MediaResource extends JsonResource
    {
        public function toArray($request)
        {
            return [
                'url' => $this->getUrl(),
                'tags' => $this->tags,
                'size
    
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.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony