@codingfactory/mediables-vue 2.0.1 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,923 @@
1
+ # Laravel Mediables v2.0
2
+
3
+ A powerful, backend-focused Laravel media management package with a clean, trait-based API. Inspired by Spatie's Media Library but built for maximum flexibility and performance.
4
+
5
+ [![Latest Version on Packagist](https://img.shields.io/packagist/v/mediables/mediables.svg?style=flat-square)](https://packagist.org/packages/mediables/mediables)
6
+ [![Total Downloads](https://img.shields.io/packagist/dt/mediables/mediables.svg?style=flat-square)](https://packagist.org/packages/mediables/mediables)
7
+ [![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
8
+
9
+ > **Upgrading from v1.x?** Check out our comprehensive [Upgrade Guide](UPGRADE.md) for a smooth migration path.
10
+
11
+ ## What's New in v2.0
12
+
13
+ ### Service-Based API
14
+
15
+ ```php
16
+ use Mediables\Facades\MediaService;
17
+
18
+ // Option 1: Two-step (store then attach)
19
+ $media = MediaService::storeMediaFile(
20
+ $request->file('image'),
21
+ 'public', // disk
22
+ 'products', // collection
23
+ ['alt' => 'Photo'] // custom properties
24
+ );
25
+ $product->attachMedia($media, 'images');
26
+
27
+ // Option 2: Combined method (recommended)
28
+ $media = MediaService::uploadAndAttachToModel(
29
+ auth()->user(), // actor
30
+ $request->file('image'),
31
+ $product, // target model
32
+ 'images', // collection
33
+ ['alt' => 'Photo'] // properties
34
+ );
35
+ ```
36
+
37
+ ### Key Features
38
+
39
+ - **Trait-Based Architecture** - Simple, clean integration with any Eloquent model
40
+ - **Service-Based Upload** - Flexible upload workflows via MediaService facade
41
+ - **Media Collections** - Organize media with powerful collection definitions
42
+ - **Smart Image Processing** - Automatic conversions, responsive images, and 46 PIXI.js filters
43
+ - **Cloud-First Design** - Native S3, CDN, and signed URL support
44
+ - **Performance Optimized** - Multi-layer caching and lazy loading
45
+ - **Backward Compatible** - Smooth migration path from v1.x
46
+ - **Modular Frontend** - Optional Vue components (Blade and Livewire coming soon)
47
+
48
+ ## Table of Contents
49
+
50
+ - [Installation](#installation)
51
+ - [Quick Start](#quick-start)
52
+ - [Defining Media Collections](#defining-media-collections)
53
+ - [Working with Media](#working-with-media)
54
+ - [Image Processing](#image-processing)
55
+ - [Frontend Components](#frontend-components)
56
+ - [Configuration](#configuration)
57
+ - [Migration from v1.x](#migration-from-v1x)
58
+ - [API Reference](#api-reference)
59
+ - [Contributing](#contributing)
60
+
61
+ ## Installation
62
+
63
+ ```bash
64
+ composer require mediables/mediables:^2.0
65
+ ```
66
+
67
+ Publish and run migrations:
68
+
69
+ ```bash
70
+ php artisan vendor:publish --tag=mediables-migrations
71
+ php artisan vendor:publish --tag=mediables-config
72
+ php artisan migrate
73
+ ```
74
+
75
+ ### Optional Frontend Packages
76
+
77
+ ```bash
78
+ # Vue 3 components (available now)
79
+ npm install @mediables/vue
80
+
81
+ # Blade components (coming soon)
82
+ # composer require mediables/blade-components
83
+
84
+ # Livewire components (coming soon)
85
+ # composer require mediables/livewire-components
86
+ ```
87
+
88
+ ## Quick Start
89
+
90
+ ### 1. Add Traits to Your Model
91
+
92
+ ```php
93
+ namespace App\Models;
94
+
95
+ use Illuminate\Database\Eloquent\Model;
96
+ use Mediables\Traits\InteractsWithMediables;
97
+
98
+ class Product extends Model
99
+ {
100
+ use InteractsWithMediables;
101
+
102
+ public function registerMediaCollections(): void
103
+ {
104
+ $this->addMediaCollection('images')
105
+ ->acceptsMimeTypes(['image/*'])
106
+ ->maxNumberOfFiles(10);
107
+
108
+ $this->addMediaCollection('documents')
109
+ ->acceptsMimeTypes(['application/pdf'])
110
+ ->singleFile();
111
+ }
112
+ }
113
+ ```
114
+
115
+ ### 2. Upload and Attach Media
116
+
117
+ ```php
118
+ use Mediables\Facades\MediaService;
119
+
120
+ // Option 1: Two-step (store then attach)
121
+ $media = MediaService::storeMediaFile(
122
+ $request->file('image'),
123
+ 'public', // disk
124
+ 'products', // collection
125
+ ['alt' => 'Photo'] // custom properties
126
+ );
127
+ $product->attachMedia($media, 'images');
128
+
129
+ // Option 2: Combined method (recommended)
130
+ $media = MediaService::uploadAndAttachToModel(
131
+ auth()->user(), // actor
132
+ $request->file('image'),
133
+ $product, // target model
134
+ 'images', // collection
135
+ ['alt' => 'Photo'] // properties
136
+ );
137
+ ```
138
+
139
+ ### 3. Retrieve and Display Media
140
+
141
+ ```php
142
+ // Get all media in collection
143
+ $images = $product->getMedia('images');
144
+
145
+ // Get first media
146
+ $mainImage = $product->getFirstMedia('images');
147
+
148
+ // Get URL (original)
149
+ $originalUrl = $mainImage->getUrl();
150
+
151
+ // Get conversion URL (use Media model method)
152
+ $thumbUrl = $mainImage->getUrl('thumb');
153
+
154
+ // Get first media URL directly (NO conversion param)
155
+ $firstUrl = $product->getFirstMediaUrl('images');
156
+
157
+ // Check if has media
158
+ if ($product->hasMedia('images')) {
159
+ // ...
160
+ }
161
+
162
+ // Count media
163
+ $count = $product->getMedia('images')->count();
164
+ ```
165
+
166
+ ## Defining Media Collections
167
+
168
+ Define what media your models accept:
169
+
170
+ ```php
171
+ public function registerMediaCollections(): void
172
+ {
173
+ // Single avatar image
174
+ $this->addMediaCollection('avatar')
175
+ ->singleFile()
176
+ ->acceptsMimeTypes(['image/jpeg', 'image/png']);
177
+
178
+ // Product gallery with limits
179
+ $this->addMediaCollection('gallery')
180
+ ->acceptsMimeTypes(['image/*'])
181
+ ->maxFileSize(5 * 1024 * 1024) // 5MB per file
182
+ ->maxNumberOfFiles(20);
183
+
184
+ // Documents with specific types
185
+ $this->addMediaCollection('documents')
186
+ ->acceptsMimeTypes(['application/pdf', 'application/msword'])
187
+ ->maxNumberOfFiles(10);
188
+ }
189
+ ```
190
+
191
+ ## Working with Media
192
+
193
+ ### Upload Workflow (Service)
194
+
195
+ ```php
196
+ use Mediables\Facades\MediaService;
197
+
198
+ // Option 1: Two-step (store then attach)
199
+ $media = MediaService::storeMediaFile(
200
+ $request->file('image'),
201
+ 'public', // disk
202
+ 'products', // collection
203
+ ['alt' => 'Photo'] // custom properties
204
+ );
205
+ $product->attachMedia($media, 'images');
206
+
207
+ // Option 2: Combined method (recommended)
208
+ $media = MediaService::uploadAndAttachToModel(
209
+ auth()->user(), // actor
210
+ $request->file('image'),
211
+ $product, // target model
212
+ 'images', // collection
213
+ ['alt' => 'Photo'] // properties
214
+ );
215
+ ```
216
+
217
+ ### Managing Collections
218
+
219
+ ```php
220
+ // Clear all media from collection
221
+ $product->clearMediaCollection('images');
222
+
223
+ // Attach existing media
224
+ $product->attachMedia($existingMedia, 'images');
225
+
226
+ // Detach media
227
+ $product->detachMedia($media, 'images');
228
+ ```
229
+
230
+ ### Working with Conversions
231
+
232
+ ```php
233
+ use Mediables\Facades\MediaService;
234
+
235
+ // Get conversion URL
236
+ $thumbnailUrl = $media->getUrl('thumb');
237
+
238
+ // Get responsive images srcset
239
+ $srcset = $media->getSrcset();
240
+
241
+ // Generate conversions manually
242
+ MediaService::generateConversions($media);
243
+ ```
244
+
245
+ ## Configuration
246
+
247
+ Simplified configuration in `config/mediables.php`:
248
+
249
+ ```php
250
+ return [
251
+ // Storage
252
+ 'disk' => env('MEDIA_DISK', 'public'),
253
+ 'conversions_disk' => env('MEDIA_CONVERSIONS_DISK', null),
254
+
255
+ // Processing
256
+ 'queue_connection' => env('MEDIA_QUEUE_CONNECTION', 'sync'),
257
+ 'conversions' => [
258
+ 'thumb' => ['width' => 150, 'height' => 150],
259
+ 'preview' => ['width' => 500, 'height' => 500],
260
+ ],
261
+
262
+ // Video Provider (currently only 'bunny' is supported)
263
+ 'video' => [
264
+ 'provider' => env('VIDEO_PROVIDER', 'bunny'),
265
+ 'bunny' => [/* ... */], // Bunny.net config
266
+ ],
267
+
268
+ // Validation
269
+ 'max_file_size' => 10 * 1024 * 1024, // 10MB
270
+ 'allowed_mimes' => 'jpeg,jpg,png,gif,webp,svg,pdf',
271
+
272
+ // Features
273
+ 'generate_responsive_images' => true,
274
+ 'versioning' => false,
275
+ 'cdn_url' => env('MEDIA_CDN_URL'),
276
+ ];
277
+ ```
278
+
279
+ ### Environment Variables for Video Providers
280
+
281
+ To configure your video provider, set `VIDEO_PROVIDER` in your `.env` file. Currently only bunny is supported.
282
+
283
+ **Bunny.net Configuration:**
284
+ When `VIDEO_PROVIDER` is set to `bunny`, the following environment variables are required:
285
+
286
+ ```env
287
+ BUNNY_VIDEO_LIBRARY_ID="your_bunny_video_library_id"
288
+ BUNNY_VIDEO_API_KEY="your_bunny_video_api_key"
289
+ BUNNY_VIDEO_HOSTNAME="video.bunnycdn.com" # Default is usually sufficient
290
+ BUNNY_VIDEO_CDN_HOSTNAME="your_library_id.b-cdn.net" # or play.bunnycdn.com
291
+ BUNNY_VIDEO_WEBHOOK_SECRET="your_webhook_secret" # Used for verifying webhooks
292
+ ```
293
+
294
+
295
+ ## Image Processing
296
+
297
+ ### Automatic Conversions
298
+
299
+ Define conversions that run automatically:
300
+
301
+ ```php
302
+ 'conversions' => [
303
+ 'thumb' => [
304
+ 'width' => 150,
305
+ 'height' => 150,
306
+ 'fit' => 'crop',
307
+ 'quality' => 80,
308
+ ],
309
+ 'preview' => [
310
+ 'width' => 500,
311
+ 'height' => 500,
312
+ 'fit' => 'contain',
313
+ ],
314
+ ],
315
+ ```
316
+
317
+ ### On-the-fly Manipulation
318
+
319
+ ```php
320
+ use Mediables\Services\Core\ImageProcessor;
321
+
322
+ $processor = app(ImageProcessor::class);
323
+
324
+ // Generate specific conversion
325
+ $processor->generateConversion($media, 'thumb', [
326
+ 'width' => 150,
327
+ 'height' => 150,
328
+ 'fit' => 'crop',
329
+ ]);
330
+ ```
331
+
332
+ ### Available Filters
333
+
334
+ The package includes 46 image filters:
335
+
336
+ ```php
337
+ use Mediables\Services\MediaManipulationService;
338
+
339
+ $manipulationService = app(MediaManipulationService::class);
340
+
341
+ // Submit a manipulation request (validated data from ManipulateMediaRequest)
342
+ $manipulationService->manipulate([
343
+ 'media_uuid' => $media->uuid,
344
+ 'manipulations' => [
345
+ 'filter' => 'ColorMatrix-1977',
346
+ 'brightness' => 10,
347
+ 'contrast' => 15,
348
+ ],
349
+ ]);
350
+
351
+ // Apply server-side filters to a media item
352
+ $processedUrl = $manipulationService->applyFilters($media, [
353
+ ['name' => 'ColorMatrix-1977'],
354
+ ]);
355
+ ```
356
+
357
+ ### Responsive Images
358
+
359
+ Responsive image generation is controlled by the `generate_responsive_images` config option. When enabled, responsive variants are generated automatically during upload.
360
+
361
+ ```php
362
+ // Enable in configuration
363
+ 'responsive_images' => [
364
+ 'enabled' => true,
365
+ 'widths' => [320, 640, 1024, 1920, 2560],
366
+ ],
367
+
368
+ // Get srcset for HTML
369
+ $srcset = $media->getSrcset('preview');
370
+
371
+ // Use in Blade templates
372
+ <img src="{{ $media->getUrl() }}"
373
+ srcset="{{ $media->getSrcset() }}"
374
+ sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw">
375
+ ```
376
+
377
+ ### Working with Variants
378
+
379
+ Media variants allow you to create processed versions of your media:
380
+
381
+ ```php
382
+ // Create a variant with specific processing
383
+ $variant = $originalMedia->createVariant([
384
+ 'manipulation' => 'cropped',
385
+ 'dimensions' => ['width' => 500, 'height' => 500],
386
+ 'filters' => ['brightness' => 10, 'contrast' => 15]
387
+ ]);
388
+
389
+ // Check processing status
390
+ if ($variant->isVariantCompleted()) {
391
+ $variantUrl = $variant->getUrl();
392
+ }
393
+
394
+ // Get all variants for media
395
+ $variants = $originalMedia->variants;
396
+
397
+ // Delete specific variant
398
+ $variant->delete();
399
+ ```
400
+
401
+ ### Signed URLs for Private Files
402
+
403
+ ```php
404
+ // Generate signed URL (expires in 60 minutes by default)
405
+ $signedUrl = $media->getSignedUrl();
406
+
407
+ // Custom expiration time
408
+ $signedUrl = $media->getSignedUrl(120); // 2 hours
409
+
410
+ // Check if URL is still valid
411
+ if ($media->isSignedUrlValid($signedUrl)) {
412
+ // URL is still valid
413
+ }
414
+ ```
415
+
416
+ ### Batch Operations
417
+
418
+ For bulk operations, iterate over your media collection using the standard service methods:
419
+
420
+ ```php
421
+ use Mediables\Facades\MediaService;
422
+
423
+ // Bulk upload with loop
424
+ $uploadResults = [];
425
+ foreach ($files as $file) {
426
+ $uploadResults[] = MediaService::storeMediaFile($file, 'public', 'products');
427
+ }
428
+
429
+ // Bulk delete with loop
430
+ foreach ($mediaItems as $media) {
431
+ MediaService::deleteMedia($media);
432
+ }
433
+
434
+ // Generate conversions for multiple media
435
+ foreach ($mediaCollection as $media) {
436
+ MediaService::generateConversions($media);
437
+ }
438
+ ```
439
+
440
+ ### Event System
441
+
442
+ The package dispatches comprehensive events:
443
+
444
+ ```php
445
+ // Listen to events
446
+ Event::listen(\Mediables\Events\MediaUploaded::class, function ($event) {
447
+ Log::info('Media uploaded: ' . $event->media->uuid);
448
+ });
449
+
450
+ // Available events:
451
+ // - MediaUploaded
452
+ // - MediaManipulated
453
+ // - MediaDeleted
454
+ // - MediaAttached
455
+ // - MediaDetached
456
+ // - ConversionGenerated
457
+ ```
458
+
459
+ ## Frontend Components
460
+
461
+ Frontend components are now in separate, optional packages:
462
+
463
+ ### Vue 3 Components
464
+
465
+ ```bash
466
+ npm install @mediables/vue
467
+ ```
468
+
469
+ ```vue
470
+ <template>
471
+ <ModelMediaManager
472
+ :model-type="'product'"
473
+ :model-uuid="product.uuid"
474
+ collection="images"
475
+ :max-files="10"
476
+ @upload-complete="handleUpload"
477
+ />
478
+ </template>
479
+
480
+ <script setup>
481
+ import { ModelMediaManager } from '@mediables/vue';
482
+ </script>
483
+ ```
484
+
485
+ ### Blade Components (Coming Soon)
486
+
487
+ ```bash
488
+ # composer require mediables/blade-components
489
+ ```
490
+
491
+ ```blade
492
+ <x-mediables-upload
493
+ :model="$product"
494
+ collection="images"
495
+ />
496
+
497
+ <x-mediables-gallery
498
+ :model="$product"
499
+ collection="images"
500
+ />
501
+ ```
502
+
503
+ ### Livewire Components (Coming Soon)
504
+
505
+ ```bash
506
+ # composer require mediables/livewire-components
507
+ ```
508
+
509
+ ```php
510
+ <livewire:mediables-manager
511
+ :model="$product"
512
+ collection="images"
513
+ />
514
+ ```
515
+
516
+ ## API Reference
517
+
518
+ The complete REST API is documented using OpenAPI 3.0.3:
519
+
520
+ - **OpenAPI Spec**: [docs/openapi.yaml](docs/openapi.yaml)
521
+ - **Interactive Docs**: [View in Redoc](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/mediables/mediables/main/docs/openapi.yaml)
522
+ - **Swagger UI**: Import `docs/openapi.yaml` into [Swagger Editor](https://editor.swagger.io/)
523
+
524
+ ### Key API Groups
525
+ - **Media Management**: Upload, list, update, delete media
526
+ - **Image Editing**: Apply filters, crop, save variants
527
+ - **Video Processing**: Encode, transcode, apply effects
528
+ - **Albums**: Organize media into hierarchical albums (requires `enable_albums=true`)
529
+ - **Admin**: Administrative endpoints for media management
530
+
531
+ ### Authentication
532
+
533
+ All API endpoints require authentication via Laravel Sanctum:
534
+
535
+ ```javascript
536
+ // Set authorization header
537
+ axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
538
+ ```
539
+
540
+ ### Media Upload
541
+
542
+ ```http
543
+ POST /api/v1/media/upload
544
+ Content-Type: multipart/form-data
545
+
546
+ Parameters:
547
+ - file: File (required)
548
+ - collection: string (optional)
549
+ - custom_properties: object (optional)
550
+ - owner_uuid: string (required)
551
+ - owner_type: string (required)
552
+ ```
553
+
554
+ Response:
555
+ ```json
556
+ {
557
+ "data": {
558
+ "uuid": "550e8400-e29b-41d4-a716-446655440000",
559
+ "file_name": "image.jpg",
560
+ "mime_type": "image/jpeg",
561
+ "size": 1024000,
562
+ "collection_name": "gallery",
563
+ "original_url": "https://cdn.example.com/media/image.jpg",
564
+ "conversion_urls": {
565
+ "thumb": "https://cdn.example.com/media/conversions/image-thumb.jpg",
566
+ "preview": "https://cdn.example.com/media/conversions/image-preview.jpg"
567
+ },
568
+ "custom_properties": {},
569
+ "created_at": "2025-01-24T10:00:00Z"
570
+ }
571
+ }
572
+ ```
573
+
574
+ ### List Media
575
+
576
+ ```http
577
+ GET /api/v1/media?collection=gallery&search=product&page=1&per_page=20
578
+ ```
579
+
580
+ ### Apply Image Filters
581
+
582
+ ```http
583
+ POST /api/v1/media/manipulate
584
+ Content-Type: application/json
585
+
586
+ {
587
+ "image_data": "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
588
+ "original_media_uuid": "550e8400-e29b-41d4-a716-446655440000",
589
+ "crop_params": {
590
+ "x": 0,
591
+ "y": 0,
592
+ "width": 100,
593
+ "height": 100,
594
+ "scaleX": 1,
595
+ "scaleY": 1
596
+ },
597
+ "filter_params": [
598
+ {"name": "ColorMatrix-1977"}
599
+ ],
600
+ "async": true
601
+ }
602
+ ```
603
+
604
+ Response (Sync, `201`):
605
+ ```json
606
+ {
607
+ "data": {
608
+ "uuid": "770e8400-e29b-41d4-a716-446655440000",
609
+ "url": "https://cdn.example.com/media/manipulated.jpg"
610
+ }
611
+ }
612
+ ```
613
+
614
+ Response (Async, `202`):
615
+ ```json
616
+ {
617
+ "id": "job-uuid-123",
618
+ "status": "queued",
619
+ "status_url": "https://api.example.com/api/v1/media/manipulations/job-uuid-123"
620
+ }
621
+ ```
622
+
623
+ **Polling Status:**
624
+ ```http
625
+ GET /api/v1/media/manipulations/{job_id}
626
+ ```
627
+
628
+ **Legacy Aliases (Deprecated):**
629
+ - `media_uuid` (alias for `original_media_uuid`)
630
+ - `manipulations` (stored as metadata only)
631
+ - Usage triggers `X-Mediables-Deprecated` header.
632
+
633
+ ### Generate Conversions
634
+
635
+ ```http
636
+ POST /api/v1/media/{media_uuid}/conversions
637
+ ```
638
+
639
+ For complete API documentation, see [docs/api.md](docs/api.md).
640
+
641
+ ## Image Processing
642
+
643
+ ### Available Filters
644
+
645
+ #### Adjustment Filters
646
+ - **brightness** (-100 to 100) - Adjust image brightness
647
+ - **contrast** (-100 to 100) - Adjust contrast levels
648
+ - **saturation** (0 to 300) - Control color saturation
649
+ - **hue** (0 to 360) - Rotate hue values
650
+ - **grayscale** (boolean) - Convert to black and white
651
+
652
+ #### Blur Effects
653
+ - **KawaseBlur** - High-quality blur effect
654
+ - **ZoomBlur** - Radial motion blur
655
+ - **MotionBlur** - Directional motion blur
656
+ - **Bloom** - Soft glow effect
657
+
658
+ #### Vintage & Artistic
659
+ - **ColorMatrix-1977** - Instagram-style vintage filter
660
+ - **Sepia** - Classic sepia tone
661
+ - **OldFilm** - Vintage film with grain
662
+ - **Dot** - Halftone newspaper effect
663
+ - **CRT** - Retro monitor effect
664
+
665
+ #### Distortion Effects
666
+ - **Twist** - Spiral distortion
667
+ - **Shockwave** - Ripple effect
668
+ - **BulgePinch** - Lens distortion
669
+
670
+ ### Usage Examples
671
+
672
+ ```php
673
+ use Mediables\Services\Core\ImageProcessor;
674
+
675
+ $processor = app(ImageProcessor::class);
676
+
677
+ // Generate a conversion with custom config
678
+ $processor->generateConversion($media, 'custom', [
679
+ 'width' => 500,
680
+ 'height' => 500,
681
+ 'fit' => 'contain',
682
+ 'quality' => 80,
683
+ 'manipulations' => [
684
+ 'brightness' => ['level' => 20],
685
+ 'contrast' => ['level' => 25],
686
+ ],
687
+ ]);
688
+ ```
689
+
690
+ ## Performance
691
+
692
+ ### Caching Strategy
693
+
694
+ The package implements multi-layer caching:
695
+
696
+ ```php
697
+ // URL caching (reduces database queries)
698
+ 'enable_url_cache' => true,
699
+ 'url_cache_duration' => 60, // minutes
700
+
701
+ // CDN integration
702
+ 'cdn' => [
703
+ 'default' => env('MEDIA_CDN_URL'),
704
+ 'invalidate_on_change' => true,
705
+ ],
706
+
707
+ // Lazy conversion generation
708
+ 'lazy_conversions' => true,
709
+ ```
710
+
711
+ ### Queue Configuration
712
+
713
+ Optimize performance with granular queue configuration:
714
+
715
+ ```php
716
+ 'queues' => [
717
+ 'upload' => 'default', // File uploads
718
+ 'conversions' => 'default', // Conversion generation
719
+ 'conversions_high' => 'high', // Priority conversions
720
+ 'conversions_low' => 'low', // Background conversions
721
+ 'responsive' => 'default', // Responsive image generation
722
+ 'delete' => 'low', // File deletion
723
+ ],
724
+ ```
725
+
726
+ ### Database Optimization
727
+
728
+ - Uses UUIDs for efficient lookups
729
+ - Polymorphic relationships for flexibility
730
+ - Indexed foreign keys and commonly queried columns
731
+ - Optimized queries with eager loading
732
+
733
+ ### Monitoring
734
+
735
+ ```php
736
+ // Get performance metrics (debug mode only)
737
+ GET /api/v1/admin/media/performance
738
+
739
+ // Monitor conversion progress
740
+ GET /api/v1/media/{media}/conversions/progress
741
+ ```
742
+
743
+ ## Artisan Commands
744
+
745
+ ```bash
746
+ # Generate missing conversions
747
+ php artisan mediables:generate-conversions
748
+
749
+ # Clean up orphaned media records
750
+ php artisan mediables:cleanup-orphans
751
+
752
+ # Verify media files exist in storage
753
+ php artisan mediables:verify-files
754
+
755
+ # Warm CDN cache
756
+ php artisan mediables:warm-cache
757
+
758
+ # Test media relationships
759
+ php artisan mediables:test-relationships
760
+
761
+ # Test S3 connectivity
762
+ php artisan mediables:test-storage
763
+ ```
764
+
765
+ ### Scheduling Orphan Cleanup
766
+
767
+ Scheduling is the consuming application's responsibility. This command is designed to be safe for cron/schedulers by using chunked processing and an optional runtime bound (`--limit`).
768
+
769
+ ```bash
770
+ php artisan mediables:cleanup-orphans --grace-period=7 --chunk=200 --limit=2000
771
+ ```
772
+
773
+ ## Testing
774
+
775
+ The package includes comprehensive testing support:
776
+
777
+ ```php
778
+ use Illuminate\Http\UploadedFile;
779
+ use Illuminate\Support\Facades\Storage;
780
+ use Mediables\Facades\MediaService;
781
+
782
+ // Fake storage for testing
783
+ Storage::fake('public');
784
+
785
+ // Create fake upload
786
+ $file = UploadedFile::fake()->image('product.jpg', 1200, 800);
787
+
788
+ // Test media upload
789
+ $media = MediaService::storeMediaFile($file, 'public', 'products');
790
+
791
+ // Assert file exists
792
+ Storage::disk('public')->assertExists($media->full_path);
793
+
794
+ // Test media attachment
795
+ $product = Product::factory()->create();
796
+ $product->attachMedia($media, 'gallery');
797
+
798
+ $this->assertTrue($product->hasMedia('gallery'));
799
+ $this->assertEquals(1, $product->getMedia('gallery')->count());
800
+ ```
801
+
802
+ ## Migration from v1.x
803
+
804
+ ### Quick Migration
805
+
806
+ Run the migration command:
807
+
808
+ ```bash
809
+ php artisan mediables:migrate-v2
810
+ ```
811
+
812
+ This will:
813
+ - Analyze your current setup
814
+ - Update trait usage automatically
815
+ - Migrate configuration
816
+ - Provide detailed migration report
817
+
818
+ ### Manual Migration
819
+
820
+ 1. **Update Traits:**
821
+
822
+ | Old (v1.x) | New (v2.0) |
823
+ |---|---|
824
+ | `Mediables\Traits\HasMediaCollections` | `Mediables\Traits\InteractsWithMediables` |
825
+
826
+ 2. **Update Method Calls:**
827
+
828
+ | Old Method | New Method |
829
+ |------------|------------|
830
+ | `getMediaByCollection()` | `getMedia()` |
831
+ | `getFirstMediaByCollection()` | `getFirstMedia()` |
832
+ | `hasMediaCollection()` | `hasMedia()` |
833
+ | `detachMedia()` | `detachMedia()` |
834
+ | `syncMediaCollection()` | `clearMediaCollection()` + `attachMedia()` loop |
835
+
836
+ For detailed migration instructions, see [UPGRADE.md](UPGRADE.md).
837
+
838
+ ## Migration from Spatie Media Library
839
+
840
+ Migrating from Spatie Media Library? We've got you covered:
841
+
842
+ ```bash
843
+ # The package includes backward compatibility
844
+ # Your existing database schema works with minor adjustments
845
+ # See detailed migration guide: docs/migration-guide.md
846
+ ```
847
+
848
+ Key differences:
849
+ - Uses UUIDs instead of auto-incrementing IDs
850
+ - Improved polymorphic relationship structure
851
+ - Enhanced querying capabilities
852
+ - Better performance optimizations
853
+
854
+ For a complete migration guide, see [docs/migration-guide.md](docs/migration-guide.md).
855
+
856
+ ## Database Schema
857
+
858
+ ### Core Tables
859
+
860
+ - **media** - Stores media file metadata and properties
861
+ - **mediables** - Polymorphic pivot table linking media to models
862
+ - **media_variants** - Tracks processing status of media variants
863
+ - **media_albums** - Optional album organization (if enabled)
864
+ - **media_audits** - Optional audit trail (if enabled)
865
+
866
+ ### Key Fields
867
+
868
+ **Media Table:**
869
+ ```sql
870
+ uuid (primary key)
871
+ file_name
872
+ original_file_name
873
+ mime_type
874
+ size
875
+ disk
876
+ collection_name
877
+ custom_properties (JSON)
878
+ created_at, updated_at
879
+ ```
880
+
881
+ **Mediables Table:**
882
+ ```sql
883
+ media_uuid (foreign key)
884
+ mediable_uuid
885
+ mediable_type
886
+ collection_name
887
+ order_column
888
+ ```
889
+
890
+ ## Requirements
891
+
892
+ - **PHP** 8.1 or higher
893
+ - **Laravel** 11.0 or higher
894
+ - **Intervention Image** 3.11 or higher
895
+ - **Vue** 3.4+ (for Vue components)
896
+ - **Ionic** 8.0+ (for mobile components)
897
+
898
+ ## License
899
+
900
+ The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
901
+
902
+ ## Contributing
903
+
904
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
905
+
906
+ ## Support & Documentation
907
+
908
+ - **Documentation**: [Full Documentation](docs/)
909
+ - **API Reference**: [API Documentation](docs/api.md)
910
+ - **Vue Components**: [Component Guide](docs/vue-components.md)
911
+ - **Migration Guide**: [Migration Guide](docs/migration-guide.md)
912
+ - **Issues**: [GitHub Issues](https://github.com/mediables/mediables/issues)
913
+
914
+ ## Credits
915
+
916
+ - Originally extracted from the Marketplace project
917
+ - Built on top of Intervention Image
918
+ - Inspired by Spatie Media Library
919
+ - Vue components designed for Ionic Framework
920
+
921
+ ---
922
+
923
+ **Ready to get started?** Check out our [Quick Start Guide](#quick-start) or dive into the [full documentation](docs/).