Uploading Files
The easiest way to upload media to your server is with the MediaUploader
class, which handles validating the file, moving it to its destination and creating a Media
record to reference it. You can get an instance of the MediaUploader using the Facade and configure it with a fluent interface.
To upload a file to the root of the default disk (set in config/mediable.php
), all you need to do is the following:
<?php
use MediaUploader; //use the facade
$media = MediaUploader::fromSource($request->file('thumbnail'))->upload();
Source Files
The fromSource()
method will accept any of the following:
an instance of
Symfony\Component\HttpFoundation\UploadedFile
, which is returned by$request->file()
.an instance of
Symfony\Component\HttpFoundation\File
.an instance of
Psr\Http\Message\StreamInterface
, which is returned by libraries using PSR-7 HTTP message interfaces, like Guzzle.a stream resource handle.
a URL as a string, beginning with
http://
orhttps://
.an absolute path as a string, beginning with
/
.a base64 or URL-encoded data URL.
Specifying Destination
By default, the uploader will place the file in the root of the default disk specified in config/mediable.php
. You can customize where the uploader will put the file on your server before you invoke the upload()
method.
<?php
$uploader = MediaUploader::fromSource($request->file('thumbnail'))
// specify a disk to use instead of the default
->toDisk('s3');
// place the file in a directory relative to the disk root
->toDirectory('user/john/profile')
// alternatively, specify both the disk and directory at once
->toDestination('s3', 'user/john/profile')
->upload();
Specifying Filename
By default, the uploader will copy the source file while maintaining its original filename. You can override this behaviour by providing a custom filename.
<?php
MediaUploader::fromSource(...)
->useFilename('profile')
->upload();
You can also tell the uploader to generate a filename using a specified hashing algorithm on the file’s contents. Supports any algorithm supported by PHP’s hash()
function.
<?php
MediaUploader::fromSource(...)
->useHashForFilename() // default is 'md5'
->useHashForFilename('sha1')
->upload();
You can restore the default behaviour with useOriginalFilename()
.
Adding Alt Text
You can record alt text attribute for the media record by calling the withAltAttribute()
method.
- ::
<?php MediaUploader::fromSource(…)
->withAltAttribute(‘This is the alt text’) ->upload();
Handling Duplicates
Occasionally, a file with a matching name might already exist at the destination you would like to upload to. The uploader allows you to configure how it should respond to this scenario. There are three possible behaviours:
<?php
// keep both, append incrementing counter to new file name
$uploader->onDuplicateIncrement();
// replace old file with new one, update existing Media record, maintain associations
$uploader->onDuplicateUpdate();
// replace old file and media record with new ones, break associations
$uploader->onDuplicateReplace();
// replace old file and media record with new ones, break associations
// will also delete any existing variants of the replaced media record
$uploader->onDuplicateReplaceWithVariants();
// cancel upload, throw an exception
$uploader->onDuplicateError();
Validation
The MediaUpload
will perform a number of validation checks on the source file. If any of the checks fail, a Plank\Mediable\MediaUploadException
will be thrown with a message indicating why the file was rejected.
You can override the most validation configuration values set in config/mediable.php
on a case-by-case basis using the same fluent interface.
<?php
$media = MediaUploader::fromSource($request->file('image'))
// model class to use
->setModelClass(MediaSubclass::class)
// maximum filesize in bytes
->setMaximumSize(99999)
// whether the aggregate type must match both the MIME type and extension
->setStrictTypeChecking(true)
// whether to allow the 'other' aggregate type
->setAllowUnrecognizedTypes(true)
// only allow files of specific MIME types
->setAllowedMimeTypes(['image/jpeg'])
// only allow files of specific extensions
->setAllowedExtensions(['jpg', 'jpeg'])
// only allow files of specific aggregate types
->setAllowedAggregateTypes(['image'])
// ensure that the file contents match a provided hash
// second argument is the hash algorithm to use
// supports any algorithm supported by PHP's hash() function
->validateHash('3ef5e70366086147c2695325d79a25cc', 'md5')
->validateHash('5e96e1fa58067853219c4cb6d3c1ce01cc5cc8ce', 'sha1')
->upload();
You can also validate the file without uploading it by calling the verifyFile
method.
If the file does not pass validation, an instance of Plank\Mediable\MediaUploadException
will be thrown
<?php
$media = MediaUploader::fromSource($request->file('image'))
// model class to use
->setModelClass(MediaSubclass::class)
// maximum filesize in bytes
->setMaximumSize(99999)
// only allow files of specific MIME types
->setAllowedMimeTypes(['image/jpeg'])
->verifyFile()
Manipulate images during upload
It is possible to edit images during the upload process using the intervention/image library.
<?php
$manipulation = ImageManipulation::make(function (Image $image, Media $originalMedia) {
$image->fit(100, 100);
})->outputPngFormat();
$media = MediaUploader::fromSource($request->file('image'))
->applyImageManipulation($manipulation);
->upload()
// alternatively you can reference a register variant name
$media = MediaUploader::fromSource($request->file('image'))
->applyImageManipulation('thumbnail')
->upload()
If the aggregate type of the file is not ‘image’, the manipulation will be ignored.
This will load the file contents and apply manipulations synchronously as part of the upload process, which may add latency. The original file is not persisted. To apply manipulations asynchronously on copies of the original file, and for more information on manipulations, see the Image Variants sections.
Alter Model before saving
You can manipulate the model before it’s saved by passing a callable to the beforeSave
method.
The callback takes two params, $model
, an instance of Plank\Mediable\Media
the current model and $source
, an instance of Plank\Mediable\SourceAdapters\SourceAdapterInterface
the current source.
<?php
$media = MediaUploader::fromSource($request->file('image'))
// model class to use
->setModelClass(CustomMediaClass::class)
// pass the callable
->beforeSave(function (Media $model, SourceAdapterInterface $source) {
$model->setAttribute('customAttribute', 'value')
})
->upload()
Visibility
In addition to setting visibility on Disks as a whole, you can also specify whether a file should be publicly viewable on a file by file basic
<?php
MediaUploader::fromSource($request->file('image'))
->makePrivate() // Disable public access
->makePublic() // Default behaviour
->upload()
Options
You can also specify additional option flags to be passed to the underlying filesystem adapter. This is particularly useful when dealing with cloud storage such as S3.
<?php
MediaUploader::fromSource($request->file('image'))
->withOptions(['Cache-Control' => 'max-age=3600'])
->upload();
Handling Exceptions
If you want to return more granular HTTP status codes when a Plank\Mediable\MediaUploadException
is thrown, you can use the Plank\Mediable\HandlesMediaUploadExceptions
trait in your app’s ExceptionsHandler or in your controller. For example, if you have set a maximum file size, an 413 HTTP response code (Request Entity Too Large) will be returned instead of a 500.
Call the transformMediaUploadException
method as part of the render
method of the exception handler, and a HttpException
with the appropriate status code will be returned. Take a look at the HandlesMediaExceptions
source code for the table of associated status codes and exceptions.
<?php
namespace App\Exceptions;
use Plank\Mediable\HandlesMediaUploadExceptions;
class Handler
{
use HandlesMediaUploadExceptions;
public function render($request, $e)
{
$e = $this->transformMediaUploadException($e);
return parent::render($request, $e);
}
}
If you only want some actions to throw an HttpException
, you can apply the trait to the controller instead.
<?php
class ExampleController extends Controller
{
use HandlesMediaUploadExceptions;
public function upload(Request $request)
{
try{
MediaUploader::fromSource($request->file('file'))
->toDestination(...)
->upload();
}catch(MediaUploadException $e){
throw $this->transformMediaUploadException($e);
}
}
}
Importing Files
If you need to create a media record for a file that is already in place on the desired filesystem disk, you can use one the import methods instead.
<?php
$media = MediaUploader::import($disk, $directory, $filename, $extension);
// or
$media = MediaUploader::importPath($disk, $path);
If you have string file data, you can import it using the fromString method.
<?php
// Encoded image converted to string
$jpg = Image::make('https://www.plankdesign.com/externaluse/plank.png')->encode('jpg');
MediaUploader::fromString($jpg)
->toDestination(...)
->upload();
Replacing Files
If you need to swap out the file belonging to a Media
record, you can use the replace()
method. This will upload the file and update the existing record while maintaining any attachments to other models.
<?php
$media = Media::find($id);
MediaUploader::fromSource($source)
->replace($media);
Updating Files
If a file has changed on disk, you can re-evaluate its attributes with the update()
method. This will reassign the media record’s mime_type
, aggregate_type
and size
attributes and will save the changes to the database, if any.
<?php
MediaUploader::update($media);