You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 7.x-dev/crud-fields.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -872,6 +872,9 @@ CRUD::field([
872
872
873
873
> NOTE: Summernote does NOT sanitize the input. If you do not trust the users of this field, you should sanitize the input or output using something like HTML Purifier. Personally we like to use install [mewebstudio/Purifier](https://github.com/mewebstudio/Purifier) and add an [accessor or mutator](https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators) on the Model, so that wherever the model is created from (admin panel or app), the output will always be clean. [Example here](https://github.com/Laravel-Backpack/demo/commit/7342cffb418bb568b9e4ee279859685ddc0456c1).
874
874
875
+
#### Uploading files with summernote
876
+
877
+
Summernote saves images as base64 encoded strings in the database. If you want to save them as files on the server, you can use the [Summernote Uploader](https://backpackforlaravel.com/docs/7.x/crud-uploaders). Please note that the Summernote Uploader is part of the `backpack/pro` package.
875
878
Input preview:
876
879
877
880

Copy file name to clipboardExpand all lines: 7.x-dev/crud-uploaders.md
+193-6Lines changed: 193 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,12 +5,12 @@
5
5
<aname="upload-about"></a>
6
6
## About
7
7
8
-
Uploading and managing files is a common task in Admin Panels. Starting with Backpack v6, you can fully setup your upload fields in your field definition, using purpose-built classes we call Uploaders. No more need to create mutators, manual validation of input or custom code to handle the files - though you can still do that, if you want.
8
+
Uploading and managing files is a common task in Admin Panels. In Backpack v7, your field definition can include uploading logic, thanks to some classes we call Uploaders. You don't need to create mutators, manual validation of input or custom code to handle file upload - though you can still do that, if you want.
9
9
10
-
<aname="upload-how-it-works"></a>
11
-
## How it works
10
+
<aname="how-to-use-uploaders"></a>
11
+
## How to Use Uploaders
12
12
13
-
When adding an upload field (`upload`, `upload_multiple`, `image` or `dropzone`) to your operation, tell Backpack that you want to use the appropriate Uploader, by using `withFiles()`:
13
+
When adding an upload field (`upload`, `upload_multiple`, `image`, `dropzone`, `easymde`, `summernote`) to your operation, tell Backpack that you want to use the appropriate Uploader, by using `withFiles()`:
@@ -23,8 +23,8 @@ That's it. Backpack will now handle the upload, storage and deletion of the file
23
23
> - (*) If you want your files to be deleted when the entry is deleted, please [Configure File Deletion](#deleting-files-when-entry-is-deleted)
24
24
25
25
26
-
<aname="upload-configuration"></a>
27
-
## Configuring the Uploaders
26
+
<aname="how-to-configure-uploaders"></a>
27
+
## How to Configure Uploaders
28
28
29
29
The `withFiles()` method accepts an array of options that you can use to customize the upload.
30
30
@@ -56,6 +56,177 @@ This allows you to overwrite or set the uploader class for this field. You can u
56
56
-**`fileNamer`** - default: **null**
57
57
It accepts a `FileNameGeneratorInterface` instance or a closure. As the name implies, this will be used to generate the file name. Read more about in the [Naming uploaded files](#upload-name-files) section.
58
58
59
+
<aname="available-uploaders"></a>
60
+
## Available Uploaders
61
+
62
+
We've already created Uploaders for the most common scenarios:
63
+
- CRUD comes with `SingleFile`, `MultipleFiles`, `SingleBas64Image`
64
+
- PRO comes with `DropzoneUploader`, `EasyMDEUploader`, `SummernoteUploader`
65
+
- if you want to use spatie/medialibrary you can just install [medialibrary-uploaders](https://github.com/Laravel-Backpack/medialibrary-uploaders) to get `MediaAjaxUploader`, `MediaMultipleFiles`, `MediaSingleBase64Image`, `MediaSingleFile`
66
+
67
+
68
+
<aname="how-to-create-uploaders"></a>
69
+
## How to Create Uploaders
70
+
71
+
Do you want to create your own Uploader class, for your custom field? Here's how you can do that, and how Uploader classes work behind the scenes.
72
+
73
+
First thing you need to decide if you are creating a _non-ajax_ or _ajax_ uploader:
74
+
-_non-ajax_ uploaders process the file upload when you submit your form;
75
+
-_ajax_ uploaders process the file upload before the form is submitted, by submitting an AJAX request using Javascript;
If you custom uploader was created to work for a custom field (say it's called `custom_upload`), you can tell Backpack to always use this uploader for that field type - that way you don't have to specify it every time you use the field. You can do that in your Service Provider `boot()` method, by adding it to the `UploadersRepository`:
You can now use `CRUD::field('avatar')->type('custom_upload')->withFiles();` and it will use your custom uploader. What happens behind the scenes is that Backpack will register your uploader to run on 3 different model events: `saving`, `retrieved` and `deleting`.
138
+
139
+
The `Uploader` class has 3 "entry points" for the mentioned events: **`storeUploadedFiles()`**, **`retrieveUploadedFiles()`** and **`deleteUploadedFiles()`**. You can override these methods in your custom uploader, but typically you will not need to do that. The methods already delegate what will happen to the relevant methods (eg. if it's not a repeatable, call ```uploadFiles()```, othewise call ```uploadRepeatableFiles()```).
140
+
141
+
Notice this custom class you're creating is extending `Backpack\CRUD\app\Library\Uploaders\Uploader`. That base uploader class has most of the functionality implemented and uses **"strategy methods"** to configure the underlying behavior.
142
+
143
+
**`shouldUploadFiles`** - a method that returns a boolean to determine if the files should be uploaded. By default it returns true, but you can overwrite it to add your custom logic.
144
+
145
+
**`shouldKeepPreviousValuesUnchanged`** - a method that returns a boolean to determine if the previous values should be kept unchanged and not perform the upload.
146
+
147
+
**`hasDeletedFiles`** - a method that returns a boolean to determine if the files were deleted from the field.
148
+
149
+
**`getUploadedFilesFromRequest`** - this is the method that will be called to get the values sent in the request. Some uploaders require you get the `->files()` others the `->input()`. By default it returns the `->files()`.
150
+
151
+
This is the implementation of those methods in `SingleFile` uploader:
152
+
```php
153
+
protected function shouldKeepPreviousValueUnchanged(Model $entry, $entryValue): bool
154
+
{
155
+
// if a string is sent as the value, it means the file was not changed so we should keep
156
+
// previous value unchanged
157
+
return is_string($entryValue);
158
+
}
159
+
160
+
protected function hasDeletedFiles($entryValue): bool
161
+
{
162
+
// if the value is null, it means the file was deleted from the field
163
+
return $entryValue === null;
164
+
}
165
+
166
+
protected function shouldUploadFiles($value): bool
167
+
{
168
+
// when the value is an instance of UploadedFile, it means the file was uploaded and we should upload it
For the ajax uploaders, the process is similar, but your custom uploader class should extend `BackpackAjaxUploader` instead of `Uploader` (**note that this requires backpack/pro**).
176
+
177
+
```php
178
+
179
+
namespace App\Uploaders\CustomUploader;
180
+
181
+
use Backpack\Pro\Uploaders\BackpackAjaxUploader;
182
+
183
+
class CustomUploader extends BackpackAjaxUploader
184
+
{
185
+
// this is called on `saving` event of the main entry, at this point you already performed the upload
186
+
// of the files in the ajax endpoint. By default they are in a temp folder, so here is the place
187
+
// where you should move them to the final disk and path and setup what will be saved in the database.
188
+
public function uploadFiles(Model $entry, $values)
189
+
{
190
+
return $valueToBeStoredInTheDatabaseEntry;
191
+
}
192
+
193
+
// this is called when your uploader field is a subfield of a repeatable field. In here you receive
194
+
// the sent values in the current request and the previous repeatable values (only the uploads values).
195
+
protected function uploadRepeatableFiles($values, $previousValues)
196
+
{
197
+
// you should return an array of arrays (each sub array is a repeatable row) where the array key is the field name.
198
+
// backpack will merge this values along the other repeatable fields and save them in the database.
199
+
return [
200
+
[
201
+
'custom_upload' => 'path/file.jpg'
202
+
],
203
+
[
204
+
'custom_upload' => 'path/file.jpg'
205
+
]
206
+
];
207
+
}
208
+
}
209
+
```
210
+
211
+
The process to register the uploader in the `UploadersRepositoy` is the same as the non-ajax uploader. `app('UploadersRepository')->addUploaderClasses(['custom_upload' => \App\Uploaders\CustomUploader::class], 'withFiles');` in the boot method of your provider.
212
+
213
+
In addition to the field configuration, ajax uploaders require that you use the `AjaxUploadOperation` trait in your controller. The operation is responsible to register the ajax route where your files will be sent and the upload process will be handled and the delete route from where you can delete **temporary files**.
214
+
215
+
Similar to model events, there are two "setup" methods for those endpoints: **`processAjaxEndpointUploads()`** and **`deleteAjaxEndpointUpload()`**. You can overwrite them to add your custom logic but most of the time you will not need to do that and just implement the `uploadFiles()` and `uploadRepeatableFiles()` methods.
216
+
217
+
The ajax uploader also has the same "strategy methods" as the non-ajax uploader (see above), but adds a few more:
218
+
-**`ajaxEndpointSuccessResponse($files = null)`** - This should return a `JsonResponse` with the needed information when the upload is successful. By default it returns a json response with the file path.
219
+
-**`ajaxEndpointErrorResponse($message)`** - Use this method to change the endpoint response in case the upload failed. Similar to the success it should return a `JsonResponse`.
220
+
-**`getAjaxEndpointDisk()`** - By default a `temporaryDisk` is used to store the files before they are moved to the final disk (when uploadFiles() is called). You can overwrite this method to change the disk used.
221
+
-**`getAjaxEndpointPath()`** - By default the path is `/temp` but you can override this method to change the path used.
222
+
-**`getDefaultAjaxEndpointValidation()`** - Should return the default validation rules (in the format of `BackpackCustomRule`) for the ajax endpoint. By default it returns a `ValidGenericAjaxEndpoint` rule.
223
+
224
+
225
+
For any other customization you would like to perform, please check the source code of the `Uploader` and `BackpackAjaxUploader` classes.
@@ -184,6 +355,22 @@ class SomeModel extends Model
184
355
}
185
356
```
186
357
358
+
<aname="deleting-temporary-files"></a>
359
+
## Deleting temporary files
360
+
361
+
When using ajax uploaders, the files are uploaded to a temporary disk and path before being moved to the final disk and path. If by some reason the user does not finish the operation, those files may lay around in your server temporary folder.
362
+
To delete them, we have created a `backpack:purge-temporary-folder` command that you can schedule to run every day, or in the time frame that better suits your needs.
For additional configuration check the `config/backpack/operations/ajax-uploads.php` file. Those configurations can also be passed on a "per-command" basis, eg: `backpack:purge-temporary-folder --disk=public --path=temp --older-than=5`.
0 commit comments