1. Go to this page and download the library: Download elegantly/laravel-media library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
namespace App\Models;
use Elegantly\Media\Traits\HasMedia;
use Elegantly\Media\MediaCollection;
use Elegantly\Media\MediaConversion;
use Elegantly\Media\Enums\MediaType;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Spatie\Image\Enums\Fit;
use \App\Jobs\Media\OptimizedImageConversionJob;
use Elegantly\Media\Models\Media;
use Elegantly\Media\Contracts\InteractWithMedia;
use Illuminate\Contracts\Support\Arrayable;
use Elegantly\Media\Support\ResponsiveImagesConversionsPreset;
class Channel extends Model implements InteractWithMedia
{
use HasMedia;
public function registerMediaCollections(): Arrayable|iterable|null;
{
return [
new MediaCollection(
name: 'avatar',
acceptedMimeTypes: [
'image/jpeg', 'image/png', 'image/gif', 'image/webp',
],
)
new MediaCollection(
name: 'videos',
acceptedMimeTypes: [
'video/mp4', 'video/webm', 'video/ogg', 'video/quicktime',
],
)
];
}
public function registerMediaTransformations($media, UploadedFile|File $file): UploadedFile|File
{
if($media->collection_name === "avatar"){
Image::load($file->getRealPath())
->fit(Fit::Crop, 500, 500)
->optimize()
->save();
}
return $file;
}
public function registerMediaConversions($media): Arrayable|iterable|null;
{
if($media->collection_name === 'avatar'){
return [
new MediaConversion(
conversionName: '360',
job: new OptimizedImageConversionJob(
media: $media,
width: 360,
fileName: "{$media->name}-360.jpg"
),
)
]
}elseif($media->collection_name === 'videos'){
return [
new MediaConversion(
conversionName: 'poster',
sync: true,// The conversion will not be queued, you will have access to it immediatly
job: new VideoPosterConversionJob(
media: $media,
seconds: 1,
fileName: "{$media->name}-poster.jpg"
),
conversions: function(GeneratedConversion $generatedConversion) use ($media){
return ResponsiveImagesConversionsPreset::make(
media: $media,
generatedConversion: $generatedConversion
widths: [360, 720]
)
}
),
...ResponsiveVideosConversionsPreset::make(
media: $media,
widths: [360, 720, 1080],
)
]
}
return null;
}
}
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ChannelAvatarController extends Controller
{
function function store(Request $request, Channel $channel)
{
$channel->addMedia(
file: $file->file('avatar'),
collection_name: 'avatar',
name: "{$channel->name}-avatar",
)
}
}
namespace App\Livewire;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Livewire\WithFileUploads;
use Livewire\Component;
class ImageUploader extends Component
{
use WithFileUploads;
function function save()
{
/** @var TemporaryUploadedFile */
$file = $this->avatar;
$this->channel->addMedia(
file: $file->getRealPath(),
collection_name: 'avatar',
name: "{$channel->name}-avatar",
)
}
}
use Elegantly\Media\Jobs\DeleteModelMediaJob;
use Elegantly\Media\Models\Media;
return [
/**
* The media model
* Define your own model here by extending \Elegantly\Media\Models\Media::class
*/
'model' => Media::class,
/**
* The default disk used for storing files
*/
'disk' => env('MEDIA_DISK', env('FILESYSTEM_DISK', 'local')),
/**
* Determine if media should be deleted with the model
* when using the HasMedia Trait
*/
'delete_media_with_model' => true,
/**
* Determine if media should be deleted with the model
* when it is soft deleted
*/
'delete_media_with_trashed_model' => false,
/**
* Deleting a large number of media attached to a model can be time-consuming
* or even fail (e.g., cloud API error, permissions, etc.)
* For performance and monitoring, when a model with the HasMedia trait is deleted,
* each media is individually deleted inside a job.
*/
'delete_media_with_model_job' => DeleteModelMediaJob::class,
/**
* The default collection name
*/
'default_collection_name' => 'default',
/**
* Prefix for the generated path of files
* Set to null if you do not want any prefix
* To fully customize the generated default path, extend the Media model and override the generateBasePath method
*/
'generated_path_prefix' => null,
/**
* Customize the queue connection used when dispatching conversion jobs
*/
'queue_connection' => env('QUEUE_CONNECTION', 'sync'),
/**
* Customize the queue used when dispatching conversion jobs
* null will fall back to the default Laravel queue
*/
'queue' => null,
/**
* Customize WithoutOverlapping middleware settings
*/
'queue_overlapping' => [
/**
* The release value should be longer than the longest conversion job that might run
* Default is: 1 minute. Increase it if your jobs are longer.
*/
'release_after' => 60,
/**
* The expire value allows you to forget a lock in case of an unexpected job failure
*
* @see https://laravel.com/docs/10.x/queues#preventing-job-overlaps
*/
'expire_after' => 60 * 60,
],
];
namespace App\Models;
use Elegantly\Media\Traits\HasMedia;
use Illuminate\Database\Eloquent\Model;
use Elegantly\Media\Contracts\InteractWithMedia;
class Channel extends Model implements InteractWithMedia
{
use HasMedia;
}
namespace App\Models;
use Elegantly\Media\Traits\HasMedia;
use Elegantly\Media\MediaCollection;
use Illuminate\Database\Eloquent\Model;
use Elegantly\Media\Contracts\InteractWithMedia;
use Illuminate\Contracts\Support\Arrayable;
class Channel extends Model implements InteractWithMedia
{
use HasMedia;
public function registerMediaCollections(): Arrayable|iterable|null;
{
return [
new MediaCollection(
name: 'avatar',
acceptedMimeTypes: [
'image/jpeg', 'image/png', 'image/gif', 'image/webp',
],
)
new MediaCollection(
name: 'videos',
acceptedMimeTypes: [
'video/mp4', 'video/webm', 'video/ogg', 'video/quicktime',
],
)
];
}
}
namespace App\Models;
use Elegantly\Media\Traits\HasMedia;
use Elegantly\Media\MediaCollection;
use Elegantly\Media\MediaConversion;
use Elegantly\Media\Enums\MediaType;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Spatie\Image\Enums\Fit;
use \App\Jobs\Media\OptimizedImageConversionJob;
use Elegantly\Media\Models\Media;
use Elegantly\Media\Contracts\InteractWithMedia;
use Illuminate\Contracts\Support\Arrayable;
use Elegantly\Media\Support\ResponsiveImagesConversionsPreset;
class Channel extends Model implements InteractWithMedia
{
use HasMedia;
// ...
public function registerMediaConversions($media): Arrayable|iterable|null;
{
if($media->collection_name === 'avatar'){
return [
new MediaConversion(
conversionName: '360',
job: new OptimizedImageConversionJob(
media: $media,
width: 360,
fileName: "{$media->name}-360.jpg"
),
)
]
}elseif($media->collection_name === 'videos'){
return [
new MediaConversion(
conversionName: 'poster',
sync: true, // The conversion will not be queued, you will have access to it immediatly
job: new VideoPosterConversionJob(
media: $media,
seconds: 1,
fileName: "{$media->name}-poster.jpg"
),
conversions: function(GeneratedConversion $generatedConversion) use ($media){
return ResponsiveImagesConversionsPreset::make(
media: $media,
generatedConversion: $generatedConversion
widths: [360, 720]
)
}
),
...ResponsiveVideosConversionsPreset::make(
media: $media,
widths: [360, 720, 1080],
)
]
}
return null;
}
}
namespace App\Support\MediaConversions;
use Elegantly\Media\Models\Media;
use Illuminate\Support\Facades\File;
use Spatie\Image\Enums\Fit;
use Spatie\Image\Image;
use Spatie\ImageOptimizer\OptimizerChain;
use Elegantly\Media\Jobs\MediaConversionJob;
class OptimizedImageConversionJob extends MediaConversionJob
{
public string $fileName;
public function __construct(
public Media $media,
?string $queue = null,
public ?int $width = null,
public ?int $height = null,
public Fit $fit = Fit::Contain,
public ?OptimizerChain $optimizerChain = null,
?string $fileName = null,
) {
parent::__construct($media, $queue);
$this->fileName = $fileName ?? $this->media->file_name;
}
public function run(): void
{
$temporaryDisk = $this->getTemporaryDisk();
$path = $this->makeTemporaryFileCopy();
$newPath = $temporaryDisk->path($this->fileName);
Image::load($path)
->fit($this->fit, $this->width, $this->height)
->optimize($this->optimizerChain)
->save($newPath);
$this->media->storeConversion(
file: $newPath,
conversion: $this->conversionName,
name: File::name($this->fileName)
);
}
}
namespace App\Models;
use Elegantly\Media\Models\Media as ElegantlyMedia;
class Media extends ElegantlyMedia
{
// ...
}
use App\Models\Media;
return [
'model' => Media::class,
// ...
];
namespace App\Models;
use App\Models\Media;
use Elegantly\Media\Traits\HasMedia;
use Elegantly\Media\Contracts\InteractWithMedia;
/**
* @implements InteractWithMedia<Media>
*/
class Post extends Model implements InteractWithMedia
{
/** @use HasMedia<Media> **/
use HasMedia;
// ...
}