A Laravel Nova resource tool to upload files directly to Amazon S3. You can (upload | download | delete) single, multiple, small or big files.
-
Secure: No sensitive data will be exposed to the front-end including AWS credentials. The uploaded and downloaded files will never pass through your server for extra protection and performance.
-
Flexible: File information can be stored in model attributes or as an array under a single model attribute or even as relationship.
-
Solid: Based on excellent components, Uppy file uploader, Laravel Nova dashboard and Amazon S3 storage.
-
Customizable: Wide range of customization options using chained methods.
-
Image Editor, Custom Meta Fields, Chunked Upload, Webcam Recording, Screen Capture, Authorization, Localization, ...
composer require "ahmedkandel/nova-s3-multipart-upload"
In your Nova resource class add NovaS3MultipartUpload
tool to fields:
use Ahmedkandel\NovaS3MultipartUpload\NovaS3MultipartUpload;
class Post extends Resource
{
public function fields(Request $request)
{
return [
// ...
NovaS3MultipartUpload::make('Video'),
];
}
}
NB the make
method requires a "human readable" name, it will try to guess the attribute name. You may pass the attribute name as a second argument.
NB the attribute name is used to store the file_path OR file/s information in case of storeAsArray
/storeAsMultipleArray
OR relationship model/s in case of hasOne
/hasMany
.
NB hasOne
/hasMany
methods are valid also for morphOne
/morphMany
In your model class add all the attributes that will be filled to $fillable
:
class Post extends Model
{
protected $fillable = ['video'];
}
When using storeAsArray
or storeAsMultipleArray
methods you will need to cast the attribute to an array in your model class:
class Post extends Model
{
protected $casts = [
'videos' => 'array',
];
}
After creating your S3 bucket and connecting it to your Laravel project, You will need an extra step to configure the S3 bucket's "Cross-origin resource sharing (CORS)" with either JSON or XML (this is NOT the "Bucket policy"):
[
{
"AllowedOrigins": [
"http://your-domain.com"
],
"AllowedMethods": [
"GET",
"PUT"
],
"AllowedHeaders": [
"Authorization",
"x-amz-date",
"x-amz-content-sha256",
"content-type"
],
"ExposeHeaders": [
"ETag"
],
"MaxAgeSeconds": 3000
},
{
"AllowedOrigins": [
"*"
],
"AllowedMethods": [
"GET"
],
"MaxAgeSeconds": 3000
}
]
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>http://your-domain.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>x-amz-date</AllowedHeader>
<AllowedHeader>x-amz-content-sha256</AllowedHeader>
<AllowedHeader>content-type</AllowedHeader>
<ExposeHeader>ETag</ExposeHeader>
<MaxAgeSeconds>3000</MaxAgeSeconds>
</CORSRule>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>
NB please replace http://your-domain.com
with your front-end domain.
-
File storage:
-
->disk($disk)
Set S3 disk name, default is 's3'. -
->path($path)
Set storage path, default is bucket root. -
->keepOriginalName()
Keep the file original names, default is to auto generate hashed names "which is recommended".
-
-
File information:
-
->storeName($fileNameColumn)
Stores file_name in this attribute/column/Key. You can edit the file name before uploading from the uploader panel. -
->storeSize($fileSizeColumn)
Stores file_size (in bytes) in this attribute/column/Key. The size will be formatted (in KB, MB, ...) on the file card. -
->storeMeta($array)
Stores other metadata and creates UI to handle them from the uploader panel. The$array
keys are the attributes/columns/keys. e.g.->storeMeta( [ 'file_author' => [ 'name' => 'Author', 'placeholder' => 'your name please!', 'default' => 'No Author', ], 'file_description' => [ 'name' => 'Description', ], 'file_uploaded_at' => [ 'name' => 'Uploaded At', 'default' => now(), 'ui' => false, ], ] )
-
-
Model attributes:
By default the file_path is stored in the model attribute specified by the
make
method. Then if any other file information (file_name, file_size, metadata) are added they get stored in the corresponding attributes.For more flexibility all these attributes could be stored as an associative array under one single model attribute defined by
make
method.-
->storeAsArray($fileKeyColumn)
Set the array key that will hold the file_path. -
->storeAsMultipleArray($fileKeyColumn)
LikestoreAsArray
but allow multiple files.
If you would like to store the file information in separate "child" model that is related to the "main" model attribute defined by
make
method.-
->hasOne($fileKeyColumn)
Set the related model attribute that will hold the file_path, also valid formorphOne
. -
->hasMany($fileKeyColumn)
LikehasOne
but allow multiple files, also valid formorphMany
. -
->refreshListable()
Refresh listable fieldsHasOne
andHasMany
in your resource detail view each time you upload or delete file.
-
-
Uploader options:
-
->autoProceed()
Start uploading automatically after the first patch of files are selected. -
->allowMultipleUploads()
Allow adding more files after uploading the first patch of files. -
->restrictions($array)
Rules and conditions to limit the type and/or number of files that can be uploaded. e.g.->restrictions( [ 'maxFileSize' => 1024 * 1024 * 1024, 'minFileSize' => 50 * 1024, 'maxNumberOfFiles' => 10, 'minNumberOfFiles' => 2, 'allowedFileTypes' => [ 'image/*', 'video/*', '.pdf', ], ] )
-
->simultaneousChunks($integer)
The maximum amount of chunks to upload simultaneously. -
->chunkSize($integer)
The minimum chunk size in bytes to use when uploading the file. -
->panelHeight($integer)
The uploader panel height in pixels. -
->fileManagerSelectionType($string)
The type of selection via file manager window ('files', 'folders', 'both'), default is 'files'. -
->footerNote($string)
Text to be shown on the footer of the uploader panel. Useful when usingrestrictions
to give instructions. -
->displayPoweredByUppy()
Display Uppy team credits on the uploader panel. -
->translate($array)
Localize the uploader panel. e.g.->translate( [ 'dropPasteImportBoth' => 'Trascina i file qui, sfoglia %{browseFiles} o %{browseFolders}', 'browseFiles' => 'i file', 'browseFolders' => 'le cartelle', 'myDevice' => 'Dispositivo', 'screencast' => 'Schermo', ] )
NB you can get a list of available
$array
key from here.
-
-
File card:
->contentDisposition($array)
How the browser handles the file download, As['attachment']
or['inline']
or both['inline', 'attachment']
, default is['attachment']
.
Uploading multiple files with their (names, sizes, metadata). Then save files information as multiple array in files
attribute in User
model.
User model class:
class User extends Model
{
protected $fillable = ['files'];
protected $casts = [
'files' => 'array',
];
}
User resource class:
use Ahmedkandel\NovaS3MultipartUpload\NovaS3MultipartUpload;
class User extends Resource
{
public function fields(Request $request)
{
return [
// ...
NovaS3MultipartUpload::make('Files')
->path($request->user()->id.'-uploads')
->storeAsMultipleArray('file_path')
->storeName('file_name')
->storeSize('file_size')
->storeMeta(
[
'file_author' => [
'name' => 'Author',
'placeholder' => 'your name please!',
'default' => 'No Author',
],
'file_description' => [
'name' => 'Description',
],
]
),
];
}
}
Preview:
When files are uploaded the user model files attribute \App\User::find(1)->files
will have the following value:
[
{
"file_name": "Video.mkv",
"file_path": "1-uploads/To5SvZLTyT1XQcUWCTpmqH6GfrgLmoep0tP6EV9n.mkv",
"file_size": 207683,
"file_author": "No Author",
"file_description": null
},
{
"file_name": "Document.pdf",
"file_path": "1-uploads/RnEBFKa0EqDoKQRkXf27l4dZ7fQ8MTyBofMK202b.pdf",
"file_size": 77395,
"file_author": "Ahmed Kandil",
"file_description": "DDD"
}
]
Nova authorize the user to see the resource tool using ->canSee(closure)
method which accepts a Closure that should return true
or false
.
We have added more methods to this tool for more granulare control:
-
->canUpload(closure)
allow the user to upload file and show the uploader panel. -
->canView(closure)
allow the user to list uploaded file and show the files grid. -
->canDownload(closure)
allow the user to download file and show the download button in the file card. -
->canDelete(closure)
allow the user to delete file and show the delete button in the file card.
e.g. if you would like to allow the user to upload only if no file attribute is empty:
->canUpload(function () {
return empty($this->model()->video);
})
e.g. if you would like to allow the user to delete files in his own model (Post or Video):
->canDelete(function () {
return request()->user()->id === $this->model()->user_id;
})
NB by default all actions are authorized until you disallow them.
-
Image Editor: enable Uppy Image Editor plugin using
->useImageEditor()
method. The plugin is using the excellent Cropper.js.NB the editor will be only activated for image files.
-
Webcam: enable Uppy Webcam plugin using
->useWebcam()
method. Then you can record videos and take pictures to be uploaded.NB to be able to use the webcam you need https connection.
-
Screen Capture: enable Uppy Screen Capture plugin using
->useScreenCapture()
method. Then you can record your screen or applications to be uploaded.NB to be able to use the screen capture you need https connection.
This package is a resource tool NOT a resource field. This means it is only visible under the resource detail view as a panel and can not be inserted in another panel or tab, it must be a direct child of the resource fields array.
Why? After a lot of thinking we found that uploading file in the same request of creating a new model is not a good idea. Because the response duration will depend on the file upload progress, which means the user have to wait without any visiual indication hoping that everything will work. So we decided to separate the files (upload | download | delete) process from the model (create | edit) process.
Please see CHANGELOG for more information on what has changed recently.
The MIT License (MIT). Please see License File for more information.