From a845b7eab2f82708ef6979874cc2e1f941579a4c Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 22 Nov 2024 11:15:31 +0000 Subject: [PATCH 01/63] add note about key requirements --- 6.x/crud-fields.md | 14 ++++++++++++++ 7.x-dev/crud-fields.md | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/6.x/crud-fields.md b/6.x/crud-fields.md index b9a69023..468aa21b 100644 --- a/6.x/crud-fields.md +++ b/6.x/crud-fields.md @@ -1138,6 +1138,13 @@ CRUD::field([ // Address google Using Google Places API is dependent on using an API Key. Please [get an API key](https://console.cloud.google.com/apis/credentials) - you do have to configure billing, but you qualify for $200/mo free usage, which covers most use cases. Then copy-paste that key as your ```services.google_places.key``` value. +**IMPORTANT NOTE**: Your key needs access to the following APIS: +- Maps JavaScript API; +- Places API; +- Geocoding API. + +While developing you can use an "unrestricted key" (no restrictions for where the key is used), but for production you should use a separate key, and **MAKE SURE** you restrict the usage of that key to your own domain. + So inside your ```config/services.php``` please add the items below: ```php 'google_places' => [ @@ -1558,6 +1565,13 @@ Using Google Places API is dependent on using an API Key. Please [get an API key ], ``` +**IMPORTANT NOTE**: Your key needs access to the following APIS: +- Maps JavaScript API; +- Places API; +- Geocoding API. + +While developing you can use an "unrestricted key" (no restrictions for where the key is used), but for production you should use a separate key, and **MAKE SURE** you restrict the usage of that key to your own domain. + **How to save in multiple inputs?** There are cases where you rather save the information on separate inputs in the database. In that scenario you should use [Laravel mutators and accessors](https://laravel.com/docs/10.x/eloquent-mutators). Using the same field as previously shown (**field name is `location`**), and having `latitude`, `longitude`, `full_address` as the database columns, we can save and retrieve them separately too: diff --git a/7.x-dev/crud-fields.md b/7.x-dev/crud-fields.md index 3f33283f..b50778e2 100644 --- a/7.x-dev/crud-fields.md +++ b/7.x-dev/crud-fields.md @@ -1138,6 +1138,13 @@ CRUD::field([ // Address google Using Google Places API is dependent on using an API Key. Please [get an API key](https://console.cloud.google.com/apis/credentials) - you do have to configure billing, but you qualify for $200/mo free usage, which covers most use cases. Then copy-paste that key as your ```services.google_places.key``` value. +**IMPORTANT NOTE**: Your key needs access to the following APIS: +- Maps JavaScript API; +- Places API; +- Geocoding API. + +While developing you can use an "unrestricted key" (no restrictions for where the key is used), but for production you should use a separate key, and **MAKE SURE** you restrict the usage of that key to your own domain. + So inside your ```config/services.php``` please add the items below: ```php 'google_places' => [ @@ -1423,6 +1430,13 @@ Using Google Places API is dependent on using an API Key. Please [get an API key ], ``` +**IMPORTANT NOTE**: Your key needs access to the following APIS: +- Maps JavaScript API; +- Places API; +- Geocoding API. + +While developing you can use an "unrestricted key" (no restrictions for where the key is used), but for production you should use a separate key, and **MAKE SURE** you restrict the usage of that key to your own domain. + **How to save in multiple inputs?** There are cases where you rather save the information on separate inputs in the database. In that scenario you should use [Laravel mutators and accessors](https://laravel.com/docs/10.x/eloquent-mutators). Using the same field as previously shown (**field name is `location`**), and having `latitude`, `longitude`, `full_address` as the database columns, we can save and retrieve them separately too: From 515cf948a02fdbf6434ac82d9e7ff5ddd69799a1 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Mon, 25 Nov 2024 12:20:47 +0200 Subject: [PATCH 02/63] polish v7 wysiwygs docs --- 7.x-dev/crud-columns.md | 79 ++++++++++++++++++----------------------- 7.x-dev/crud-fields.md | 53 ++++++++------------------- 2 files changed, 49 insertions(+), 83 deletions(-) diff --git a/7.x-dev/crud-columns.md b/7.x-dev/crud-columns.md index f7956e27..63478d37 100644 --- a/7.x-dev/crud-columns.md +++ b/7.x-dev/crud-columns.md @@ -208,6 +208,23 @@ Show connected items selected via checklist_dependency field. It's definition is
+ +### ckeditor PRO + +The perfect match for the [CKEditor field](https://github.com/Laravel-Backpack/ckeditor-field). The CKEditor column will just output the non-escaped text value of a db column (or model attribute). Its definition is simple: + +```php +[ + 'name' => 'info', // The db column name + 'label' => 'Info', // Table column heading + 'type' => 'ckeditor', +], +``` + +For more information, please see [backpack/ckeditor-field](https://github.com/Laravel-Backpack/ckeditor-field) on Github - that is the add-on that provides this functionality. + +
+ ### closure @@ -818,6 +835,23 @@ The text column will just output the text value of a db column (or model attribu
+ +### tinymce PRO + +The perfect match for the [`tinymce` field](https://github.com/Laravel-Backpack/tinymce-field). The tinymce column will just output the non-escaped text value of a db column (or model attribute). Its definition is simple: +```php +[ + 'name' => 'info', // The db column name + 'label' => 'Info', // Table column heading + 'type' => 'tinymce', +], +``` + +For more information on the TinyMCE field and column, see [backpack/tinymce-field]( +The perfect match for the [`tinymce` field](https://github.com/Laravel-Backpack/tinymce-field)) on Github - that's the addon that provides this functionality. + +
+ ### time @@ -983,21 +1017,6 @@ Show a thumbnail image stored in the db column as `base64` image string.
- -### ckeditor PRO - -The ckeditor column will just output the non-escaped text value of a db column (or model attribute). Its definition is: - -```php -[ - 'name' => 'info', // The db column name - 'label' => 'Info', // Table column heading - 'type' => 'ckeditor', -], -``` - -
- ### date_picker PRO @@ -1363,21 +1382,6 @@ Its definition is very similar to the [table *field type*](/docs/{{version}}/cru
- -### tinymce PRO - -The tinymce column will just output the non-escaped text value of a db column (or model attribute). Its definition is: - -```php -[ - 'name' => 'info', // The db column name - 'label' => 'Info', // Table column heading - 'type' => 'tinymce', -], -``` - -
- ### video PRO @@ -1394,21 +1398,6 @@ Display a small screenshot for a YouTube or Vimeo video, stored in the database
- -### wysiwyg PRO - -The wysiwyg column will just output the non-escaped text value of a db column (or model attribute). Its definition is: - -```php -[ - 'name' => 'info', // The db column name - 'label' => 'Info', // Table column heading - 'type' => 'wysiwyg', -], -``` - -
- ## Overwriting Default Column Types diff --git a/7.x-dev/crud-fields.md b/7.x-dev/crud-fields.md index b50778e2..fed013a9 100644 --- a/7.x-dev/crud-fields.md +++ b/7.x-dev/crud-fields.md @@ -383,6 +383,13 @@ Input preview:
+ +### ckeditor + +Show a WYSIWIG field to the user, powered by CKEditor. This field is provided as a first-party add-on - see instructions [here](https://github.com/Laravel-Backpack/ckeditor-field). + +
+ ### color @@ -839,7 +846,7 @@ Input preview: ### summernote -Show a [Summernote wysiwyg editor](http://summernote.org/) to the user. +Show a [Summernote WYSIWYG editor](http://summernote.org/) to the user. ```php CRUD::field([ // Summernote @@ -963,6 +970,13 @@ CRUD::field([ // Time
+ +### tinymce + +Show a WYSIWYG editor powered by TinyMCE to the admin. This is provided using a first-party add-on - see instructions [here](https://github.com/Laravel-Backpack/tinymce-field). + +
+ ### upload @@ -1193,13 +1207,6 @@ Input preview:
- -### ckeditor - -This field is providedy by a third-party integration, you can find instructions on how to install and use it [here](https://github.com/Laravel-Backpack/ckeditor-field). - -
- ### date_range PRO @@ -2541,13 +2548,6 @@ Input preview: ![CRUD Field - table](https://backpackforlaravel.com/uploads/docs-4-2/fields/table.png) -
- - -### tinymce - -TinyMCE is now provided by a third-party package, you can find instructions on how to use and configure it [here](https://github.com/Laravel-Backpack/tinymce-field). -
@@ -2581,29 +2581,6 @@ So you should use [attribute casting](https://mattstauffer.com/blog/laravel-5.0- Vimeo does not require an API key in order to query their DB, but YouTube does, even though their free quota is generous. You can get a free YouTube API Key inside [Google Developers Console](https://console.developers.google.com/) ([video tutorial here](https://www.youtube.com/watch?v=pP4zvduVAqo)). Please DO NOT use our API Key - create your own. The key above is there just for your convenience, to easily try out the field. As soon as you decide to use this field type, create an API Key and use _your_ API Key. Our key hits its ceiling every month, so if you use our key most of the time it won't work. -
- - -### wysiwyg PRO - -Show a wysiwyg (CKEditor) to the user. - -```php -CRUD::field([ // WYSIWYG Editor - 'name' => 'description', - 'label' => 'Description', - 'type' => 'wysiwyg', - - // optional configuration - 'options' => [], // ckeditor configuration options - - // elfinder configuration options when using [the file manager package](https://github.com/Laravel-Backpack/FileManager) - // to use this feature you need to be running backpack/pro:2.2.1 or higher and backpack/filemanager:3.0.8 or higher - // for `elfinderOptions` passing an empty array or `true` will enable the file manager with default options - 'elfinderOptions' => [], -]); -``` - ## Overwriting Default Field Types From 6a89dc922c42e863bbee3fadf7b490ca8d4b8dd1 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Mon, 25 Nov 2024 14:13:23 +0200 Subject: [PATCH 03/63] reorganize uploader docs --- 7.x-dev/crud-uploaders.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index 2b49ef32..14d4f903 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -5,10 +5,10 @@ ## About -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. +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. - -## How it works + +## How to Use Uploaders 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()`: @@ -23,8 +23,8 @@ That's it. Backpack will now handle the upload, storage and deletion of the file > - (*) If you want your files to be deleted when the entry is deleted, please [Configure File Deletion](#deleting-files-when-entry-is-deleted) - -## Configuring the Uploaders + +## How to Configure Uploaders The `withFiles()` method accepts an array of options that you can use to customize the upload. @@ -56,6 +56,25 @@ This allows you to overwrite or set the uploader class for this field. You can u - **`fileNamer`** - default: **null** 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. + +## Available Uploaders + +We've already created Uploaders for the most common scenarios: +- CRUD comes with `SingleFile`, `MultipleFiles`, `SingleBas64Image` +- PRO comes with `AjaxUploader`, `DropzoneUploader`, `EasyMDEUploader` +- 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` + + + +## How to Create Uploaders + +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. + +// TODO + + +## FAQ about Uploaders + ### Handling uploads in relationship fields From 42dd2e7b40224b77f1422cb0c5639f0206e733ed Mon Sep 17 00:00:00 2001 From: pxpm Date: Wed, 27 Nov 2024 12:46:25 +0000 Subject: [PATCH 04/63] add docs on how to create an uploader --- 7.x-dev/crud-uploaders.md | 127 +++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index 14d4f903..6e70c85f 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -70,7 +70,132 @@ We've already created Uploaders for the most common scenarios: 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. -// TODO +First thing you need to decide if you need "Ajax" or "Non-Ajax" upload. The big difference is that the "non-ajax" uploaders process the file upload when you submit your form, while the ajax upload process the file using a javascript ajax request, so it can be uploaded before you submit the form. + +First let's see how to create a non-ajax uploader, for that we will create a `CustomUploader` class that extends the abstract class `Uploader`. + +```php +namespace App\Uploaders\CustomUploader; + +use Backpack\CRUD\app\Library\Uploaders\Uploader; + +class CustomUploader extends Uploader +{ + // the function we need to implement + public function uploadFiles(Model $entry, $values) + { + // $entry is the model instance we are working with + // $values is the sent files from request. + + // do your upload logic here + + return $valueToBeStoredInTheDatabaseEntry; + } + + // in case you want to use your uploader inside repeatable fields + protected function uploadRepeatableFiles($values, $previousValues, $entry = null) + { + } +} +``` + +You can now use this uploader in your field definition: + +```php +CRUD::field('avatar')->type('upload')->withFiles([ + 'uploader' => \App\Uploaders\CustomUploader::class, +]); +``` + +But most likely, you have a `custom_upload` field that you'd like to use this uploader without having to specify it every time. You can do that by adding it to the `UploadersRepository` in your Service Provider `boot()` method: + +```php +// in your App\Providers\AppServiceProvider.php + +protected function boot() +{ + app('UploadersRepository')->addUploaderClasses(['custom_upload' => \App\Uploaders\CustomUploader::class], 'withFiles'); +} +``` + +You can now use `CRUD::field('avatar')->type('custom_upload')->withFiles();` and it will use your custom uploader. What happen behind the scenes is that Backpack will register your uploader to be ran in 3 different model events: `saving`, `retrieved` and `deleting`. + +The `Uploader` class has 3 "entry points" for the mentioned events: **`storeUploadedFiles()`**, **`retrieveUploadedFiles()`** and **`deleteUploadedFiles()`**. You can overwrite these methods in your custom uploader to add your custom logic but for most uploaders you will not need to overwrite them as they are "setup" methods for the action that will be performed, and after setup they call the relevant methods that each uploader will implement, like ```uploadFiles()``` or ```uploadRepeatableFiles()```. + +The base uploader class has most of the functionality implemented and use **"strategy methods"** to configure the underlying behavior. + +**`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. + +**`shouldKeepPreviousValuesUnchanged`** - a method that returns a boolean to determine if the previous values should be kept unchanged and not perform the upload. + +**`hasDeletedFiles`** - a method that returns a boolean to determine if the files were deleted from the field. + +This is the implementation of those methods in `SingleFile` uploader: +```php +protected function shouldKeepPreviousValueUnchanged(Model $entry, $entryValue): bool +{ + // if a string is sent as the value, it means the file was not changed so we should keep + // previous value unchanged + return is_string($entryValue); +} + +protected function hasDeletedFiles($entryValue): bool +{ + // if the value is null, it means the file was deleted from the field + return $entryValue === null; +} + +protected function shouldUploadFiles($value): bool +{ + // when the value is an instance of UploadedFile, it means the file was uploaded and we should upload it + return is_a($value, 'Illuminate\Http\UploadedFile', true); +} +``` + +For the ajax uploaders, the process is similar, but the `CustomUploader` class should extend `BackpackAjaxUploader` **(requires backpack/pro)** instead of `Uploader`. + +```php + +namespace App\Uploaders\CustomUploader; + +use Backpack\Pro\Uploaders\BackpackAjaxUploader; + +class CustomUploader extends BackpackAjaxUploader +{ + // this is called on `saving` event of the main entry, at this point you already performed the upload + // of the files in the ajax endpoint. By default they are in a temp folder, so here is the place + // where you should move them to the final disk and path and setup what will be saved in the database. + public function uploadFiles(Model $entry, $values) + { + return $valueToBeStoredInTheDatabaseEntry; + } + + // in case you want to use your uploader inside repeatable fields + protected function uploadRepeatableFiles($values, $previousValues, $entry = null) + { + } +} +``` + +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. + +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**. + +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. + +The ajax uploader also has the same "strategy methods" as the non-ajax uploader (see above), but adds a few more: +**`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. + +**`ajaxEndpointErrorResponse($message)`** - use this method to change the endpoint response in case the upload failed. Similar to the success it should return a `JsonResponse`. + +**`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. + +**`getAjaxEndpointPath()`** - by default the path is `/temp` but you can overwrite this method to change the path used. + +**`getDefaultAjaxEndpointValidation()`** - Should return the default validation rules (in the format of `BackpackCustomRule`) for the ajax endpoint. By default it returns a `ValidGenericAjaxEndpoint` rule. + + +For any other customization you would like to perform, please check the source code of the `Uploader` and `BackpackAjaxUploader` classes. ## FAQ about Uploaders From 000b574e7e6d2674c5af4b269c4cb2b5bea86d45 Mon Sep 17 00:00:00 2001 From: pxpm Date: Wed, 27 Nov 2024 13:06:40 +0000 Subject: [PATCH 05/63] add getUploadedFilesFromRequest strategy method --- 7.x-dev/crud-uploaders.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index 6e70c85f..91d70739 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -130,6 +130,8 @@ The base uploader class has most of the functionality implemented and use **"str **`hasDeletedFiles`** - a method that returns a boolean to determine if the files were deleted from the field. +**`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()`. + This is the implementation of those methods in `SingleFile` uploader: ```php protected function shouldKeepPreviousValueUnchanged(Model $entry, $entryValue): bool From 208046b7598ffe8b04a47268fa954392bc8d398a Mon Sep 17 00:00:00 2001 From: pxpm Date: Mon, 2 Dec 2024 13:47:03 +0000 Subject: [PATCH 06/63] update docs for temporary file deletion --- 7.x-dev/crud-uploaders.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index 91d70739..7b78ac1e 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -330,6 +330,22 @@ class SomeModel extends Model } ``` + +## Deleting temporary files + +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. +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. + +```php +// in your routes/console +use Illuminate\Console\Scheduling\Schedule; + +Schedule::command('backpack:purge-temporary-folder')->daily(); + +``` + +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`. + ### Configuring uploaders in custom fields From ea3aee810c1ea13c6fd98e891369eeaf807f31b0 Mon Sep 17 00:00:00 2001 From: pxpm Date: Tue, 3 Dec 2024 10:45:03 +0000 Subject: [PATCH 07/63] add docs in field about uploader --- 7.x-dev/crud-fields.md | 3 +++ 7.x-dev/crud-uploaders.md | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/7.x-dev/crud-fields.md b/7.x-dev/crud-fields.md index fed013a9..b0310059 100644 --- a/7.x-dev/crud-fields.md +++ b/7.x-dev/crud-fields.md @@ -872,6 +872,9 @@ CRUD::field([ > 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). +#### Uploading files with summernote + +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 File Upload](https://backpackforlaravel.com/docs/7.x/crud-uploaders) . Please note that the Summernote Uploader is part of the `backpack/pro` package. Input preview: ![CRUD Field - summernote](https://backpackforlaravel.com/uploads/docs-4-2/fields/summernote.png) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index 7b78ac1e..dad7b7dc 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -10,7 +10,7 @@ Uploading and managing files is a common task in Admin Panels. In Backpack v7, y ## How to Use Uploaders -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()`: +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()`: ```php CRUD::field('avatar')->type('upload')->withFiles(); @@ -61,7 +61,7 @@ It accepts a `FileNameGeneratorInterface` instance or a closure. As the name imp We've already created Uploaders for the most common scenarios: - CRUD comes with `SingleFile`, `MultipleFiles`, `SingleBas64Image` -- PRO comes with `AjaxUploader`, `DropzoneUploader`, `EasyMDEUploader` +- PRO comes with `DropzoneUploader`, `EasyMDEUploader`, `SummernoteUploader` - 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` From d847a9c0fe6eed741d339799ec31ca157dba795f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Thu, 5 Dec 2024 12:22:51 +0200 Subject: [PATCH 08/63] Apply suggestions from code review --- 7.x-dev/crud-fields.md | 2 +- 7.x-dev/crud-uploaders.md | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/7.x-dev/crud-fields.md b/7.x-dev/crud-fields.md index b0310059..78c62af9 100644 --- a/7.x-dev/crud-fields.md +++ b/7.x-dev/crud-fields.md @@ -874,7 +874,7 @@ CRUD::field([ #### Uploading files with summernote -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 File Upload](https://backpackforlaravel.com/docs/7.x/crud-uploaders) . Please note that the Summernote Uploader is part of the `backpack/pro` package. +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. Input preview: ![CRUD Field - summernote](https://backpackforlaravel.com/uploads/docs-4-2/fields/summernote.png) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index dad7b7dc..a2b11e65 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -70,7 +70,12 @@ We've already created Uploaders for the most common scenarios: 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. -First thing you need to decide if you need "Ajax" or "Non-Ajax" upload. The big difference is that the "non-ajax" uploaders process the file upload when you submit your form, while the ajax upload process the file using a javascript ajax request, so it can be uploaded before you submit the form. +First thing you need to decide if you are creating a _non-ajax_ or _ajax_ uploader: +- _non-ajax_ uploaders process the file upload when you submit your form; +- _ajax_ uploaders process the file upload before the form is submitted, by submitting an AJAX request using Javascript; + + +## How to Create a Custom Non-Ajax Uploader First let's see how to create a non-ajax uploader, for that we will create a `CustomUploader` class that extends the abstract class `Uploader`. @@ -107,7 +112,7 @@ CRUD::field('avatar')->type('upload')->withFiles([ ]); ``` -But most likely, you have a `custom_upload` field that you'd like to use this uploader without having to specify it every time. You can do that by adding it to the `UploadersRepository` in your Service Provider `boot()` method: +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`: ```php // in your App\Providers\AppServiceProvider.php @@ -118,11 +123,11 @@ protected function boot() } ``` -You can now use `CRUD::field('avatar')->type('custom_upload')->withFiles();` and it will use your custom uploader. What happen behind the scenes is that Backpack will register your uploader to be ran in 3 different model events: `saving`, `retrieved` and `deleting`. +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`. The `Uploader` class has 3 "entry points" for the mentioned events: **`storeUploadedFiles()`**, **`retrieveUploadedFiles()`** and **`deleteUploadedFiles()`**. You can overwrite these methods in your custom uploader to add your custom logic but for most uploaders you will not need to overwrite them as they are "setup" methods for the action that will be performed, and after setup they call the relevant methods that each uploader will implement, like ```uploadFiles()``` or ```uploadRepeatableFiles()```. -The base uploader class has most of the functionality implemented and use **"strategy methods"** to configure the underlying behavior. +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. **`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. @@ -152,9 +157,11 @@ protected function shouldUploadFiles($value): bool // when the value is an instance of UploadedFile, it means the file was uploaded and we should upload it return is_a($value, 'Illuminate\Http\UploadedFile', true); } -``` -For the ajax uploaders, the process is similar, but the `CustomUploader` class should extend `BackpackAjaxUploader` **(requires backpack/pro)** instead of `Uploader`. + +## How to Create a Custom Ajax Uploader + +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**). ```php @@ -186,15 +193,11 @@ In addition to the field configuration, ajax uploaders require that you use the 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. The ajax uploader also has the same "strategy methods" as the non-ajax uploader (see above), but adds a few more: -**`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. - -**`ajaxEndpointErrorResponse($message)`** - use this method to change the endpoint response in case the upload failed. Similar to the success it should return a `JsonResponse`. - -**`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. - -**`getAjaxEndpointPath()`** - by default the path is `/temp` but you can overwrite this method to change the path used. - -**`getDefaultAjaxEndpointValidation()`** - Should return the default validation rules (in the format of `BackpackCustomRule`) for the ajax endpoint. By default it returns a `ValidGenericAjaxEndpoint` rule. +- **`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. +- **`ajaxEndpointErrorResponse($message)`** - Use this method to change the endpoint response in case the upload failed. Similar to the success it should return a `JsonResponse`. +- **`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. +- **`getAjaxEndpointPath()`** - By default the path is `/temp` but you can override this method to change the path used. +- **`getDefaultAjaxEndpointValidation()`** - Should return the default validation rules (in the format of `BackpackCustomRule`) for the ajax endpoint. By default it returns a `ValidGenericAjaxEndpoint` rule. For any other customization you would like to perform, please check the source code of the `Uploader` and `BackpackAjaxUploader` classes. From 311d7f66709b9d9aa66898fa970e0d9eeb41497d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Thu, 5 Dec 2024 12:23:39 +0200 Subject: [PATCH 09/63] Apply suggestions from code review --- 7.x-dev/crud-uploaders.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index a2b11e65..44bb4cf1 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -75,7 +75,7 @@ First thing you need to decide if you are creating a _non-ajax_ or _ajax_ upload - _ajax_ uploaders process the file upload before the form is submitted, by submitting an AJAX request using Javascript; -## How to Create a Custom Non-Ajax Uploader +### How to Create a Custom Non-Ajax Uploader First let's see how to create a non-ajax uploader, for that we will create a `CustomUploader` class that extends the abstract class `Uploader`. @@ -159,7 +159,7 @@ protected function shouldUploadFiles($value): bool } -## How to Create a Custom Ajax Uploader +### How to Create a Custom Ajax Uploader 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**). From 0a299e61d35302b74f39e3f1769a700c6fe5e6de Mon Sep 17 00:00:00 2001 From: Pedro Martins Date: Thu, 5 Dec 2024 10:52:33 +0000 Subject: [PATCH 10/63] Update 7.x-dev/crud-uploaders.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cristian Tăbăcitu --- 7.x-dev/crud-uploaders.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index 44bb4cf1..a56beaf3 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -125,7 +125,7 @@ protected function boot() 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`. -The `Uploader` class has 3 "entry points" for the mentioned events: **`storeUploadedFiles()`**, **`retrieveUploadedFiles()`** and **`deleteUploadedFiles()`**. You can overwrite these methods in your custom uploader to add your custom logic but for most uploaders you will not need to overwrite them as they are "setup" methods for the action that will be performed, and after setup they call the relevant methods that each uploader will implement, like ```uploadFiles()``` or ```uploadRepeatableFiles()```. +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()```). 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. From 7873d5a5fde5901935e74a4ece7f13ca9a150a1b Mon Sep 17 00:00:00 2001 From: pxpm Date: Thu, 5 Dec 2024 12:26:42 +0000 Subject: [PATCH 11/63] add repeatable uploader docs --- 7.x-dev/crud-uploaders.md | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/7.x-dev/crud-uploaders.md b/7.x-dev/crud-uploaders.md index a56beaf3..e5089291 100644 --- a/7.x-dev/crud-uploaders.md +++ b/7.x-dev/crud-uploaders.md @@ -97,9 +97,20 @@ class CustomUploader extends Uploader return $valueToBeStoredInTheDatabaseEntry; } - // in case you want to use your uploader inside repeatable fields - protected function uploadRepeatableFiles($values, $previousValues, $entry = null) + // this is called when your uploader field is a subfield of a repeatable field. In here you receive + // the sent values in the current request and the previous repeatable values (only the uploads values). + protected function uploadRepeatableFiles($values, $previousValues) { + // you should return an array of arrays (each sub array is a repeatable row) where the array key is the field name. + // backpack will merge this values along the other repeatable fields and save them in the database. + return [ + [ + 'custom_upload' => 'path/file.jpg' + ], + [ + 'custom_upload' => 'path/file.jpg' + ] + ]; } } ``` @@ -179,9 +190,20 @@ class CustomUploader extends BackpackAjaxUploader return $valueToBeStoredInTheDatabaseEntry; } - // in case you want to use your uploader inside repeatable fields - protected function uploadRepeatableFiles($values, $previousValues, $entry = null) + // this is called when your uploader field is a subfield of a repeatable field. In here you receive + // the sent values in the current request and the previous repeatable values (only the uploads values). + protected function uploadRepeatableFiles($values, $previousValues) { + // you should return an array of arrays (each sub array is a repeatable row) where the array key is the field name. + // backpack will merge this values along the other repeatable fields and save them in the database. + return [ + [ + 'custom_upload' => 'path/file.jpg' + ], + [ + 'custom_upload' => 'path/file.jpg' + ] + ]; } } ``` From 9e874cbe6e29ac04963235cd5fda2ce4bf6eb4ad Mon Sep 17 00:00:00 2001 From: pxpm Date: Wed, 18 Dec 2024 10:50:44 +0000 Subject: [PATCH 12/63] fix switch docs --- 6.x/crud-fields.md | 2 +- 7.x-dev/crud-fields.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/6.x/crud-fields.md b/6.x/crud-fields.md index 468aa21b..b054b92e 100644 --- a/6.x/crud-fields.md +++ b/6.x/crud-fields.md @@ -883,7 +883,7 @@ CRUD::field([ // Switch 'label' => 'I have not read the terms and conditions and I never will', // optional - 'color' => 'primary', // May be any bootstrap color class or an hex color + 'color' => '#232323', // in CoreUI v2 theme you can also specify bootstrap colors, like `primary`, `danger`, `success`, etc You can also overwrite the `--bg-switch-checked-color` css variable to change the color of the switch when it's checked 'onLabel' => '✓', 'offLabel' => '✕', ]); diff --git a/7.x-dev/crud-fields.md b/7.x-dev/crud-fields.md index fed013a9..2dfe9206 100644 --- a/7.x-dev/crud-fields.md +++ b/7.x-dev/crud-fields.md @@ -890,7 +890,7 @@ CRUD::field([ // Switch 'label' => 'I have not read the terms and conditions and I never will', // optional - 'color' => 'primary', // May be any bootstrap color class or an hex color + 'color' => '#232323', // in CoreUI v2 theme you can also specify bootstrap colors, like `primary`, `danger`, `success`, etc You can also overwrite the `--bg-switch-checked-color` css variable to change the color of the switch when it's checked 'onLabel' => '✓', 'offLabel' => '✕', ]); From e4a31eabe399b6a89e4b9ca2946cb8cc1ffb830a Mon Sep 17 00:00:00 2001 From: Avrora Date: Thu, 2 Jan 2025 14:51:49 +0200 Subject: [PATCH 13/63] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8dea706d..8056e3e6 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,5 @@ You can find the online version of the Backpack documentation at https://backpac - pull requests are welcome and appreciated; - pull requests should point to the ```master``` branch; - all links should point to the current version of the documentation page (ex: ```/docs/{{version}}/installation```); -- all images should be uploaded to ```https://backpackforlaravel.com/uploads/docs/``` and used from there; ask @tabacitu to help upload them; +- all images should be uploaded to ```https://backpackforlaravel.com/uploads/docs/``` and used from there; ask [@tabacitu](https://github.com/tabacitu) to help upload them; - all headings should be prepended by an HTML anchor, with the name of the heading; this way, Algolia can take the user directly to that heading (ex: ``````); From 10c58a4e5744c0d6e719d7cdc011b85dc01f4e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Fri, 3 Jan 2025 12:44:34 +0200 Subject: [PATCH 14/63] add docs for `addClause()` and `addBaseClause()` I didn't find any place where we had this documented, so here goes: --- 6.x/crud-filters.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/6.x/crud-filters.md b/6.x/crud-filters.md index 205e3154..8a1221ae 100644 --- a/6.x/crud-filters.md +++ b/6.x/crud-filters.md @@ -666,3 +666,27 @@ function() { // if the filter is active (the GET parameter "draft" exits) // CRUD::addClause('draft'); }); ``` + + + +### When to use `addClause()` or `addBaseClause()` to apply filtering logic + +In most of our filter examples we use `CRUD::addClause()` to apply filtering logic to that Eloquent model. This allows you to call methods on that model, either standard Laravel methods like `where()` or custom methods like scopes: + +```php +CRUD::addClause('where', 'total', '=', '0'); // call standard laravel method "where" with params +CRUD::addClause('free'); // call free() on the Model, which would itself call scopeFree() +``` + +When the filter is selected, your List operation will also show a small text: "_Showing 1 to 10 entries (filtered from 998)_". + +But there's another method you can use to add filtering to the Eloquent model - `addBaseClause()`. This works EXACTLY the same as `addClause()` but the filtering happens _earlier_ in the lifecycle, before pagination is even calculated. That means your users will no longer see the end part of the text above. With the EXACT same filtering, happening before pagination is calculated, your text will become: "_Showing 1 to 10 entries._". In short: + +```php +CRUD::addClause('where', 'total', '=', '0'); // Showing 1 to 10 entries (filtered from 998) +CRUD::addBaseClause('where', 'total', '=', '0'); // Showing 1 to 10 entries +``` + +When should you use one or the other? +- in 99% of the cases you should probably use `addClause()`; it's more intuitive and informative for the admin, once they click a filter, to have feedback that what they see is a filtered list, out of a bigger list; +- in 1% of the cases though, when you want to actually _hide_ the total number of entries in the table, you should use `addBaseClause()` instead; for example, if you want to ONLY show the articles of the current logged in person, you would not want them to how many entries are in the database, so you should use `addBaseClause()`; From 5f7f63f2edf84dcae14b98afb58a5e3d10775088 Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 3 Jan 2025 12:20:40 +0000 Subject: [PATCH 15/63] add append attributes docs --- 6.x/crud-operation-fetch.md | 26 ++++++++++++++++++++++++++ 7.x-dev/crud-operation-fetch.md | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/6.x/crud-operation-fetch.md b/6.x/crud-operation-fetch.md index 2685f7b3..cc13a988 100644 --- a/6.x/crud-operation-fetch.md +++ b/6.x/crud-operation-fetch.md @@ -84,6 +84,32 @@ public function fetchUser() { } ``` +**Adding attributes to fetched models without appends** + +It's already possible to add attributes to the fetched models using the `appends` property in the model. However, this method has some drawbacks, like the fact that the appended attributes will be added to all instances of the model, whenever they are used, not only when they are fetched. If you want to add attributes to the fetched models without using the `appends` property in the model, you can use the `append_attributes` in the fetch configuration. For example: + +```php +public function fetchUser() { + return $this->fetch([ + 'model' => User::class, + 'append_attributes' => ['something'], + ]); + } + +// User.php model +public function something(): Attribute +{ + return Attribute::make( + get: function (mixed $value, array $attributes) { + return $attributes['something_else']; + }, + ); +} + +// and in your field definition +CRUD::field('my_ajax_field')->attribute('something'); +``` + ## Using FetchOperation with `select2_ajax` filter diff --git a/7.x-dev/crud-operation-fetch.md b/7.x-dev/crud-operation-fetch.md index 2685f7b3..cc13a988 100644 --- a/7.x-dev/crud-operation-fetch.md +++ b/7.x-dev/crud-operation-fetch.md @@ -84,6 +84,32 @@ public function fetchUser() { } ``` +**Adding attributes to fetched models without appends** + +It's already possible to add attributes to the fetched models using the `appends` property in the model. However, this method has some drawbacks, like the fact that the appended attributes will be added to all instances of the model, whenever they are used, not only when they are fetched. If you want to add attributes to the fetched models without using the `appends` property in the model, you can use the `append_attributes` in the fetch configuration. For example: + +```php +public function fetchUser() { + return $this->fetch([ + 'model' => User::class, + 'append_attributes' => ['something'], + ]); + } + +// User.php model +public function something(): Attribute +{ + return Attribute::make( + get: function (mixed $value, array $attributes) { + return $attributes['something_else']; + }, + ); +} + +// and in your field definition +CRUD::field('my_ajax_field')->attribute('something'); +``` + ## Using FetchOperation with `select2_ajax` filter From 07bbc4dfd46d0e7a3db2995008f5004b99fbb52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Mon, 27 Jan 2025 09:52:53 +0200 Subject: [PATCH 16/63] v7 upgrade guide for wysiwyg editors --- 7.x-dev/upgrade-guide.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index 00ee27a4..ed34d992 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -94,7 +94,12 @@ No changes needed. ### CrudControllers -No changes needed. +Step X. The `wysiwyg` field and column have been removed, because they were hiding functionality. But don't worry, they were just alias columns. Behind the scenes, they were just loading the `ckeditor` field and `text` column respectively. If you're using the `wysiwyg` column of field in your CrudController, replace them with their originals. + +Step X. The `ckeditor` field and column have been moved from the PRO package to an open-source addon. If you are using either of them and want to keep doing so, just run `composer require backpack/ckeditor-field`. Please note that CKEditor is a 3rd party JS library that requires _payment_ when used for commercial purposes (GPL licensed). See their [pricing page](https://ckeditor.com/pricing/) for options. We can give away a few sub-licenses every year - [contact us](https://backpackforlaravel.com/contact) to see if any are still available. If you would rather move away from CKEditor, you can just change your field/column to use `summernote` instead, they are both HTML editors so your content should be compatible. Summernote has more limited editing options, but it's MIT-licensed. + +Step X. Similarly, the `tinymce` field and column have been moved from the PRO package to an open-source addon. If you are using either of them and want to keep doing so, just run `composer require backpack/tinymce-field`. Please note that TinyMCE is a 3rd party JS library that normally requires _payment_ when used for commercial purposes (GLP licensed). See their [pricing page](https://www.tiny.cloud/pricing/) for options. You can sign-up for [free commercial licenses on their website here](https://www.tiny.cloud/get-tiny/). If you would rather move away from TinyMCE, you can just change your field/column to use `summernote` instead, they are both HTML editors so your content should be compatible. Summernote has more limited editing options, but it's MIT-licensed. + ### CSS & JS Assets From 0f24b23b887bf29d873a147735739c9e0ecc8a2a Mon Sep 17 00:00:00 2001 From: pxpm Date: Wed, 5 Feb 2025 16:25:15 +0000 Subject: [PATCH 17/63] wip --- 7.x-dev/crud-operations-lifecycle.md | 72 ++++++++++++++++++++++++++++ 7.x-dev/crud-operations.md | 5 ++ 7.x-dev/index.md | 1 + 3 files changed, 78 insertions(+) create mode 100644 7.x-dev/crud-operations-lifecycle.md diff --git a/7.x-dev/crud-operations-lifecycle.md b/7.x-dev/crud-operations-lifecycle.md new file mode 100644 index 00000000..1e7494c3 --- /dev/null +++ b/7.x-dev/crud-operations-lifecycle.md @@ -0,0 +1,72 @@ +# Operations Lifecycle + +-- + + +## About + +At important points in the CRUD Lifecycle, Backpack triggers what we call "lifecycle events". You can hook into those events - by registering custom code that will run when that lifecycle event happens. This allows you to customize the process, without having to override any of the core files for CRUD or an Operation. + +For example, in a Backpack CRUD all routes are setup on the **CrudController** using methods like `setupModerateOperationRoutes()`. Before those methods are called, Backpack calls `LifecycleEvent::trigger('crud:before_all_route_setup')`. If you want to add your own code that runs there, you can do: + +```php +LifecycleEvent::hookInto('crud:before_setup_routes', function($controller) { + // do something before the routes are setup +}); +``` + +Here are all the general Lifecycle Events we currently have: + +`crud:before_setup_routes` - before any operation routes are registered +`crud:after_setup_routes` - after all operation routes have been registered +`crud:before_setup_defaults` - before all defaults are setup +`crud:after_setup_defaults` - after all defaults have been setup +`crud:before_setup` - before any operation is set up +`crud:after_setup` - after that operation has been set up + + +In addition to the general Lifecycle events above, each operation can trigger its own lifecycle events. For example, here are the lifecycle events triggered by the Create operation: + +`create:before_setup` - exposes parameters: $crud +`create:after_setup` - exposes parameters: $crud + +You can hook into those events using a similar syntax to the general lifecycle events: + +```php +LifecycleEvent::hookInto(['create:before_setup'], function() { + $this->crud->addButton('top', 'create', 'view', 'crud::buttons.create'); +}); +``` + +Note that when using the hooks for specific operations, the hook is prefixed with the operation name followed by the hook name. This allow you to hook into specific operation events, or even to multiple events at the same time: + +```php +LifecycleEvent::hookInto(['create:before_setup', 'list:before_setup'], function() { + // do something before the create operation and the list operation are setup +}); +``` + + + +As a developer you may have had the need to create custom operations, and while creating a "one time use" operation may not require/demand the usage of lifecycle events, creating a reusable operation that you may want to share with the community, or use in multiple projects, may benefit from the usage of lifecycle events to allow other developers to hook into your operation and customize its behavior. + +You can add your own lifecycle events to your custom operations by calling the `LifecycleEvent::trigger()` method at the appropriate points in your operation. For example, if you have a custom operation that need to do something after some action happen in te operation, you can trigger a lifecycle event like this: + +```php +public function moderate() { + // do something to "moderate" the entry and register the hook + LifecycleEvent::trigger('moderate:after_moderation', [ + 'controller' => $this, + 'operation' => 'moderate', + ]); +} +``` + +Then, other developers can hook into that event like this: + +```php +LifecycleEvent::hookInto(['moderate:after_moderation'], function($controller, $operation) { + // do something after the moderate operation has been executed +}); +``` + diff --git a/7.x-dev/crud-operations.md b/7.x-dev/crud-operations.md index 459b393c..985dec1f 100644 --- a/7.x-dev/crud-operations.md +++ b/7.x-dev/crud-operations.md @@ -261,6 +261,11 @@ You'll notice the generated operation has: You can customize these to fit the operation you have in mind, then ```use \App\Http\Controllers\Admin\Operations\CommentOperation;``` inside the CrudControllers where you want the operation. + +### Operations Lifecycle Hooks + +Backpack operations trigger lifecycle events at various points in their execution. You can hook into these events to customize the operation's behavior. You can read a detailed guide about [how to use lifecycle hooks](/docs/{{version}}/crud-operations-lifecycle). + ### Contents of a Custom Operation diff --git a/7.x-dev/index.md b/7.x-dev/index.md index cb6360d6..57966958 100644 --- a/7.x-dev/index.md +++ b/7.x-dev/index.md @@ -44,6 +44,7 @@ + [Delete](/docs/{{version}}/crud-operation-delete) + [Show](/docs/{{version}}/crud-operation-show) + [Columns](/docs/{{version}}/crud-columns) + + [Operations Lifecycle Hooks](/docs/{{version}}/crud-operations-lifecycle) - [Additional Operations](/docs/{{version}}/crud-operations) + [Clone](/docs/{{version}}/crud-operation-clone) + [Reorder](/docs/{{version}}/crud-operation-reorder) From bdc5b42338fcd1268c631b2fdfd8c32fd42a41a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Fri, 7 Feb 2025 10:24:24 +0200 Subject: [PATCH 18/63] explain operatin lifecycle and move lifecycle hooks docs to operation docs --- 7.x-dev/crud-operations-lifecycle.md | 72 ----------------- 7.x-dev/crud-operations.md | 117 +++++++++++++++++++++++++-- 7.x-dev/index.md | 1 - 3 files changed, 112 insertions(+), 78 deletions(-) diff --git a/7.x-dev/crud-operations-lifecycle.md b/7.x-dev/crud-operations-lifecycle.md index 1e7494c3..e69de29b 100644 --- a/7.x-dev/crud-operations-lifecycle.md +++ b/7.x-dev/crud-operations-lifecycle.md @@ -1,72 +0,0 @@ -# Operations Lifecycle - --- - - -## About - -At important points in the CRUD Lifecycle, Backpack triggers what we call "lifecycle events". You can hook into those events - by registering custom code that will run when that lifecycle event happens. This allows you to customize the process, without having to override any of the core files for CRUD or an Operation. - -For example, in a Backpack CRUD all routes are setup on the **CrudController** using methods like `setupModerateOperationRoutes()`. Before those methods are called, Backpack calls `LifecycleEvent::trigger('crud:before_all_route_setup')`. If you want to add your own code that runs there, you can do: - -```php -LifecycleEvent::hookInto('crud:before_setup_routes', function($controller) { - // do something before the routes are setup -}); -``` - -Here are all the general Lifecycle Events we currently have: - -`crud:before_setup_routes` - before any operation routes are registered -`crud:after_setup_routes` - after all operation routes have been registered -`crud:before_setup_defaults` - before all defaults are setup -`crud:after_setup_defaults` - after all defaults have been setup -`crud:before_setup` - before any operation is set up -`crud:after_setup` - after that operation has been set up - - -In addition to the general Lifecycle events above, each operation can trigger its own lifecycle events. For example, here are the lifecycle events triggered by the Create operation: - -`create:before_setup` - exposes parameters: $crud -`create:after_setup` - exposes parameters: $crud - -You can hook into those events using a similar syntax to the general lifecycle events: - -```php -LifecycleEvent::hookInto(['create:before_setup'], function() { - $this->crud->addButton('top', 'create', 'view', 'crud::buttons.create'); -}); -``` - -Note that when using the hooks for specific operations, the hook is prefixed with the operation name followed by the hook name. This allow you to hook into specific operation events, or even to multiple events at the same time: - -```php -LifecycleEvent::hookInto(['create:before_setup', 'list:before_setup'], function() { - // do something before the create operation and the list operation are setup -}); -``` - - - -As a developer you may have had the need to create custom operations, and while creating a "one time use" operation may not require/demand the usage of lifecycle events, creating a reusable operation that you may want to share with the community, or use in multiple projects, may benefit from the usage of lifecycle events to allow other developers to hook into your operation and customize its behavior. - -You can add your own lifecycle events to your custom operations by calling the `LifecycleEvent::trigger()` method at the appropriate points in your operation. For example, if you have a custom operation that need to do something after some action happen in te operation, you can trigger a lifecycle event like this: - -```php -public function moderate() { - // do something to "moderate" the entry and register the hook - LifecycleEvent::trigger('moderate:after_moderation', [ - 'controller' => $this, - 'operation' => 'moderate', - ]); -} -``` - -Then, other developers can hook into that event like this: - -```php -LifecycleEvent::hookInto(['moderate:after_moderation'], function($controller, $operation) { - // do something after the moderate operation has been executed -}); -``` - diff --git a/7.x-dev/crud-operations.md b/7.x-dev/crud-operations.md index 985dec1f..477efd88 100644 --- a/7.x-dev/crud-operations.md +++ b/7.x-dev/crud-operations.md @@ -179,6 +179,118 @@ Inside a ```setupOperationNameRoutes()```, you'll notice that's also where we de Once an operation name has been set using that route, you can do ```$crud->getOperation()``` inside your views and do things according to this. + +## Operation Lifecycle + +When making customizations to existing operations or creating custom operations, it's important to understand how Backpack loads operations in the first place. Let's take it from the top, with a practical example. Backpack CRUDs follow the simple MVC pattern (Model-View-Controller): +- a route points to a CrudController (eg. `Route::crud('article', 'ArticleCrudController')`) +- that `ArticleCrudController` then loads operations as traits eg. `use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;` + +Inside `DeleteOperation` (or any other operation) you will typically have these at least three methods, including `setupXxxRoutes()` and `setupXxxDefaults()` methods: + +```php + +trait DeleteOperation +{ + // Defines which routes are needed for the operation + protected function setupDeleteRoutes($segment, $routeName, $controller) {} + + // Add the default settings, buttons, etc that this operation needs. + protected function setupDeleteDefaults() {} + + // Custom methods, that the routes registered above call + public function destroy($id) {} +} +``` + +When do these get called? Well: +- `setupDeleteRoutes()` gets called _when routes are being set up_; if your CRUD routes are defined in `routes/backpack/custom.php` like our convention, then _that_ is when those methods are called; +- `setupDeleteDefaults()` and all other methods in the CrudController get called when the request is processed; let's get deeper into that; + +When a request to `example.com/admin/article` gets made: +- Laravel will setup all routes; that includes the CRUD routes, so it will call all setupXxxRoutes methods, in all operation traits, used on all CrudControllers); +- Laravel will identify that the route points to a particular CrudController, and a particular method inside that controller (in our example, `DeleteOperation::destroy`, used inside `ArticleCrudController`); so it will instantiate the ArticleCrudController; +- when `ArticleCrudController` gets instantiate, its `parent::__construct()` method will set up the operation for you; and it will do it in the following order: + +1. CrudController will set up the operation defaults (by calling `DeleteOperation::setupDeleteDefaults()`); +2. CrudController will call the `ArticleController::setup()`, to allow you as a developer to set up all operation in one place. It's discouraged to use the `setup()` method for that - in practice it's much cleaner to have a setup method for each operation. +3. CrudController will call the `ArticleController::setupDeleteOperation()` method, if present, to allow the developer to configure that operation; + +This means you can think of the Operation lifecycle of having the following "lifecycle events": +- the operation routes being set up +- the defaults being set up +- the operation being set up (aka configured by developer) + +Understanding these moments and their order, is important in order to place your custom logic _in the right place_ and _at the right time_ in the operation lifecycle. + + +### Lifecycle Hooks + +At important points in the CRUD Lifecycle, Backpack triggers what we call "lifecycle events". You can hook into those events - by registering custom code that will run when that lifecycle event happens. This allows you to customize the process, without having to override any of the core files for CRUD or an Operation. + +For example, in a Backpack CRUD all routes are setup on the **CrudController** using methods like `setupModerateOperationRoutes()`. Before those methods are called, Backpack calls `LifecycleEvent::trigger('crud:before_all_route_setup')`. If you want to add your own code that runs there, you can do: + +```php +LifecycleEvent::hookInto('crud:before_setup_routes', function($controller) { + // do something before the routes are setup +}); +``` + +Here are all the general Lifecycle Events we currently have: + +`crud:before_setup_routes` - before any operation routes are registered +`crud:after_setup_routes` - after all operation routes have been registered +`crud:before_setup_defaults` - before all defaults are setup +`crud:after_setup_defaults` - after all defaults have been setup +`crud:before_setup` - before any operation is set up +`crud:after_setup` - after that operation has been set up + + +In addition to the general Lifecycle events above, each operation can trigger its own lifecycle events. For example, here are the lifecycle events triggered by the Create operation: + +`create:before_setup` - exposes parameters: $crud +`create:after_setup` - exposes parameters: $crud + +You can hook into those events using a similar syntax to the general lifecycle events: + +```php +LifecycleEvent::hookInto(['create:before_setup'], function() { + $this->crud->addButton('top', 'create', 'view', 'crud::buttons.create'); +}); +``` + +Note that when using the hooks for specific operations, the hook is prefixed with the operation name followed by the hook name. This allow you to hook into specific operation events, or even to multiple events at the same time: + +```php +LifecycleEvent::hookInto(['create:before_setup', 'list:before_setup'], function() { + // do something before the create operation and the list operation are setup +}); +``` + + + +As a developer you may have had the need to create custom operations, and while creating a "one time use" operation may not require/demand the usage of lifecycle events, creating a reusable operation that you may want to share with the community, or use in multiple projects, may benefit from the usage of lifecycle events to allow other developers to hook into your operation and customize its behavior. + +You can add your own lifecycle events to your custom operations by calling the `LifecycleEvent::trigger()` method at the appropriate points in your operation. For example, if you have a custom operation that need to do something after some action happen in te operation, you can trigger a lifecycle event like this: + +```php +public function moderate() { + // do something to "moderate" the entry and register the hook + LifecycleEvent::trigger('moderate:after_moderation', [ + 'controller' => $this, + 'operation' => 'moderate', + ]); +} +``` + +Then, other developers can hook into that event like this: + +```php +LifecycleEvent::hookInto(['moderate:after_moderation'], function($controller, $operation) { + // do something after the moderate operation has been executed +}); +``` + ## Creating a Custom Operation @@ -261,11 +373,6 @@ You'll notice the generated operation has: You can customize these to fit the operation you have in mind, then ```use \App\Http\Controllers\Admin\Operations\CommentOperation;``` inside the CrudControllers where you want the operation. - -### Operations Lifecycle Hooks - -Backpack operations trigger lifecycle events at various points in their execution. You can hook into these events to customize the operation's behavior. You can read a detailed guide about [how to use lifecycle hooks](/docs/{{version}}/crud-operations-lifecycle). - ### Contents of a Custom Operation diff --git a/7.x-dev/index.md b/7.x-dev/index.md index 57966958..cb6360d6 100644 --- a/7.x-dev/index.md +++ b/7.x-dev/index.md @@ -44,7 +44,6 @@ + [Delete](/docs/{{version}}/crud-operation-delete) + [Show](/docs/{{version}}/crud-operation-show) + [Columns](/docs/{{version}}/crud-columns) - + [Operations Lifecycle Hooks](/docs/{{version}}/crud-operations-lifecycle) - [Additional Operations](/docs/{{version}}/crud-operations) + [Clone](/docs/{{version}}/crud-operation-clone) + [Reorder](/docs/{{version}}/crud-operation-reorder) From cf9afb183c1035408922d05730d115e02a019719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Fri, 7 Feb 2025 10:24:49 +0200 Subject: [PATCH 19/63] Delete 7.x-dev/crud-operations-lifecycle.md --- 7.x-dev/crud-operations-lifecycle.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 7.x-dev/crud-operations-lifecycle.md diff --git a/7.x-dev/crud-operations-lifecycle.md b/7.x-dev/crud-operations-lifecycle.md deleted file mode 100644 index e69de29b..00000000 From 02b74d4b98684db6456e25d1e1499e1fe7f1fd92 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Fri, 7 Feb 2025 10:38:48 +0200 Subject: [PATCH 20/63] polish docs for lifecycle hooks --- 7.x-dev/crud-operations.md | 31 ++++++++++++++++++------------- 7.x-dev/release-notes.md | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/7.x-dev/crud-operations.md b/7.x-dev/crud-operations.md index 477efd88..baf14bbe 100644 --- a/7.x-dev/crud-operations.md +++ b/7.x-dev/crud-operations.md @@ -226,25 +226,31 @@ Understanding these moments and their order, is important in order to place your ### Lifecycle Hooks -At important points in the CRUD Lifecycle, Backpack triggers what we call "lifecycle events". You can hook into those events - by registering custom code that will run when that lifecycle event happens. This allows you to customize the process, without having to override any of the core files for CRUD or an Operation. +At important points in the CRUD Lifecycle, Backpack triggers what we call "_lifecycle events_". You can hook into those events - by registering custom code that will run when that lifecycle event happens. This allows you to customize the process, without having to override any of the core files for that CRUD or Operation. -For example, in a Backpack CRUD all routes are setup on the **CrudController** using methods like `setupModerateOperationRoutes()`. Before those methods are called, Backpack calls `LifecycleEvent::trigger('crud:before_all_route_setup')`. If you want to add your own code that runs there, you can do: +For example, in a Backpack CRUD all routes are setup on the **CrudController** using methods like `setupModerateOperationRoutes()`. Before those methods are called, Backpack triggers an event called `crud:before_all_route_setup`. If you want to add your own code that runs there, you can do: ```php +use Backpack\CRUD\app\Library\CrudPanel\Hooks\Facades\LifecycleHook; + LifecycleEvent::hookInto('crud:before_setup_routes', function($controller) { // do something before the routes are setup }); ``` - -Here are all the general Lifecycle Events we currently have: + +#### General Lifecycle Events + +Here are all the general lifecycle events Backpack triggers: -`crud:before_setup_routes` - before any operation routes are registered -`crud:after_setup_routes` - after all operation routes have been registered -`crud:before_setup_defaults` - before all defaults are setup -`crud:after_setup_defaults` - after all defaults have been setup -`crud:before_setup` - before any operation is set up -`crud:after_setup` - after that operation has been set up +- `crud:before_setup_routes` - before any operation routes are registered +- `crud:after_setup_routes` - after all operation routes have been registered +- `crud:before_setup_defaults` - before all defaults are setup +- `crud:after_setup_defaults` - after all defaults have been setup +- `crud:before_setup` - before any operation is set up +- `crud:after_setup` - after that operation has been set up + +#### Operation Lifecycle Events In addition to the general Lifecycle events above, each operation can trigger its own lifecycle events. For example, here are the lifecycle events triggered by the Create operation: @@ -268,10 +274,9 @@ LifecycleEvent::hookInto(['create:before_setup', 'list:before_setup'], function( ``` +### How to add your own hooks -As a developer you may have had the need to create custom operations, and while creating a "one time use" operation may not require/demand the usage of lifecycle events, creating a reusable operation that you may want to share with the community, or use in multiple projects, may benefit from the usage of lifecycle events to allow other developers to hook into your operation and customize its behavior. - -You can add your own lifecycle events to your custom operations by calling the `LifecycleEvent::trigger()` method at the appropriate points in your operation. For example, if you have a custom operation that need to do something after some action happen in te operation, you can trigger a lifecycle event like this: +You can add your own lifecycle events to your custom operations by calling the `LifecycleEvent::trigger()` method at the appropriate points in your operation. For example, if you have a custom operation that need to do something after some action happens in the operation, you can trigger a lifecycle event like this: ```php public function moderate() { diff --git a/7.x-dev/release-notes.md b/7.x-dev/release-notes.md index 3df11af9..0779e8f5 100644 --- a/7.x-dev/release-notes.md +++ b/7.x-dev/release-notes.md @@ -22,7 +22,7 @@ Together, our team has put in an incredible amount of work to make v7 what it is ### CRUD Lifecycle Hooks -// TODO +Previously when working with Operations, developers found themselves needing to _override_ an entire operation method, in order to do things before/after the routes/defaults/operation is set up. This created a lot of duplicate code, and made it hard to maintain. Now, you can use CRUD Lifecycle Hooks to add your own code before/after each operation method. This is a much cleaner way to add your own code, without having to override the entire method. [Read more](/docs/{{version}}/crud-operations#lifecycle-hooks). ### Two-Factor Authentication From b82a9dff128488eee1179a65e3364386ca5f23dc Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Fri, 7 Feb 2025 10:50:18 +0200 Subject: [PATCH 21/63] v7 - mention filters inside custom views --- 7.x-dev/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/7.x-dev/release-notes.md b/7.x-dev/release-notes.md index 0779e8f5..f5cc34f0 100644 --- a/7.x-dev/release-notes.md +++ b/7.x-dev/release-notes.md @@ -33,6 +33,10 @@ Previously when working with Operations, developers found themselves needing to // just like your air purifier // TODO +### Filters inside CustomViews + +Filters can now be used inside [Custom Views for your List operation](https://backpackforlaravel.com/docs/{{version}}/crud-operation-list-entries#custom-views-for-listoperation-pro). This means once the admin has selected the Custom View, they can further drill down in the list, using the filters. But not only that... you can _remove_ the general filters and add entirely new filters, just for that Custom View. + ### Browser Tests // TODO From 8f42d1d704e229bb8971a69e39ef4cf45172e9fd Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 7 Feb 2025 16:07:40 +0000 Subject: [PATCH 22/63] docs for agnostic filters --- 7.x-dev/crud-filters.md | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/7.x-dev/crud-filters.md b/7.x-dev/crud-filters.md index 205e3154..70486a89 100644 --- a/7.x-dev/crud-filters.md +++ b/7.x-dev/crud-filters.md @@ -555,6 +555,87 @@ Inside this file, you'll have:
+ +## How to use Filters on any admin panel page + +Filters can be added to any admin panel page, not just the main CRUD table. Imagine that you want to have a dashboard page, with a few widgets that show some data. You can add filters to that page, and use them to filter the data shown in the widgets. +You start by creating a new page, eg: a reports page. +```bash +php artisan backpack:page Reports +``` +**NOTE:** You can read more about creating your custom pages in the [creating a custom page docs.](/docs/{{version}}/base-about#custom-pages-1) + +After the page is created, you should edit the `resources/views/admin/reports.blade.php` file and add the filters navbar and the event listeners: +```diff +@extends(backpack_view('blank')) + +@section('content') +
+

Reports

+

Page for Reports

+
+
+
+
+
+
++ @include('crud::inc.filters_navbar') +
+
+
+
+@endsection + ++@push('after_scripts') ++ ++@endpush +``` + +After that, time to add your own filters in the `ReportsController.php` + +```php +class ReportsController extends Controller +{ + public function index() + { + $crud = app('crud'); + + $crud->addFilter([ + 'type' => 'simple', + 'name' => 'checkbox', + 'label' => 'Simple', + ], false); + + $crud->addFilter([ // dropdown filter + 'name' => 'select_from_array', + 'type' => 'dropdown', + 'label'=> 'Dropdown', + ], ['one' => 'One', 'two' => 'Two', 'three' => 'Three']); + + return view('admin.reports', [ + 'title' => 'Reports', + 'breadcrumbs' => [ + trans('backpack::crud.admin') => backpack_url('http://github.com/dashboard'), + 'Reports' => false, + ], + 'crud' => $crud, + ]); + } +} +``` +
+ ## Examples From 5b1771844242247b0d4ca6efdd61fd094a59fe0d Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 7 Feb 2025 16:15:12 +0000 Subject: [PATCH 23/63] wip --- 7.x-dev/crud-filters.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/7.x-dev/crud-filters.md b/7.x-dev/crud-filters.md index 70486a89..11228123 100644 --- a/7.x-dev/crud-filters.md +++ b/7.x-dev/crud-filters.md @@ -634,6 +634,11 @@ class ReportsController extends Controller } } ``` + +That's it, you should now have the filters navbar on your reports page. You can use the event listeners to update the data shown on the page based on the filters selected by the user. + +<-- INSERT IMAGE --> +
From 3a69a8792fd482852dc4a6aa57898db4fc66527d Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Mon, 17 Feb 2025 11:33:54 +0200 Subject: [PATCH 24/63] polish custom filters docs --- 7.x-dev/crud-filters.md | 166 ++++++++++++++++++++------------------- 7.x-dev/release-notes.md | 6 +- 2 files changed, 91 insertions(+), 81 deletions(-) diff --git a/7.x-dev/crud-filters.md b/7.x-dev/crud-filters.md index 11228123..29a2bcd0 100644 --- a/7.x-dev/crud-filters.md +++ b/7.x-dev/crud-filters.md @@ -555,17 +555,87 @@ Inside this file, you'll have:
+ +## Examples + +Use a dropdown to filter by the values of a MySQL ENUM column: + +```php +CRUD::filter('published') + ->type('select2') + ->values(function() { + return \App\Models\Test::getEnumValuesAsAssociativeArray('published'); + }) + ->whenActive(function($value) { + CRUD::addClause('where', 'published', $value); + }); +``` + +Use a select2 to filter by a 1-n relationship: +```php +CRUD::filter('category_id') + ->type('select2') + ->values(function() { + return \App\Models\Category::all()->pluck('name', 'id')->toArray(); + }) + ->whenActive(function($value) { + CRUD::addClause('where', 'category_id', $value); + }); +``` + +Use a select2_multiple to filter Products by an n-n relationship: +```php +CRUD::filter('tags') + ->type('select2_multiple') + ->values(function() { // the options that show up in the select2 + return Product::all()->pluck('name', 'id')->toArray(); + }) + ->whenActive(function($values) { + foreach (json_decode($values) as $key => $value) { + $this->crud->query = $this->crud->query->whereHas('tags', function ($query) use ($value) { + $query->where('tag_id', $value); + }); + } + }); +``` + +Use a simple filter to add a scope if the filter is active: +```php +// add a "simple" filter called Published +CRUD::filter('published') + ->type('simple') + ->whenActive(function() { // if the filter is active (the GET parameter "published" exits) + CRUD::addClause('published'); + }); +``` + +Use a simple filter to show the softDeleted items (trashed): +```php +CRUD::filter('trashed') + ->type('simple') + ->whenActive(function($values) { + $this->crud->query = $this->crud->query->onlyTrashed(); + }); +``` + + +## Tips and Tricks + -## How to use Filters on any admin panel page +### Use Filters on custom admin panel pages Filters can be added to any admin panel page, not just the main CRUD table. Imagine that you want to have a dashboard page, with a few widgets that show some data. You can add filters to that page, and use them to filter the data shown in the widgets. -You start by creating a new page, eg: a reports page. + + +![](https://backpackforlaravel.com/uploads/docs/filters/filters-in-custom-page.png) + +You start by [creating a new page](/docs/{{version}}/base-about#custom-pages-1) to hold your custom content, eg: a reports page. + ```bash php artisan backpack:page Reports ``` -**NOTE:** You can read more about creating your custom pages in the [creating a custom page docs.](/docs/{{version}}/base-about#custom-pages-1) -After the page is created, you should edit the `resources/views/admin/reports.blade.php` file and add the filters navbar and the event listeners: +To use filters on a custom admin panel page, you should edit the blade file (in this example the `resources/views/admin/reports.blade.php` file) to **add the filters navbar** and **the event listeners**: ```diff @extends(backpack_view('blank')) @@ -589,20 +659,24 @@ After the page is created, you should edit the `resources/views/admin/reports.bl +@push('after_scripts') + +@endpush ``` -After that, time to add your own filters in the `ReportsController.php` +After that, time to add your own filters in your controller (in this example, `ReportsController.php`): ```php class ReportsController extends Controller @@ -635,77 +709,11 @@ class ReportsController extends Controller } ``` -That's it, you should now have the filters navbar on your reports page. You can use the event listeners to update the data shown on the page based on the filters selected by the user. - -<-- INSERT IMAGE --> - -
- - -## Examples - -Use a dropdown to filter by the values of a MySQL ENUM column: - -```php -CRUD::filter('published') - ->type('select2') - ->values(function() { - return \App\Models\Test::getEnumValuesAsAssociativeArray('published'); - }) - ->whenActive(function($value) { - CRUD::addClause('where', 'published', $value); - }); -``` - -Use a select2 to filter by a 1-n relationship: -```php -CRUD::filter('category_id') - ->type('select2') - ->values(function() { - return \App\Models\Category::all()->pluck('name', 'id')->toArray(); - }) - ->whenActive(function($value) { - CRUD::addClause('where', 'category_id', $value); - }); -``` - -Use a select2_multiple to filter Products by an n-n relationship: -```php -CRUD::filter('tags') - ->type('select2_multiple') - ->values(function() { // the options that show up in the select2 - return Product::all()->pluck('name', 'id')->toArray(); - }) - ->whenActive(function($values) { - foreach (json_decode($values) as $key => $value) { - $this->crud->query = $this->crud->query->whereHas('tags', function ($query) use ($value) { - $query->where('tag_id', $value); - }); - } - }); -``` - -Use a simple filter to add a scope if the filter is active: -```php -// add a "simple" filter called Published -CRUD::filter('published') - ->type('simple') - ->whenActive(function() { // if the filter is active (the GET parameter "published" exits) - CRUD::addClause('published'); - }); -``` - -Use a simple filter to show the softDeleted items (trashed): -```php -CRUD::filter('trashed') - ->type('simple') - ->whenActive(function($values) { - $this->crud->query = $this->crud->query->onlyTrashed(); - }); -``` - - -## Tips and Tricks +That's it, you should now have the filters navbar on your reports page. You can use the event listeners to update the data shown on the page based on the filters selected by the user. +Here are the Javascript events you can listen to: +- `backpack:filter:changed` when a filter is changed; +- `backpack:filter:cleared` when a filter is cleared; +- `backpack:filters:cleared` when all filters are cleared; ### Add a debounce time to filters @@ -725,7 +733,7 @@ CRUD::filter('name') All filter types accept a `debounce`, like for example the simple filter, range filter etc. -### Adding a filter using array syntax +### Add a filter using array syntax In Backpack v4-v5 we used an "array syntax" to add and manipulate filters. That syntax is still supported for backwards-compatiblity. But it most cases it's easier to use the fluent syntax. diff --git a/7.x-dev/release-notes.md b/7.x-dev/release-notes.md index f5cc34f0..664e7749 100644 --- a/7.x-dev/release-notes.md +++ b/7.x-dev/release-notes.md @@ -30,8 +30,10 @@ Previously when working with Operations, developers found themselves needing to ### Re-Usable Filters -// just like your air purifier -// TODO + +![](https://backpackforlaravel.com/uploads/docs/filters/filters-in-custom-page.png) + +Starting with this Backpack version, you can use the [filters](/docs/{{version}}/crud-filters) in custom pages too. Instead of being tied to DataTables, filters now trigger generic Javascript events like `backpack:filter:changed`. You can catch those events using custom code in Javascript or Livewire... and do stuff. This it possible to use filters on completely custom pages - like custom dashboards, custom reports or custom operations. [Read more](/docs/{{version}}/crud-filters#use-filters-on-custom-admin-panel-pages). ### Filters inside CustomViews From 8ad70b57f4c3cf1c88cc452ce490d8cbfae559d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Tue, 4 Mar 2025 12:33:26 +0200 Subject: [PATCH 25/63] add note about discounts --- 6.x/faq.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/6.x/faq.md b/6.x/faq.md index 8f30e58c..5b732448 100644 --- a/6.x/faq.md +++ b/6.x/faq.md @@ -41,6 +41,23 @@ Backpack PRO is a closed-source add-on, which requires payment in order to recei No - we're no longer giving away free licenses. But we _have_ released Backpack CRUD v5 and v6 under the MIT License, which means it's free and open-source. It has fewer features, but you can do absolutely do anything you want with it. + +### Can I get a discount for university use? + +Yes, if you are a teacher at highschool or university and want to use Backpack to teach your students how to code, we're happy to give you a discount for our MULTI-PROJECT and EVERYTHING plans, so your students can quickly learn PHP, Laravel and Backpack. Reach out to us from your .edu email (or provide other proof). For this use case, please make sure to "refresh" your token every year, to prevent misuse. + + +### Can I get a discount for a backlink? + +Yes, but only for your second/third purchases. Before your license expires, you will receive an email offering you 20% discount if you include a backlink from your website to ours. Reply to that email with a link, and our team will help you get the discount. + +To get the 20% discount for backlink, please include a backlink from your MAIN WEBSITE (not from your admin panel), to our main website: `https://backpackforlaravel.com?utm_source=customer_ref`. What works best is to add a link to your footer: +- Admin Panel by Backpack +- Backoffice by Backpack +- CMS Powered by Backpack +- ERP Powered by Backpack +- Powered By Backpack + ## Installation @@ -233,4 +250,4 @@ APP_DEBUG=false ``` php artisan config:clear php artisan config:cache -``` \ No newline at end of file +``` From 28e39ac577557be265420bea90c5a213a8d09bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Tue, 4 Mar 2025 12:47:46 +0200 Subject: [PATCH 26/63] better terms for backlink discount --- 6.x/faq.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/6.x/faq.md b/6.x/faq.md index 5b732448..6491a5bf 100644 --- a/6.x/faq.md +++ b/6.x/faq.md @@ -51,12 +51,10 @@ Yes, if you are a teacher at highschool or university and want to use Backpack t Yes, but only for your second/third purchases. Before your license expires, you will receive an email offering you 20% discount if you include a backlink from your website to ours. Reply to that email with a link, and our team will help you get the discount. -To get the 20% discount for backlink, please include a backlink from your MAIN WEBSITE (not from your admin panel), to our main website: `https://backpackforlaravel.com?utm_source=customer_ref`. What works best is to add a link to your footer: -- Admin Panel by Backpack -- Backoffice by Backpack -- CMS Powered by Backpack -- ERP Powered by Backpack -- Powered By Backpack +To get the 20% discount: +- include a backlink from your MAIN WEBSITE (not from your admin panel), to our main website: `https://backpackforlaravel.com?utm_source=customer_ref`; most people add a link to their footer; here are a few ideas: `Admin Panel by Backpack`, `Backoffice by Backpack`, `CMS Powered by Backpack`, `ERP Powered by Backpack`, `Powered By Backpack`; +- make sure the link is `dofollow` (regular link); +- make sure to keep the link there for 12 months; ## Installation From 0ac303397d7007a04e8bf16da0799db7d07bb368 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Thu, 6 Mar 2025 14:27:23 +0100 Subject: [PATCH 27/63] Add basset:clear to upgrade guide --- 7.x-dev/upgrade-guide.md | 1 + 1 file changed, 1 insertion(+) diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index ed34d992..23c411a6 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -121,6 +121,7 @@ No changes needed. Step xx. Clear your app's cache: ``` +php artisan basset:clear php artisan config:clear php artisan cache:clear php artisan view:clear From bf268580b09a5883d51286c527f5a225b56700e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Thu, 17 Apr 2025 13:33:52 +0300 Subject: [PATCH 28/63] Update upgrade-guide.md --- 6.x/upgrade-guide.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/6.x/upgrade-guide.md b/6.x/upgrade-guide.md index d0884234..ddad73d1 100644 --- a/6.x/upgrade-guide.md +++ b/6.x/upgrade-guide.md @@ -55,7 +55,8 @@ Please make sure your project respects the requirements below, before you start "backpack/editable-columns": "^3.0", "backpack/revise-operation": "^2.0", "backpack/medialibrary-uploaders": "^1.0", - "backpack/devtools": "^2.0", + "backpack/devtools": "^3.0", + "backpack/generators": "^4.0", ``` Step 3.1. We removed `PackageVersions` and the cache busting string is now handled by `Basset`. @@ -81,7 +82,7 @@ When asked to install a theme, please choose the CoreUIv2 theme. It'll be easier **No changes needed.** But there are a few improvements you _could_ make, if you want, that will help clean up your Models and move a bit of logic that might be admin-panel-only to the admin panel files: -Step 4. (OPTIONAL) If you use acessors and mutators for upload fields, you can now use Uploaders instead. TODO: link to migration steps +Step 4. (OPTIONAL) If you use acessors and mutators for upload fields, you can now [use Uploaders instead](/docs/{{version}}/crud-uploaders). Step 5. (OPTIONAL) If you use accessors and mutators any other fields, you can [use Eloquent model events on fields](/docs/{{version}}/crud-operation-create#use-events-in-your-field-definition). From f1f1b8cf179cb82c86a45c01b668d9b3470e609f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Tue, 22 Apr 2025 11:31:04 +0300 Subject: [PATCH 29/63] v6 upgrade guide - details for no hint path defined for namespace backpack error --- 6.x/upgrade-guide.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/6.x/upgrade-guide.md b/6.x/upgrade-guide.md index ddad73d1..84866270 100644 --- a/6.x/upgrade-guide.md +++ b/6.x/upgrade-guide.md @@ -179,6 +179,10 @@ It's as easy as using an asset from a CDN, but it's much _much_ better than that Step 18. **Have you developed any custom fields, columns, operations etc?** Rephrased: do you have anything inside your `resources/views/vendor/backpack/crud` directory? If so, we recommended you load your CSS & JS assets using `@basset('path/to/file.css')` instead of `@loadonce('path/to/file.css')` or ``. This will not only make sure that piece of JS/CSS/code is only loaded once per pageload, but it will also help serve all assets from one central location (your `storage/app/public` directory) which can be easily cleared using `php artisan basset:clear` to force cache-busting. You can find [more info about it here](https://github.com/laravel-backpack/basset). + +Step 18.B. If you have custom pages or custom operations, take particular note of the fact that the `backpack::` view namespace no longer exists. Most likely, when you try to use views from that namespace you will get an error saying "_No hint path defined for namespace [backpack]_". To fix this, the best solution is to change from using the namespace directly (eg. `@extends('backpack::blank')`) to using the backpack_view helper (eg. `@extends(backpack_view('blank'))`). That helper will make sure to load that blade file, from whatever theme is active right now (with fallback to the `vendor/backpack/ui` directory). Alternatively, if you only want to support ONE theme, you can replace that `backpack::` namespace with the namespace of the theme (eg. `backpack.theme-tabler::`). + + ---- Step 19. If you've published and overriden any CRUD blade files, please take a look at the changes, and re-do them in your files too. We've done quite a few changes, to account for different themes in v6. For custom components, a good way to make them pretty would be to copy-paste HTML from [Tabler](https://tabler.io/preview), [CoreUIv4](https://coreui.io/demos/bootstrap/4.2/free/), [Backstrap](https://backstrap.net/) (depending on what theme you've chosen to use) or straight out [Bootstrap](https://getbootstrap.com/docs/5.3/examples/). // TODO: link to diff From bf9375ab584a4652a05aaa7cd734f38a629ab4c9 Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 30 May 2025 15:53:29 +0100 Subject: [PATCH 30/63] wip --- 7.x-dev/base-widgets.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/7.x-dev/base-widgets.md b/7.x-dev/base-widgets.md index d984ee64..bd801601 100644 --- a/7.x-dev/base-widgets.md +++ b/7.x-dev/base-widgets.md @@ -349,6 +349,27 @@ class ChartjsPieController extends ChartController
+ +### Datatable + +Allow you to show a datatable for your CrudControllers. + +```php +[ + 'type' => 'datatable', + 'controller' => 'App\Http\Controllers\Admin\PetShop\InvoiceCrudController', + 'name' => 'invoice_crud', + 'configure' => function($crud, $parent) { + // you can use this closure to modify your CrudController definition. + if ($parent) { + $crud->addClause('where', 'owner_id', $parent->id); + } + } +] +``` + + +
### Div From c572e8f184e041348f67be9ddff5d62dbee8525b Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 30 May 2025 16:11:00 +0100 Subject: [PATCH 31/63] docs for component --- 7.x-dev/base-components.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index 8f61b769..ea6ed11f 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -46,6 +46,19 @@ Note that you can further customize this using custom attributes. If you define
+ +### Datatable + +Show a datatable for the defined controller. + +```php + +``` + +Note that you can further customize this using custom attributes. If you define a `target` on it, that will be passed down to the `a` element. + +
+ ### Menu Separator From 0bbd8967a913774d8edbcc77e430e368230ad343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Mon, 2 Jun 2025 11:22:27 +0300 Subject: [PATCH 32/63] detail the datatable components a bit --- 7.x-dev/base-components.md | 11 ++++++++--- 7.x-dev/base-widgets.md | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index ea6ed11f..07fb27de 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -47,12 +47,17 @@ Note that you can further customize this using custom attributes. If you define
-### Datatable +### DataTable -Show a datatable for the defined controller. +Show a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CRUD for that entity needs to be already set up, and passed to this component as a parameter. The datatable will pick up everything that in your `setupListOperation()`. You can then further add/remove/configure functionality using the configuration closure: ```php - + ``` Note that you can further customize this using custom attributes. If you define a `target` on it, that will be passed down to the `a` element. diff --git a/7.x-dev/base-widgets.md b/7.x-dev/base-widgets.md index bd801601..70d8952f 100644 --- a/7.x-dev/base-widgets.md +++ b/7.x-dev/base-widgets.md @@ -350,9 +350,9 @@ class ChartjsPieController extends ChartController
-### Datatable +### DataTable -Allow you to show a datatable for your CrudControllers. +Shows a datatable component from a particular CrudController. For more info about the configuration parameter, please see the [datatable component docs](/docs/{{version}}/base-components#datatable). ```php [ From d0e1d1a2f72c166a602ce78dd34dd2b760fad9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Mon, 2 Jun 2025 12:00:21 +0300 Subject: [PATCH 33/63] polish datatable component docs --- 7.x-dev/base-components.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index 07fb27de..c7d21079 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -49,7 +49,7 @@ Note that you can further customize this using custom attributes. If you define ### DataTable -Show a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CRUD for that entity needs to be already set up, and passed to this component as a parameter. The datatable will pick up everything that in your `setupListOperation()`. You can then further add/remove/configure functionality using the configuration closure: +Show a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CRUD for that entity needs to be already set up, and passed to this component as a parameter: ```php ``` -Note that you can further customize this using custom attributes. If you define a `target` on it, that will be passed down to the `a` element. +The datatable will pick up everything that in your `setupListOperation()`. You can then further add/remove/configure functionality using the configuration closure: + +```php + + +```
From 52bee18549689b3fa75e218204c2f164963e95b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Thu, 5 Jun 2025 13:17:28 +0300 Subject: [PATCH 34/63] use bp-datatable syntax --- 7.x-dev/base-components.md | 20 +++++++------------- 7.x-dev/base-widgets.md | 4 ++-- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index c7d21079..bfcb805c 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -51,24 +51,18 @@ Note that you can further customize this using custom attributes. If you define Show a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CRUD for that entity needs to be already set up, and passed to this component as a parameter: -```php - +```html + ``` The datatable will pick up everything that in your `setupListOperation()`. You can then further add/remove/configure functionality using the configuration closure: -```php - - + :setup="function($crud, $parent) { if ($parent) { $crud->addClause('where', 'customer_id', $parent->id); } }" + name="invoices" /> ``` diff --git a/7.x-dev/base-widgets.md b/7.x-dev/base-widgets.md index 70d8952f..a1d1a5bb 100644 --- a/7.x-dev/base-widgets.md +++ b/7.x-dev/base-widgets.md @@ -358,8 +358,8 @@ Shows a datatable component from a particular CrudController. For more info abou [ 'type' => 'datatable', 'controller' => 'App\Http\Controllers\Admin\PetShop\InvoiceCrudController', - 'name' => 'invoice_crud', - 'configure' => function($crud, $parent) { + 'name' => 'invoices', + 'setup' => function($crud, $parent) { // you can use this closure to modify your CrudController definition. if ($parent) { $crud->addClause('where', 'owner_id', $parent->id); From 7b217a394a47ea9a3f2851aa2e11c7d77620766f Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 6 Jun 2025 15:00:47 +0100 Subject: [PATCH 35/63] wip --- 7.x-dev/base-components.md | 4 ++-- 7.x-dev/upgrade-guide.md | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index bfcb805c..6f198f77 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -52,13 +52,13 @@ Note that you can further customize this using custom attributes. If you define Show a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CRUD for that entity needs to be already set up, and passed to this component as a parameter: ```html - + ``` The datatable will pick up everything that in your `setupListOperation()`. You can then further add/remove/configure functionality using the configuration closure: ```html - :setup="function($crud, $parent) { if ($parent) { $crud->addClause('where', 'customer_id', $parent->id); } }" diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index ed34d992..b48b3ed4 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -109,7 +109,10 @@ No changes needed. ### Views -No changes needed. +**List Operation View** - The List Operation view got a huge change. We decoupled the datatable from the view, so that you can use the table anywhere you would like. +Most of the code is still identical but moved to `datatable.blade.php`. The `list.blade.php` view now only includes the mentioned datatable component. + +If you had customized the `list.blade.php` you should move your customizations to `datatable.blade.php`. ### Security From dad13bb8265ef09912ee67469f3766175ec93311 Mon Sep 17 00:00:00 2001 From: Mohammad Emran Date: Sat, 7 Jun 2025 09:06:00 +0600 Subject: [PATCH 36/63] Mention Laravel 12 support --- 6.x/introduction.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/6.x/introduction.md b/6.x/introduction.md index 7bab24a6..bd12f489 100644 --- a/6.x/introduction.md +++ b/6.x/introduction.md @@ -56,7 +56,7 @@ We heavily recommend you spend a little time to understand Backpack, and only af ### Requirements - - Laravel 10.x or 11.x + - Laravel 10.x or 11.x or 12.x - MySQL / PostgreSQL / SQLite / SQL Server @@ -78,9 +78,9 @@ Backpack v6 is the current version and is actively maintained by the Backpack te ### License Backpack is open-core: -- **Backpack CRUD is free & open-source, licensed under the [MIT License](https://github.com/Laravel-Backpack/CRUD/blob/main/LICENSE.md)**; it is perfect if you're building a simple admin panel - it's packed with features! it's also perfect if you're building an open-source project, the permissive license allows you to do whatever you want; -- **Backpack PRO is a paid, closed-source add-on, licensed under our [EULA](https://backpackforlaravel.com/eula)**; [PRO](https://backpackforlaravel.com/products/pro-for-unlimited-projects) adds additional functionality to CRUD, that will be useful when your admin panel grows (see our [FREE vs PRO comparison](https://backpackforlaravel.com/docs/6.x/features-free-vs-paid)); -- Of the other add-ons we've created, some are FREE and some are PAID; please see [our add-ons list](https://backpackforlaravel.test/docs/6.x/add-ons-official) for more info; +- **Backpack CRUD is free & open-source, licensed under the [MIT License](https://github.com/Laravel-Backpack/CRUD/blob/main/LICENSE.md)**; it is perfect if you're building a simple admin panel - it's packed with features! it's also perfect if you're building an open-source project, the permissive license allows you to do whatever you want. +- **Backpack PRO is a paid, closed-source add-on, licensed under our [EULA](https://backpackforlaravel.com/eula)**; [PRO](https://backpackforlaravel.com/products/pro-for-unlimited-projects) adds additional functionality to CRUD, which will be useful when your admin panel grows (see our [FREE vs PRO comparison](https://backpackforlaravel.com/docs/6.x/features-free-vs-paid)). +- Of the other add-ons we've created, some are FREE and some are PAID; please see [our add-ons list](https://backpackforlaravel.test/docs/6.x/add-ons-official) for more info. [Our documentation](https://backpackforlaravel.com/docs) covers both CRUD and PRO, with all the PRO features clearly labeled PRO. From e8fb02744c70ed8f64efe76b8c4ad75a667df3f3 Mon Sep 17 00:00:00 2001 From: Mohammad Emran Date: Tue, 10 Jun 2025 18:27:33 +0600 Subject: [PATCH 37/63] Mention Laravel 12 support and minor fixes --- 7.x-dev/introduction.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/7.x-dev/introduction.md b/7.x-dev/introduction.md index 02ca3170..3ea33a23 100644 --- a/7.x-dev/introduction.md +++ b/7.x-dev/introduction.md @@ -6,8 +6,8 @@ Backpack is a collection of Laravel packages that help you **build custom admini In a nutshell: -- UI - Backpack will provide you with a _visual interface_ for the admin panel (the HTML, the CSS, the JS), authentication functionality & global bubble notifications; you can choose from one of the 3 themes we have developed (powered by Tabler, CoreUI v4 or CoreUI v2), a third-party theme or create your own theme; the enormous advantage of using a Bootstrap-based HTML theme is that when you need custom pages, you already have the HTML blocks for the UI, you don't have to design them yourself; -- CRUDs - Backpack will also help you build _sections where your admins can manipulate entries for Eloquent models_; we call them _CRUD Panels_ after the most basic operations: Create, Read, Update & Delete; after [understanding Backpack](/docs/{{version}}/getting-started-basics), you'll be able to create a CRUD panel in a few minutes per model: +- **UI** - Backpack will provide you with a _visual interface_ for the admin panel (the HTML, the CSS, the JS), authentication functionality & global bubble notifications; you can choose from one of the 3 themes we have developed (powered by Tabler, CoreUI v4 or CoreUI v2), a third-party theme or create your own theme; the enormous advantage of using a Bootstrap-based HTML theme is that when you need custom pages, you already have the HTML blocks for the UI, you don't have to design them yourself. +- **CRUDs** - Backpack will also help you build _sections where your admins can manipulate entries for Eloquent models_; we call them _CRUD Panels_ after the most basic operations: Create, Read, Update & Delete; after [understanding Backpack](/docs/{{version}}/getting-started-basics), you'll be able to create a CRUD panel in a few minutes per model: ![](https://user-images.githubusercontent.com/1032474/86720524-c5a1d480-c02d-11ea-87ed-d03b0197eb25.gif) @@ -31,8 +31,8 @@ php artisan backpack:build ``` If you have NOT created your Eloquent models yet, you can use whatever you want for that. We recommend: -- FREE - [`laravel-shift/blueprint`](https://github.com/laravel-shift/blueprint) as the best **YAML-based tool** for this; -- PAID - [`backpack/devtools`](https://backpackforlaravel.com/products/devtools) as the best **web interface** for this; it makes it dead simple to create Eloquent models, from the comfort of your web browser; +- FREE - [`laravel-shift/blueprint`](https://github.com/laravel-shift/blueprint) as the best **YAML-based tool** for this. +- PAID - [`backpack/devtools`](https://backpackforlaravel.com/products/devtools) as the best **web interface** for this. It makes it dead simple to create Eloquent models, from the comfort of your web browser. --- @@ -56,7 +56,7 @@ We heavily recommend you spend a little time to understand Backpack, and only af ### Requirements - - Laravel 10.x or 11.x + - Laravel 10.x or 11.x or 12.x - MySQL / PostgreSQL / SQLite / SQL Server @@ -78,9 +78,9 @@ Backpack v6 is the current version and is actively maintained by the Backpack te ### License Backpack is open-core: -- **Backpack CRUD is free & open-source, licensed under the [MIT License](https://github.com/Laravel-Backpack/CRUD/blob/main/LICENSE.md)**; it is perfect if you're building a simple admin panel - it's packed with features! it's also perfect if you're building an open-source project, the permissive license allows you to do whatever you want; -- **Backpack PRO is a paid, closed-source add-on, licensed under our [EULA](https://backpackforlaravel.com/eula)**; [PRO](https://backpackforlaravel.com/products/pro-for-unlimited-projects) adds additional functionality to CRUD, that will be useful when your admin panel grows (see our [FREE vs PRO comparison](https://backpackforlaravel.com/docs/6.x/features-free-vs-paid)); -- Of the other add-ons we've created, some are FREE and some are PAID; please see [our add-ons list](https://backpackforlaravel.test/docs/6.x/add-ons-official) for more info; +- **Backpack CRUD is free & open-source, licensed under the [MIT License](https://github.com/Laravel-Backpack/CRUD/blob/main/LICENSE.md)**. It is perfect if you're building a simple admin panel - it's packed with features! It's also perfect if you're building an open-source project, the permissive license allows you to do whatever you want. +- **Backpack PRO is a paid, closed-source add-on, licensed under our [EULA](https://backpackforlaravel.com/eula)**. [PRO](https://backpackforlaravel.com/products/pro-for-unlimited-projects) adds additional functionality to CRUD, which will be useful when your admin panel grows (see our [FREE vs PRO comparison](https://backpackforlaravel.com/docs/7.x/features-free-vs-paid)). +- Of the other add-ons we've created, some are FREE and some are PAID. Please see [our add-ons list](https://backpackforlaravel.test/docs/7.x/add-ons-official) for more info. [Our documentation](https://backpackforlaravel.com/docs) covers both CRUD and PRO, with all the PRO features clearly labeled PRO. @@ -89,9 +89,9 @@ Backpack is open-core: ### Versioning, Updates and Upgrades Starting with the previous version, all our packages follow [semantic versioning](https://semver.org/). Here's what `major.minor.patch` (e.g. `7.0.1`) means for us: -- `major` - breaking changes, major new features, complete rewrites; released **once a year**, in February; it adds features that were previously impossible and upgrades our dependencies; upgrading is done by following our clear and detailed upgrade guides; -- `minor` - new features, released in backwards-compatible ways; **every few months**; update takes seconds; -- `patch` - bug fixes & small non-breaking changes; historically **every week**; update takes seconds; +- `major` - breaking changes, major new features, complete rewrites; released **once a year**, in February. It adds features that were previously impossible and upgrades our dependencies; upgrading is done by following our clear and detailed upgrade guides. +- `minor` - new features, released in backwards-compatible ways; **every few months**; update takes seconds. +- `patch` - bug fixes & small non-breaking changes; historically **every week**; update takes seconds. When we release a new Backpack\CRUD version, all paid add-ons receive support for it the same day. @@ -100,15 +100,15 @@ When you buy a premium Backpack add-on, you get access to not only _updates_, bu ### Add-ons -Backpack's core is open-source and free (Backpack\CRUD). FREE +Backpack's core is open-source and free (Backpack\CRUD). **FREE** The reason we've been able to build and maintain Backpack since 2016 is that Laravel professionals have supported us, by buying our paid products. As of 2022, these are all Backpack add-ons, which we highly recommend: -- [Backpack PRO](/products/pro-for-unlimited-projects) - a crazy amount of added features; PAID -- [Backpack DevTools](/products/devtools) - a developer UI for generating migrations, models and CRUDs; PAID -- [Backpack FigmaTemplate](/products/figma-template) - quickly create designs and mockups, using Backpack's design; PAID -- [Backpack EditableColumns](/products/editable-columns) - let your admins do quick edits, right in the table view; PAID +- [Backpack PRO](/products/pro-for-unlimited-projects) - a crazy amount of added features. **PAID** +- [Backpack DevTools](/products/devtools) - a developer UI for generating migrations, models and CRUDs. **PAID** +- [Backpack FigmaTemplate](/products/figma-template) - quickly create designs and mockups, using Backpack's design. **PAID** +- [Backpack EditableColumns](/products/editable-columns) - let your admins do quick edits, right in the table view. **PAID** -In addition to our open-source core and our closed-source add-ons, there are a few other add-ons you might want to take a look at, that treat common use cases. Some have been developed by our core team, some by our wonderful community. You can just install interfaces to manage [site-wide settings](https://github.com/Laravel-Backpack/Settings), [the default Laravel users table](https://github.com/eduardoarandah/UserManager), [users, groups & permissions](https://github.com/Laravel-Backpack/PermissionManager), [content for custom pages, using page templates](https://github.com/Laravel-Backpack/PageManager), [news articles, categories and tags](https://github.com/Laravel-Backpack/NewsCRUD), etc. FREE +In addition to our open-source core and our closed-source add-ons, there are a few other add-ons you might want to take a look at, that treat common use cases. Some have been developed by our core team, some by our wonderful community. You can just install interfaces to manage [site-wide settings](https://github.com/Laravel-Backpack/Settings), [the default Laravel users table](https://github.com/eduardoarandah/UserManager), [users, groups & permissions](https://github.com/Laravel-Backpack/PermissionManager), [content for custom pages, using page templates](https://github.com/Laravel-Backpack/PageManager), [news articles, categories and tags](https://github.com/Laravel-Backpack/NewsCRUD), etc. **FREE** For more information, please see [our add-ons page](/addons). From 61c9f0f962399323ced408d8b6eb1b7f330f6197 Mon Sep 17 00:00:00 2001 From: Mohammad Emran Date: Tue, 10 Jun 2025 18:31:30 +0600 Subject: [PATCH 38/63] Minor text formatting --- 6.x/introduction.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/6.x/introduction.md b/6.x/introduction.md index bd12f489..b7d36647 100644 --- a/6.x/introduction.md +++ b/6.x/introduction.md @@ -6,8 +6,8 @@ Backpack is a collection of Laravel packages that help you **build custom admini In a nutshell: -- UI - Backpack will provide you with a _visual interface_ for the admin panel (the HTML, the CSS, the JS), authentication functionality & global bubble notifications; you can choose from one of the 3 themes we have developed (powered by Tabler, CoreUI v4 or CoreUI v2), a third-party theme or create your own theme; the enormous advantage of using a Bootstrap-based HTML theme is that when you need custom pages, you already have the HTML blocks for the UI, you don't have to design them yourself; -- CRUDs - Backpack will also help you build _sections where your admins can manipulate entries for Eloquent models_; we call them _CRUD Panels_ after the most basic operations: Create, Read, Update & Delete; after [understanding Backpack](/docs/{{version}}/getting-started-basics), you'll be able to create a CRUD panel in a few minutes per model: +- **UI** - Backpack will provide you with a _visual interface_ for the admin panel (the HTML, the CSS, the JS), authentication functionality & global bubble notifications; you can choose from one of the 3 themes we have developed (powered by Tabler, CoreUI v4 or CoreUI v2), a third-party theme or create your own theme; the enormous advantage of using a Bootstrap-based HTML theme is that when you need custom pages, you already have the HTML blocks for the UI, you don't have to design them yourself. +- **CRUDs** - Backpack will also help you build _sections where your admins can manipulate entries for Eloquent models_; we call them _CRUD Panels_ after the most basic operations: Create, Read, Update & Delete; after [understanding Backpack](/docs/{{version}}/getting-started-basics), you'll be able to create a CRUD panel in a few minutes per model: ![](https://user-images.githubusercontent.com/1032474/86720524-c5a1d480-c02d-11ea-87ed-d03b0197eb25.gif) @@ -31,8 +31,8 @@ php artisan backpack:build ``` If you have NOT created your Eloquent models yet, you can use whatever you want for that. We recommend: -- FREE - [`laravel-shift/blueprint`](https://github.com/laravel-shift/blueprint) as the best **YAML-based tool** for this; -- PAID - [`backpack/devtools`](https://backpackforlaravel.com/products/devtools) as the best **web interface** for this; it makes it dead simple to create Eloquent models, from the comfort of your web browser; +- FREE - [`laravel-shift/blueprint`](https://github.com/laravel-shift/blueprint) as the best **YAML-based tool** for this. +- PAID - [`backpack/devtools`](https://backpackforlaravel.com/products/devtools) as the best **web interface** for this. It makes it dead simple to create Eloquent models, from the comfort of your web browser. --- @@ -78,9 +78,9 @@ Backpack v6 is the current version and is actively maintained by the Backpack te ### License Backpack is open-core: -- **Backpack CRUD is free & open-source, licensed under the [MIT License](https://github.com/Laravel-Backpack/CRUD/blob/main/LICENSE.md)**; it is perfect if you're building a simple admin panel - it's packed with features! it's also perfect if you're building an open-source project, the permissive license allows you to do whatever you want. -- **Backpack PRO is a paid, closed-source add-on, licensed under our [EULA](https://backpackforlaravel.com/eula)**; [PRO](https://backpackforlaravel.com/products/pro-for-unlimited-projects) adds additional functionality to CRUD, which will be useful when your admin panel grows (see our [FREE vs PRO comparison](https://backpackforlaravel.com/docs/6.x/features-free-vs-paid)). -- Of the other add-ons we've created, some are FREE and some are PAID; please see [our add-ons list](https://backpackforlaravel.test/docs/6.x/add-ons-official) for more info. +- **Backpack CRUD is free & open-source, licensed under the [MIT License](https://github.com/Laravel-Backpack/CRUD/blob/main/LICENSE.md)**. It is perfect if you're building a simple admin panel - it's packed with features! It's also perfect if you're building an open-source project, the permissive license allows you to do whatever you want. +- **Backpack PRO is a paid, closed-source add-on, licensed under our [EULA](https://backpackforlaravel.com/eula)**. [PRO](https://backpackforlaravel.com/products/pro-for-unlimited-projects) adds additional functionality to CRUD, which will be useful when your admin panel grows (see our [FREE vs PRO comparison](https://backpackforlaravel.com/docs/6.x/features-free-vs-paid)). +- Of the other add-ons we've created, some are FREE and some are PAID. Please see [our add-ons list](https://backpackforlaravel.test/docs/6.x/add-ons-official) for more info. [Our documentation](https://backpackforlaravel.com/docs) covers both CRUD and PRO, with all the PRO features clearly labeled PRO. @@ -89,9 +89,9 @@ Backpack is open-core: ### Versioning, Updates and Upgrades Starting with the previous version, all our packages follow [semantic versioning](https://semver.org/). Here's what `major.minor.patch` (e.g. `6.0.1`) means for us: -- `major` - breaking changes, major new features, complete rewrites; released **once a year**, in February; it adds features that were previously impossible and upgrades our dependencies; upgrading is done by following our clear and detailed upgrade guides; -- `minor` - new features, released in backwards-compatible ways; **every few months**; update takes seconds; -- `patch` - bug fixes & small non-breaking changes; historically **every week**; update takes seconds; +- `major` - breaking changes, major new features, complete rewrites; released **once a year**, in February. It adds features that were previously impossible and upgrades our dependencies; upgrading is done by following our clear and detailed upgrade guides. +- `minor` - new features, released in backwards-compatible ways; **every few months**; update takes seconds. +- `patch` - bug fixes & small non-breaking changes; historically **every week**; update takes seconds. When we release a new Backpack\CRUD version, all paid add-ons receive support for it the same day. @@ -100,15 +100,15 @@ When you buy a premium Backpack add-on, you get access to not only _updates_, bu ### Add-ons -Backpack's core is open-source and free (Backpack\CRUD). FREE +Backpack's core is open-source and free (Backpack\CRUD). **FREE** The reason we've been able to build and maintain Backpack since 2016 is that Laravel professionals have supported us, by buying our paid products. As of 2022, these are all Backpack add-ons, which we highly recommend: -- [Backpack PRO](/products/pro-for-unlimited-projects) - a crazy amount of added features; PAID -- [Backpack DevTools](/products/devtools) - a developer UI for generating migrations, models and CRUDs; PAID -- [Backpack FigmaTemplate](/products/figma-template) - quickly create designs and mockups, using Backpack's design; PAID -- [Backpack EditableColumns](/products/editable-columns) - let your admins do quick edits, right in the table view; PAID +- [Backpack PRO](/products/pro-for-unlimited-projects) - a crazy amount of added features; **PAID** +- [Backpack DevTools](/products/devtools) - a developer UI for generating migrations, models and CRUDs; **PAID** +- [Backpack FigmaTemplate](/products/figma-template) - quickly create designs and mockups, using Backpack's design; **PAID** +- [Backpack EditableColumns](/products/editable-columns) - let your admins do quick edits, right in the table view; **PAID** -In addition to our open-source core and our closed-source add-ons, there are a few other add-ons you might want to take a look at, that treat common use cases. Some have been developed by our core team, some by our wonderful community. You can just install interfaces to manage [site-wide settings](https://github.com/Laravel-Backpack/Settings), [the default Laravel users table](https://github.com/eduardoarandah/UserManager), [users, groups & permissions](https://github.com/Laravel-Backpack/PermissionManager), [content for custom pages, using page templates](https://github.com/Laravel-Backpack/PageManager), [news articles, categories and tags](https://github.com/Laravel-Backpack/NewsCRUD), etc. FREE +In addition to our open-source core and our closed-source add-ons, there are a few other add-ons you might want to take a look at, that treat common use cases. Some have been developed by our core team, some by our wonderful community. You can just install interfaces to manage [site-wide settings](https://github.com/Laravel-Backpack/Settings), [the default Laravel users table](https://github.com/eduardoarandah/UserManager), [users, groups & permissions](https://github.com/Laravel-Backpack/PermissionManager), [content for custom pages, using page templates](https://github.com/Laravel-Backpack/PageManager), [news articles, categories and tags](https://github.com/Laravel-Backpack/NewsCRUD), etc. **FREE** For more information, please see [our add-ons page](/addons). From 87578f802c4c81e2c0e8c94ac49641ce45c0b6c8 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Thu, 19 Jun 2025 15:04:08 +0300 Subject: [PATCH 39/63] add docs for datagrid and datalist components --- 7.x-dev/base-components.md | 207 ++++++++++++++++++++++++++++++++----- 1 file changed, 180 insertions(+), 27 deletions(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index 6f198f77..f18255b2 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -30,8 +30,8 @@ All components also allow you to specify custom attributes. When you specify a c Even though the 'target' attribute doesn't _technically_ exist in the component, that attribute will be placed on that component's `a` element. - -## Available Components + +## UI Components ### Menu Item @@ -46,29 +46,6 @@ Note that you can further customize this using custom attributes. If you define
- -### DataTable - -Show a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CRUD for that entity needs to be already set up, and passed to this component as a parameter: - -```html - -``` - -The datatable will pick up everything that in your `setupListOperation()`. You can then further add/remove/configure functionality using the configuration closure: - -```html - - :setup="function($crud, $parent) { if ($parent) { $crud->addClause('where', 'customer_id', $parent->id); } }" - name="invoices" - /> -``` - -
- - ### Menu Separator @@ -96,12 +73,188 @@ To show a dropdown menu, with elements, you can use the `menu-dropdown` and `men ``` -Notes: -- on `menu-dropdown` you can define `nested="true"` to flag that dropdown as nested (aka. having a parent); so you can have dropdown in dropdown in dropdown; +Notes: +- on `menu-dropdown` you can define `nested="true"` to flag that dropdown as nested (aka. having a parent); so you can have dropdown in dropdown in dropdown; - on both components, you can also define custom attributes; eg. if you define a `target` on one, that will be passed down to the `a` element;
+ +## Data Components + +These are the components that Backpack uses inside the default CRUD operations. Starting Backpack v7, they are exposed as components, so that you can also use them _outside_ the CrudControllers, or in your custom operations. + + +### Datatable + +![Backpack v7 Datatable component](https://backpackforlaravel.com/uploads/v7/datatable_component.jpg) + +Useful if you want to show the entries in the database, for an Eloquent model. This component shows a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: + +```html + +``` + +**Configuration options:** +- `name='invoices_datatable'` - by default, a name will be generated; but you can pick one you can recognize; +- `operation='list'` - by default, the datatable component will pick up everything that controller sets up for the List operation; if you want to change the operation it will initialize, you can pass this parameter; +- `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove columns, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; + +**Advanced example:** + +```html + +``` + +
+ + +### Datagrid + +![Backpack v7 Datagrid component](https://backpackforlaravel.com/uploads/v7/datagrid_component.jpg) + +Useful if you want to show the attributes of an entry in the database (the attributes of an Eloquent model). This components shows a grid view with all attributes that are configured using CRUD columns. + +There are two ways to use the Datagrid component: + +#### Datagrid for an existing CrudController + +Your datagrid will pick up the configuration in your CrudController automatically. + + +```html + +``` + +**Configuration options:** +- `name='datagrid'` - by default, a name will be generated; but you can pick one you can recognize; +- `operation='show'` - by default, the datagrid component will pick up everything that controller sets up for the Show operation; if you want to change the operation it will initialize, you can pass this parameter; +- `:setup="function($crud, $entry) {}"` - if you want to make changes to the operation setup (eg. add/remove columns, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; + +**Advanced example:** + +```html + +``` + +#### Datagrid for an Eloquent entry + +If you want to show a datagrid component for a entity that does _not_ have a CrudController, you can do that too. But you have to manually specify the columns you want to be shown: + +```html + +``` + + +
+ + +### Datalist + +![Backpack v7 Datalist component](https://backpackforlaravel.com/uploads/v7/datalist_component.jpg) + +Useful if you want to show the attributes of an entry in the database (the attributes of an Eloquent model). This components shows a table with all attributes that are configured using CRUD columns. + +There are two ways to use the Datalist component: + +#### Datalist for an existing CrudController + +Your datalist will pick up the configuration in your CrudController automatically. + + +```html + +``` + +**Configuration options:** +- `name='invoices_datalist'` - by default, a name will be generated; but you can pick one you can recognize; +- `operation='show'` - by default, the datalist component will pick up everything that controller sets up for the Show operation; if you want to change the operation it will initialize, you can pass this parameter; +- `:setup="function($crud, $entry) {}"` - if you want to make changes to the operation setup (eg. add/remove columns, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; + +**Advanced example:** + +```html + +``` + +#### Datalist for an Eloquent entry + +If you want to show a datalist component for a entity that does _not_ have a CrudController, you can do that too. But you have to manually specify the columns you want to be shown: + +```html + +``` + + +
+ + +## Syntaxes for Using Components + +All components that Backpack provides are available to use both using the "full namespace" syntax: + +```html + +``` + +and using the slightly shorter "alias" syntax: + +```html + +``` + +You can use whichever one you prefer. But please note that if you need to pass the components to a dynamic Laravel Blade component, only the "alias" syntax will work (eg. you will pass `:component='bp-datagrid'`). This is a limitation from Laravel, not Backpack. + + ## Overriding Default Components From c0ed9c04d9680ee252047dd49e9262744116a72a Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Sat, 21 Jun 2025 13:12:15 +0300 Subject: [PATCH 40/63] add docs for chip widget --- 7.x-dev/base-widgets.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/7.x-dev/base-widgets.md b/7.x-dev/base-widgets.md index a1d1a5bb..0f09c6c4 100644 --- a/7.x-dev/base-widgets.md +++ b/7.x-dev/base-widgets.md @@ -347,6 +347,23 @@ class ChartjsPieController extends ChartController ``` +
+ + +### Chip + +Shows a chip blade view - which is useful to show more information about a database entry, using little screen real estate. + +```php +[ + 'type' => 'chip', + 'view' => 'crud::chips.general', + 'title' => 'invoices', + 'entry' => Invoice::first(), +] +``` + +
@@ -360,7 +377,7 @@ Shows a datatable component from a particular CrudController. For more info abou 'controller' => 'App\Http\Controllers\Admin\PetShop\InvoiceCrudController', 'name' => 'invoices', 'setup' => function($crud, $parent) { - // you can use this closure to modify your CrudController definition. + // you can use this closure to modify your CrudController definition. if ($parent) { $crud->addClause('where', 'owner_id', $parent->id); } @@ -388,7 +405,7 @@ Allows you to include multiple widgets within a "div" element with the attribute ] ``` -Anything you specify on this widget, other than ```type``` and ```content```, has to be a string, and will be considered an attribute of the "div" element. +Anything you specify on this widget, other than ```type``` and ```content```, has to be a string, and will be considered an attribute of the "div" element. For example, in the following snippet, ```class``` and ```custom-attribute``` are attributes of the "div" element: ```php From 2042b56dc6715eec76e25bd034418b639cf882d3 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Sat, 21 Jun 2025 13:56:46 +0300 Subject: [PATCH 41/63] add new page for chips --- 7.x-dev/crud-chips.md | 222 ++++++++++++++++++++++++++++++++++++++++++ 7.x-dev/index.md | 4 +- 2 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 7.x-dev/crud-chips.md diff --git a/7.x-dev/crud-chips.md b/7.x-dev/crud-chips.md new file mode 100644 index 00000000..6f74c176 --- /dev/null +++ b/7.x-dev/crud-chips.md @@ -0,0 +1,222 @@ +# Chips + +--- + + +## About + +A chips helps show the information of a database entry, in a format that takes up little space visually. + +It can be used inside operations to: +- show more info inside a table cell in **ListOperation**; +- show a related item in more detail in **ShowOperation**; + +A chip consists of only one file - a blade file with the same name as the chip type (ex: ```general.blade.php```). Backpack provides you with one chip type, that is designed to accomodate many types of database entries, but you can easily [create an entirely new chip type](#creating-a-custom-chip-type). + + +### Default Chip Types + + +#### General Chip + +// TODO: add image of general chip + +This chip was designed to be so general, that it's useful to show _most_ types of information from the database. + +```php +@include('crud::chips.general', [ + 'text' => 'John Doe', + 'title' => 'Example of a chip without URL', + 'url' => 'https://google.com/', + 'target' => '_blank', + 'image' => asset('uploads/person1.jpg'), + 'details' => [ + [ + 'icon' => 'la la-hashtag', + 'text' => '8AH13A7', + 'url' => 'mailto:john.doe@example.com', + 'title' => 'Click to email', + ], + [ + 'icon' => 'la la-envelope', + 'text' => 'john.doe@example.com', + 'url' => 'mailto:john.doe@example.com', + 'title' => 'Click to email', + ], + [ + 'icon' => 'la la-phone', + 'text' => '+1 (555) 123-4567', + 'url' => 'tel:+15551234567', + 'title' => 'Click to call', + ] + ] +]) +``` + + +### How to use chips + +Depending on _where_ you want to use a chip, there are a few ways you can do that. Remember - a chip is a simple blade file, so the methods below should be pretty intuitive: + + +#### How to use a chip inside a custom blade view + +// TODO: image with chip inside a custom blade view + +If you want to load a chip inside a custom page, custom component or anything else custom, you can just include the blade view directly, and pass whatever attributes you want to show. For example, if you want to use the `general` chip you can just include that blade file, and pass some of the variables it supports: + +```php +{{-- Example of General chip for a person, with data from Eloquent model --}} +@include('crud::chips.general', [ + 'text' => $user->name, + 'url' => backpack_url('http://github.com/user/'.$user-%3Eid.'/show'), + 'showImage' => false, + // 'image' => backpack_avatar_url(http://github.com/$user), // doesn't work well with dummy data + 'details' => [ + [ + 'icon' => 'la la-hashtag', + 'text' => $user->id, + 'url' => backpack_url('http://github.com/user/'.$user-%3Eid.'/show'), + 'title' => 'Click to preview', + ], + [ + 'icon' => 'la la-envelope', + 'text' => $user->email, + 'url' => 'mailto:'.$user->email, + 'title' => 'Click to email', + ], + [ + 'icon' => 'la la-calendar', + 'text' => $user->created_at->format('F j, Y'), + 'title' => 'Created at '.$user->created_at, + ] + ] +]) +``` + + +#### How to use a chip as a datatable column + +// TODO: image of CRUD before and after using chips in a Datatable + +When your datatables have too many columns, chips become very useful. They allow you to group multiple columns inside a chip, reducing the number of columns and thereby showing more information in less space. No longer will your admins have to expand the table row or use horizontal scrolling to see important info. + +Remember, a chip is just a simple blade file. So to use a chip as a column, we can just use the `view` column type, and pass the path to our chip file. For example: + +```php +// after we create an `invoice` chip +// we can use that chip as a column: +CRUD::addColumn([ + 'name' => 'info', + 'type' => 'view', + 'view' => 'crud::chips.invoice', +]); +``` +By default, the view column type is not searchable. In order to make your chip columns searchable you need to [specify a custom ```searchLogic``` in your declaration](/docs/{{version}}/crud-columns#custom-search-logic). + + +#### How to use a chip as a widget + +// TODO: image with chip as a widget + +Chip files usually only contain the minimum content and styling necessary. You can include them as widgets directly, but they probably won't look very pretty on a custom page, because they don't have a background, borders, shadow etc. That's why we've also created a `chip` widget, which adds wrappers just like the other widgets - so that your chip will look good when placed on a custom page (or an existing CRUD page, why not). + +To use the `chip` widget, you can do: + +```php +Widget::add() + ->to('after_content') // optional + ->type('chip') + ->view('crud::chips.owner') + ->title('Owner') + ->entry($owner); +``` + +
+ + +## Overwriting Default Chip Types + +You can overwrite a chip type by placing a file with the same name in your ```resources\views\vendor\backpack\crud\chips``` directory. But it is NOT recommended to do so. When you're overwriting a default chip type, you're forfeiting any future updates for that chip. We can't push updates to a file that you're no longer using. + +In 99.9% of the cases, it's recommended NOT to override the default `general` chip file, but to create a _custom_ chip file. That will make it a lot easier to upgrade to newer versions of Backpack - because the file is completely in your control. + +
+ + +## Creating a Custom Chip Type + +Chips consist of only one file - a blade file with the same name as the chip type (ex: ```person.blade.php```). You can create one by placing a new blade file inside ```resources\views\vendor\backpack\crud\chips```. Be careful to choose a distinctive name - usually the model name works best. + +// TODO: create this command +To create a new chip file in the standard directory, you can run `php artisan backpack:chip {chip-file-name}`. This will create a new file in that directory, from a stub, for you to customize however you want. + +For example, you can do `php artisan backpack:chip person` to create a ```person.blade.php``` then includes the HTML content directly: + +```html +
+
+
+
+
+ +
+
+
+ +
+ + + 8AH13A7 + + + + john.doe@example.com + + + + +1 (555) 123-4567 + +
+
+
+
+``` + +But most likely, you'll want to create a chip that outputs some information for a particular database entry. If you like how the `general` chip looks, and only want to make it easy to re-use the chip, you can create a chip that includes the `general` chip. For example: + +```php +@php + $last_purchase = $entry->invoices()->orderBy('issuance_date', 'DESC')->first()->issuance_date; +@endphp + +@include('crud::chips.general', [ + 'text' => $entry->name, + 'url' => backpack_url('http://github.com/pet-shop/owner/'.$entry-%3Eid.'/show'), + 'image' => asset($entry->avatar->url), + // 'showImage' => false, + 'details' => [ + [ + 'icon' => 'la la-dog', + 'text' => $entry->pets->count().' pets', + 'title' => 'Number of pets: '.$entry->pets->count(), + ], + [ + 'icon' => 'la la-shopping-cart', + 'text' => $entry->invoices->count(). ' purchases', + 'title' => 'Number of purchases: '.$entry->invoices->count(), + ], + [ + 'icon' => 'la la-calendar', + 'text' => $last_purchase->format('F j, Y'), + 'title' => 'Last purchase: '.$last_purchase, + ] + ] +]) +``` + +Otherwise, you can create a completely custom chip, that looks and works differently from the `general` chip. There are no limitations - since chips are simple blade files. diff --git a/7.x-dev/index.md b/7.x-dev/index.md index cb6360d6..c46ebe04 100644 --- a/7.x-dev/index.md +++ b/7.x-dev/index.md @@ -16,7 +16,7 @@ - [3. Advanced Features](/docs/{{version}}/getting-started-advanced-features) - [4. Add-ons, License & Support](/docs/{{version}}/getting-started-license-and-support) - [Tutorials](/docs/{{version}}/tutorials) - + #### Admin UI - [About](/docs/{{version}}/base-about) @@ -36,6 +36,7 @@ + [Columns](/docs/{{version}}/crud-columns) + [Buttons](/docs/{{version}}/crud-buttons) + [Filters](/docs/{{version}}/crud-filters) + + [Chips](/docs/{{version}}/crud-chips) + [Create](/docs/{{version}}/crud-operation-create) & [Update](/docs/{{version}}/crud-operation-update) + [Fields](/docs/{{version}}/crud-fields) + [Save Actions](/docs/{{version}}/crud-save-actions) @@ -44,6 +45,7 @@ + [Delete](/docs/{{version}}/crud-operation-delete) + [Show](/docs/{{version}}/crud-operation-show) + [Columns](/docs/{{version}}/crud-columns) + + [Chips](/docs/{{version}}/crud-chips) - [Additional Operations](/docs/{{version}}/crud-operations) + [Clone](/docs/{{version}}/crud-operation-clone) + [Reorder](/docs/{{version}}/crud-operation-reorder) From 1451ca6131ba7215914a894e2246acc9d4348a25 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Tue, 24 Jun 2025 12:48:45 +0300 Subject: [PATCH 42/63] add docs for dataform component --- 7.x-dev/base-components.md | 42 ++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index f18255b2..139b2d70 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -84,6 +84,40 @@ Notes: These are the components that Backpack uses inside the default CRUD operations. Starting Backpack v7, they are exposed as components, so that you can also use them _outside_ the CrudControllers, or in your custom operations. + + +### Dataform + +![Backpack v7 Dataform component](https://backpackforlaravel.com/uploads/v7/dataform_component.jpg) + +This component helps you show a form _anywhere you want_, so the admin to easily create or edit an entries for an Eloquent model. The dataform component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: + +```html + +``` + +**Configuration options:** +- `name='invoice_form'` - by default, a name will be generated; but you can pick one you can recognize; +- `operation='create'` - by default, the datatable component will pick up everything that controller sets up for the Create operation; if you want to change the operation it will initialize, you can pass this parameter; +- `:entry="\App\Models\Invoice::find(1)"` - if you want to use UpdateOperation or a custom form operation that needs the entry; +- `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove fields, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; + +**Advanced example:** + +```html + +``` + +
+ ### Datatable @@ -92,7 +126,7 @@ These are the components that Backpack uses inside the default CRUD operations. Useful if you want to show the entries in the database, for an Eloquent model. This component shows a datatable _anywhere you want_, so the admin to easily list, filter, search and perform other operations on entries of an Eloquent model. The datatable component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: ```html - + ``` **Configuration options:** @@ -104,7 +138,7 @@ Useful if you want to show the entries in the database, for an Eloquent model. T ```html ``` @@ -193,7 +227,7 @@ Your datalist will pick up the configuration in your CrudController automaticall ```html ``` From ff321f8392c3ea76d1acc12183cfe74270754096 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Tue, 24 Jun 2025 12:53:04 +0300 Subject: [PATCH 43/63] mention dataform widget --- 7.x-dev/base-widgets.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/7.x-dev/base-widgets.md b/7.x-dev/base-widgets.md index a1d1a5bb..8652410d 100644 --- a/7.x-dev/base-widgets.md +++ b/7.x-dev/base-widgets.md @@ -347,10 +347,27 @@ class ChartjsPieController extends ChartController ``` + +### Dataform + +Shows a dataform component from a particular CrudController. For more info about the configuration parameter, please see the [dataform component docs](/docs/{{version}}/base-components#dataform). + +```php +[ + 'type' => 'dataform', + 'controller' => 'App\Http\Controllers\Admin\InvoiceCrudController', + 'name' => 'invoice_form', + 'setup' => function($crud, $parent) { + // you can use this closure to modify your CrudController definition. + $crud->removeField('notes'); + } +] +``` +
-### DataTable +### Datatable Shows a datatable component from a particular CrudController. For more info about the configuration parameter, please see the [datatable component docs](/docs/{{version}}/base-components#datatable). @@ -360,7 +377,7 @@ Shows a datatable component from a particular CrudController. For more info abou 'controller' => 'App\Http\Controllers\Admin\PetShop\InvoiceCrudController', 'name' => 'invoices', 'setup' => function($crud, $parent) { - // you can use this closure to modify your CrudController definition. + // you can use this closure to modify your CrudController definition. if ($parent) { $crud->addClause('where', 'owner_id', $parent->id); } @@ -388,7 +405,7 @@ Allows you to include multiple widgets within a "div" element with the attribute ] ``` -Anything you specify on this widget, other than ```type``` and ```content```, has to be a string, and will be considered an attribute of the "div" element. +Anything you specify on this widget, other than ```type``` and ```content```, has to be a string, and will be considered an attribute of the "div" element. For example, in the following snippet, ```class``` and ```custom-attribute``` are attributes of the "div" element: ```php From 1cdcd74cf286c62a54e2dcdcbd59137c7efe5f15 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Wed, 25 Jun 2025 13:27:31 +0300 Subject: [PATCH 44/63] change general chip syntax, polish docs --- 7.x-dev/crud-chips.md | 127 +++++++++++++++++++++++++++--------------- 1 file changed, 83 insertions(+), 44 deletions(-) diff --git a/7.x-dev/crud-chips.md b/7.x-dev/crud-chips.md index 6f74c176..7d989197 100644 --- a/7.x-dev/crud-chips.md +++ b/7.x-dev/crud-chips.md @@ -5,13 +5,11 @@ ## About -A chips helps show the information of a database entry, in a format that takes up little space visually. +A chips helps show the information of a database entry, in a format that takes up little space visually. It can be used anywhere you want, but it's particularly useful inside operations to: +- show more info inside a table cell in the **ListOperation**; +- show a related item in more detail in the **ShowOperation**; -It can be used inside operations to: -- show more info inside a table cell in **ListOperation**; -- show a related item in more detail in **ShowOperation**; - -A chip consists of only one file - a blade file with the same name as the chip type (ex: ```general.blade.php```). Backpack provides you with one chip type, that is designed to accomodate many types of database entries, but you can easily [create an entirely new chip type](#creating-a-custom-chip-type). +A chip consists of only one file - a blade file with the same name as the chip type (ex: ```general.blade.php```). Backpack provides you with one chip type, that is very general (hence the name). This chip is designed to accomodate most types of database entries - but if your needs are more particular, you can easily [create an entirely new chip type](#creating-a-custom-chip-type). ### Default Chip Types @@ -19,33 +17,70 @@ A chip consists of only one file - a blade file with the same name as the chip t #### General Chip -// TODO: add image of general chip +![Backpack v7 general chip](https://backpackforlaravel.com/uploads/v7/general_chip.jpg) + +This chip was designed to be so general, that it's useful to show _most_ types of entries from the database. The general chip has 3 sections: `heading`, `image` and `details`. All sections are optional. Each of those sections has one mandatory attribute, `content`. Any other attributes you specify on those sections will be placed on that DOM element. -This chip was designed to be so general, that it's useful to show _most_ types of information from the database. +Here's a very minimal usage of the general chip: ```php @include('crud::chips.general', [ - 'text' => 'John Doe', - 'title' => 'Example of a chip without URL', - 'url' => 'https://google.com/', - 'target' => '_blank', - 'image' => asset('uploads/person1.jpg'), + 'heading' => [ + 'content' => 'John Doe', + ], + 'image' => [ + 'content' => asset('uploads/person1.jpg'), + ], 'details' => [ [ 'icon' => 'la la-hashtag', - 'text' => '8AH13A7', + 'content' => '8AH13A7', + ], + [ + 'icon' => 'la la-envelope', + 'content' => 'john.doe@example.com', + ], + [ + 'icon' => 'la la-phone', + 'content' => '+1 (555) 123-4567', + ] + ] +]) +``` + +But you can also specify more attributes, to enhance your chip with links, titles etc: + +```php +@include('crud::chips.general', [ + 'heading' => [ + 'content' => 'John Doe', + 'href' => 'https://google.com/', + 'target' => '_blank', + 'title' => 'Example of a chip without URL', + ], + 'image' => [ + 'content' => asset('uploads/person1.jpg'), + 'element' => 'a', + 'href' => 'https://chatgpt.com/', + 'target' => '_blank', + 'title' => 'Image can have its own URL, but why?! Falls back to the one in the heading', + ], + 'details' => [ + [ + 'icon' => 'la la-hashtag', + 'content' => '8AH13A7', 'url' => 'mailto:john.doe@example.com', 'title' => 'Click to email', ], [ 'icon' => 'la la-envelope', - 'text' => 'john.doe@example.com', + 'content' => 'john.doe@example.com', 'url' => 'mailto:john.doe@example.com', 'title' => 'Click to email', ], [ 'icon' => 'la la-phone', - 'text' => '+1 (555) 123-4567', + 'content' => '+1 (555) 123-4567', 'url' => 'tel:+15551234567', 'title' => 'Click to call', ] @@ -61,33 +96,38 @@ Depending on _where_ you want to use a chip, there are a few ways you can do tha #### How to use a chip inside a custom blade view -// TODO: image with chip inside a custom blade view - If you want to load a chip inside a custom page, custom component or anything else custom, you can just include the blade view directly, and pass whatever attributes you want to show. For example, if you want to use the `general` chip you can just include that blade file, and pass some of the variables it supports: ```php -{{-- Example of General chip for a person, with data from Eloquent model --}} +{{-- Example of General chip for a person, with data from a User model --}} @include('crud::chips.general', [ - 'text' => $user->name, - 'url' => backpack_url('http://github.com/user/'.$user-%3Eid.'/show'), - 'showImage' => false, - // 'image' => backpack_avatar_url(http://github.com/$user), // doesn't work well with dummy data + 'heading' => [ + 'content' => $user->name, + 'href' => backpack_url('http://github.com/user/'.$user-%3Eid.'/show'), + 'title' => 'Click to preview', + ], + 'image' => [ + 'content' => backpack_avatar_url(http://github.com/$user), // doesn't work well with dummy data + 'element' => 'a', + 'href' => backpack_url('http://github.com/user/'.$user-%3Eid.'/show'), + 'title' => 'Because of dummy data, this image is not available, but it would show a profile image', + ], 'details' => [ [ 'icon' => 'la la-hashtag', - 'text' => $user->id, + 'content' => $user->id, 'url' => backpack_url('http://github.com/user/'.$user-%3Eid.'/show'), 'title' => 'Click to preview', ], [ 'icon' => 'la la-envelope', - 'text' => $user->email, + 'content' => $user->email, 'url' => 'mailto:'.$user->email, 'title' => 'Click to email', ], [ 'icon' => 'la la-calendar', - 'text' => $user->created_at->format('F j, Y'), + 'content' => $user->created_at->format('F j, Y'), 'title' => 'Created at '.$user->created_at, ] ] @@ -97,9 +137,9 @@ If you want to load a chip inside a custom page, custom component or anything el #### How to use a chip as a datatable column -// TODO: image of CRUD before and after using chips in a Datatable +![Backpack v7 general chip in datatable component](https://backpackforlaravel.com/uploads/v7/general_chip_in_datatable_component.jpg) -When your datatables have too many columns, chips become very useful. They allow you to group multiple columns inside a chip, reducing the number of columns and thereby showing more information in less space. No longer will your admins have to expand the table row or use horizontal scrolling to see important info. +When your datatables have too many columns, chips become particularly useful. They allow you to compress the info from 5 or more columns... into a single chip column. This improves the UX of big datatables - your admins will no longer have to expand the table row or use horizontal scrolling to see crucial info. Remember, a chip is just a simple blade file. So to use a chip as a column, we can just use the `view` column type, and pass the path to our chip file. For example: @@ -117,7 +157,7 @@ By default, the view column type is not searchable. In order to make your chip c #### How to use a chip as a widget -// TODO: image with chip as a widget +![Backpack v7 general chip as widget](https://backpackforlaravel.com/uploads/v7/general_chip_as_widget.jpg) Chip files usually only contain the minimum content and styling necessary. You can include them as widgets directly, but they probably won't look very pretty on a custom page, because they don't have a background, borders, shadow etc. That's why we've also created a `chip` widget, which adds wrappers just like the other widgets - so that your chip will look good when placed on a custom page (or an existing CRUD page, why not). @@ -137,7 +177,7 @@ Widget::add() ## Overwriting Default Chip Types -You can overwrite a chip type by placing a file with the same name in your ```resources\views\vendor\backpack\crud\chips``` directory. But it is NOT recommended to do so. When you're overwriting a default chip type, you're forfeiting any future updates for that chip. We can't push updates to a file that you're no longer using. +You can override a chip by create a file in ```resources\views\vendor\backpack\crud\chips``` with the same name. But it is NOT recommended to override the `general` chip type. When you do that, you're forfeiting any future updates for that chip. We can't push updates to a file that you're no longer using. In 99.9% of the cases, it's recommended NOT to override the default `general` chip file, but to create a _custom_ chip file. That will make it a lot easier to upgrade to newer versions of Backpack - because the file is completely in your control. @@ -148,7 +188,6 @@ In 99.9% of the cases, it's recommended NOT to override the default `general` ch Chips consist of only one file - a blade file with the same name as the chip type (ex: ```person.blade.php```). You can create one by placing a new blade file inside ```resources\views\vendor\backpack\crud\chips```. Be careful to choose a distinctive name - usually the model name works best. -// TODO: create this command To create a new chip file in the standard directory, you can run `php artisan backpack:chip {chip-file-name}`. This will create a new file in that directory, from a stub, for you to customize however you want. For example, you can do `php artisan backpack:chip person` to create a ```person.blade.php``` then includes the HTML content directly: @@ -195,28 +234,28 @@ But most likely, you'll want to create a chip that outputs some information for @endphp @include('crud::chips.general', [ - 'text' => $entry->name, - 'url' => backpack_url('http://github.com/pet-shop/owner/'.$entry-%3Eid.'/show'), - 'image' => asset($entry->avatar->url), - // 'showImage' => false, + 'heading' => [ + 'content' => 'Invoice '.$entry->series.' '.$entry->number.' - '.$entry->owner->name, + 'href' => backpack_url('http://github.com/pet-shop/invoice/'.$entry-%3Eid.'/show'), + ], 'details' => [ [ - 'icon' => 'la la-dog', - 'text' => $entry->pets->count().' pets', - 'title' => 'Number of pets: '.$entry->pets->count(), + 'icon' => 'la la-dollar', + 'content' => $entry->total, + 'title' => 'Total invoice amount $'.$entry->total, ], [ - 'icon' => 'la la-shopping-cart', - 'text' => $entry->invoices->count(). ' purchases', - 'title' => 'Number of purchases: '.$entry->invoices->count(), + 'icon' => 'la la-tags', + 'content' => $entry->items->count().' items', ], [ 'icon' => 'la la-calendar', - 'text' => $last_purchase->format('F j, Y'), - 'title' => 'Last purchase: '.$last_purchase, + 'content' => $last_purchase->format('F j, Y'), + 'title' => 'Issuance date: '.$last_purchase, ] ] ]) + ``` -Otherwise, you can create a completely custom chip, that looks and works differently from the `general` chip. There are no limitations - since chips are simple blade files. +Otherwise, you can create a completely custom chip, that looks and works differently from the `general` chip. There are no limitations - since chips are simple blade files. Just copy-paste the HTML from the `general` chip and change it to match your needs. Or add completely different HTML - there are no limitations. From 07d8bc2e7699c24b18a672cbd50a282c2e83e26f Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Wed, 25 Jun 2025 13:57:17 +0300 Subject: [PATCH 45/63] better docs for chip command --- 7.x-dev/crud-chips.md | 78 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/7.x-dev/crud-chips.md b/7.x-dev/crud-chips.md index 7d989197..14e363f9 100644 --- a/7.x-dev/crud-chips.md +++ b/7.x-dev/crud-chips.md @@ -152,7 +152,12 @@ CRUD::addColumn([ 'view' => 'crud::chips.invoice', ]); ``` -By default, the view column type is not searchable. In order to make your chip columns searchable you need to [specify a custom ```searchLogic``` in your declaration](/docs/{{version}}/crud-columns#custom-search-logic). + +Now create that blade file, by running `php artisan backpack:chip invoice`. This will create a file in `resources/views/admin/chips` for you to edit, and customize as you like. By default, it just uses the `$entry` variable (which will be present if you use it as a column). You can include the `general` chip view if it's good enough for you, or copy-paste the HTML from the `general` chip, and modify it to your liking (you can run `php artisan backpack:chip invoice --from=general` to create a chip with all the HTML from general). + +Please note: +- By default, the view column type is not searchable. In order to make your chip columns searchable you need to [specify a custom ```searchLogic``` in your declaration](/docs/{{version}}/crud-columns#custom-search-logic). +- By default, the view column type is not orderable. In order to make your chip columns orderable you need to [specify a custom ```orderLogic``` in your declaration](/docs/{{version}}/crud-columns#custom-order-logic). #### How to use a chip as a widget @@ -188,9 +193,42 @@ In 99.9% of the cases, it's recommended NOT to override the default `general` ch Chips consist of only one file - a blade file with the same name as the chip type (ex: ```person.blade.php```). You can create one by placing a new blade file inside ```resources\views\vendor\backpack\crud\chips```. Be careful to choose a distinctive name - usually the model name works best. -To create a new chip file in the standard directory, you can run `php artisan backpack:chip {chip-file-name}`. This will create a new file in that directory, from a stub, for you to customize however you want. +To create a new chip file in the standard directory, you can run: +- `php artisan backpack:chip {chip-name}` to create a new file in that directory, from our stub that assumes you want to use that chip inside the ListOperation and ShowOperation, so you'll be using the `$entry` variable to define what you want the chip to include; +- `php artisan backpack:chip {chip-name} --from=general` to create a new file in that directory, from our `general` chip, so you can change the HTML however you want; + +For example, you can do `php artisan backpack:chip invoice` to create ```invoice.blade.php``` that helps you define what that chips includes: + +```php +@php + $last_purchase = $entry->invoices()->orderBy('issuance_date', 'DESC')->first()->issuance_date; +@endphp + +@include('crud::chips.general', [ + 'heading' => [ + 'content' => 'Invoice '.$entry->series.' '.$entry->number.' - '.$entry->owner->name, + 'href' => backpack_url('http://github.com/pet-shop/invoice/'.$entry-%3Eid.'/show'), + ], + 'details' => [ + [ + 'icon' => 'la la-dollar', + 'content' => $entry->total, + 'title' => 'Total invoice amount $'.$entry->total, + ], + [ + 'icon' => 'la la-tags', + 'content' => $entry->items->count().' items', + ], + [ + 'icon' => 'la la-calendar', + 'content' => $last_purchase->format('F j, Y'), + 'title' => 'Issuance date: '.$last_purchase, + ] + ] +]) +``` -For example, you can do `php artisan backpack:chip person` to create a ```person.blade.php``` then includes the HTML content directly: +But you can also run `php artisan backpack:chip custom --from=general`, wipe everything inside the generated file, and include your own custom HTML, hardcoded or not: ```html
@@ -226,36 +264,4 @@ For example, you can do `php artisan backpack:chip person` to create a ```person
``` -But most likely, you'll want to create a chip that outputs some information for a particular database entry. If you like how the `general` chip looks, and only want to make it easy to re-use the chip, you can create a chip that includes the `general` chip. For example: - -```php -@php - $last_purchase = $entry->invoices()->orderBy('issuance_date', 'DESC')->first()->issuance_date; -@endphp - -@include('crud::chips.general', [ - 'heading' => [ - 'content' => 'Invoice '.$entry->series.' '.$entry->number.' - '.$entry->owner->name, - 'href' => backpack_url('http://github.com/pet-shop/invoice/'.$entry-%3Eid.'/show'), - ], - 'details' => [ - [ - 'icon' => 'la la-dollar', - 'content' => $entry->total, - 'title' => 'Total invoice amount $'.$entry->total, - ], - [ - 'icon' => 'la la-tags', - 'content' => $entry->items->count().' items', - ], - [ - 'icon' => 'la la-calendar', - 'content' => $last_purchase->format('F j, Y'), - 'title' => 'Issuance date: '.$last_purchase, - ] - ] -]) - -``` - -Otherwise, you can create a completely custom chip, that looks and works differently from the `general` chip. There are no limitations - since chips are simple blade files. Just copy-paste the HTML from the `general` chip and change it to match your needs. Or add completely different HTML - there are no limitations. +Otherwise, you can create a completely custom chip, that looks and works differently from the `general` chip, and re-use that in your application. There are no limitations - since chips are simple blade files. Just copy-paste the HTML from the `general` chip and change it to match your needs. From 7ad8a047f11a3dc57473de95b410ca1f79d9d127 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Wed, 25 Jun 2025 13:59:56 +0300 Subject: [PATCH 46/63] note about eager loading --- 7.x-dev/crud-chips.md | 1 + 1 file changed, 1 insertion(+) diff --git a/7.x-dev/crud-chips.md b/7.x-dev/crud-chips.md index 14e363f9..4f571ba3 100644 --- a/7.x-dev/crud-chips.md +++ b/7.x-dev/crud-chips.md @@ -156,6 +156,7 @@ CRUD::addColumn([ Now create that blade file, by running `php artisan backpack:chip invoice`. This will create a file in `resources/views/admin/chips` for you to edit, and customize as you like. By default, it just uses the `$entry` variable (which will be present if you use it as a column). You can include the `general` chip view if it's good enough for you, or copy-paste the HTML from the `general` chip, and modify it to your liking (you can run `php artisan backpack:chip invoice --from=general` to create a chip with all the HTML from general). Please note: +- If your chip uses any info from RELATED items, you should probably eager load those items. For example if you're in an InvoiceCrudController you could do this in your `setupListOperation()` or hell maybe even in setup(): `CRUD::with(['event', 'event.production', 'event.venue', 'event.venue.city']);` - that way when your chip needs that info, it already has it onpage, and makes no extra queries; - By default, the view column type is not searchable. In order to make your chip columns searchable you need to [specify a custom ```searchLogic``` in your declaration](/docs/{{version}}/crud-columns#custom-search-logic). - By default, the view column type is not orderable. In order to make your chip columns orderable you need to [specify a custom ```orderLogic``` in your declaration](/docs/{{version}}/crud-columns#custom-order-logic). From 67a63d5ae7913607fb85747f8b057f43e74fb1a8 Mon Sep 17 00:00:00 2001 From: Cristian Tabacitu Date: Thu, 26 Jun 2025 20:44:36 +0300 Subject: [PATCH 47/63] polish v7 installation, release notes and upgrade guide before beta launch --- 7.x-dev/installation.md | 13 ++++-- 7.x-dev/release-notes.md | 85 ++++++++++++++++++++++++++++------------ 7.x-dev/upgrade-guide.md | 46 +++++++++++----------- 3 files changed, 94 insertions(+), 50 deletions(-) diff --git a/7.x-dev/installation.md b/7.x-dev/installation.md index 8fc6859d..b6e6197d 100644 --- a/7.x-dev/installation.md +++ b/7.x-dev/installation.md @@ -5,11 +5,11 @@ ## Requirements -If you can run Laravel 10 or 11, you can install Backpack. Backpack does _not_ have additional requirements. +If you can run Laravel 12, you can install Backpack. Backpack does _not_ have additional requirements. For the following process, we assume: -- you have a [working installation of Laravel](https://laravel.com/docs/11.x#installation) (an existing project is fine, you don't need a *fresh* Laravel install); +- you have a [working installation of Laravel](https://laravel.com/docs/12.x#installation) (an existing project is fine, you don't need a *fresh* Laravel install); - you have configured your .ENV file with your database and mail information; @@ -24,7 +24,14 @@ For the following process, we assume: Go to your Laravel project's directory, then in your terminal, run: ``` bash -composer require backpack/crud +# during beta, configure your Composer.json to accept unstable version, by running: +composer config minimum-stability dev +composer config prefer-stable true + +# then require the v7-beta: +composer require backpack/crud:"^7.0@dev" + +# and finally, install Backpack: php artisan backpack:install ``` diff --git a/7.x-dev/release-notes.md b/7.x-dev/release-notes.md index 664e7749..e6555e9c 100644 --- a/7.x-dev/release-notes.md +++ b/7.x-dev/release-notes.md @@ -2,34 +2,64 @@ --- -**Planned launch date:** Dec 4th, 2024 +**Planned launch date:** August 1st, 2025 -For the past 2 years, we've done our very best to make all changes to Backpack in a backwards-compatible way. To not push a new version, because we know it's a pain in the bee's hind to upgrade stuff. But... it's time for a new release. Have no fear though, we've made this super easy for you. +For the past 2.5 years, we've done our very best to make all changes to Backpack in a backwards-compatible way. To not push a new version, because we know it's a pain to upgrade stuff. But... it's time for a new release. Have no fear though, we've made this super easy for you - and the new features & bug fixes are worth it! -Backpack v7 is a maintenance release. Yes, it does have a few breaking changes, but they will not impact 99.9% of projects. But that doesn't mean you shouldn't follow the upgrade guide! Please do - read it from top to bottom and make sure none of the changes impact you. +Here are the BIG things Backpack v7 brings to the table and why you should upgrade from [Backpack v6](/docs/6.x) to v7. But first... we should give credit where credit is due. **Big BIG thanks to our team: [Pedro Martins](https://github.com/pxpm), [Jorge Castro](https://github.com/jcastroa87)**, [Karan Datwani](https://github.com/karandatwani92)** and [Cristian Tabacitu](https://github.com/tabacitu) for working on this new version - and of course **our paying customers**, who have made all of this possible by supporting our work 🙏 -Here are the BIG things Backpack v7 brings to the table and why you should upgrade from [Backpack v6](/docs/6.x) to v7. But first... we should give credit where credit is due. **Big BIG thanks to**: -- **[Pedro Martins](https://github.com/pxpm)** for x; -- **[Jorge Castro](https://github.com/jcastroa87)** for y; -- **[Karan Datwani](https://github.com/karandatwani92)** for z; -- **[Cristian Tabacitu](https://github.com/tabacitu)** for t; -- **our paying customers**, who have made all of this possible by supporting our work 🙏 - -Together, our team has put in an incredible amount of work to make v7 what it is - more than XXX commits, across YYY months, all while still maintaining, bug fixing and improving v6. Again, big thanks to everybody who has helped made this happen 🙏 +Together, our team has put in an incredible amount of work to make v7 what it is - more than 1000 commits, across more than 8 months, all while still maintaining, bug fixing and improving v6. Again, big thanks to everybody who has helped made this happen - and of course, BIG thanks to our beta testers 🙏 ## Added -### CRUD Lifecycle Hooks +### Data Components -Previously when working with Operations, developers found themselves needing to _override_ an entire operation method, in order to do things before/after the routes/defaults/operation is set up. This created a lot of duplicate code, and made it hard to maintain. Now, you can use CRUD Lifecycle Hooks to add your own code before/after each operation method. This is a much cleaner way to add your own code, without having to override the entire method. [Read more](/docs/{{version}}/crud-operations#lifecycle-hooks). +Our team has spend a lot of time and effort to make it possible to include the content of our main operations... anywhere you want. In the process, we've not only bent the laws of physics (ok maybe only PHP), but also made those operations _cleaner_. + +#### Datatable component + +![Datatable component in Backpack for Laravel v7](https://backpackforlaravel.com/uploads/v7/datatable_component.jpg) + +You can now include a datatable anywhere you want! Just use the component in your custom views, custom pages or custom operations - it will pick up all the setup from your existing CrudController. [Read more](/docs/{{version}}/base-components#datatable-1). + +#### Dataform component + +![Dataform component in Backpack for Laravel v7](https://backpackforlaravel.com/uploads/v7/dataform_component.jpg) + +You can now include a form anywhere you want! Same as the datatable - just use the component in your custom blade files, and it will pick up the fields from your CrudController. [Read more](/docs/{{version}}/base-components#dataform-component). + +#### Datalist component + +![Datalist component in Backpack for Laravel v7](https://backpackforlaravel.com/uploads/v7/datalist_component.jpg) + +You can now use the content of the Show page for a particular entry... anywhere you want. It's as simple as loading the component and passing the CrudController. [Read more](/docs/{{version}}/base-components#datalist-component). + +#### Datagrid component + +![Datagrid component in Backpack for Laravel v7](https://backpackforlaravel.com/uploads/v7/datagrid_component.jpg) + +Our previous design for the Show operation worked fine... but it wasn't pretty. We've developed an alternative comopnent, so that your Show operation looks a little better - just specify you want the show operation to use `datagrid` in your `config/backpack/operations/show.php`. Of course... you can also use it (you guessed it)... anywhere you want. It's as simple as loading the component and passing the CrudController. [Read more](/docs/{{version}}/base-components#datagrid-component). -### Two-Factor Authentication +### Chips -// TODO +![Chips in Backpack v7](https://backpackforlaravel.com/uploads/v7/general_chip.jpg) -### Re-Usable Filters +You know columns, you know fields - please welcome... chips! A chips helps show the information of a database entry, in a format that takes up little space visually. It can be used anywhere you want, but it's particularly useful inside the Show and List operations, to cram as much info as possible in as little space as possible. [Read more](/docs/{{version}}/crud-chips). +### Skins + +![Chips in Backpack v7](https://backpackforlaravel.com/uploads/v7/glass_skin.jpg) + +It's been 2.5 years since we've adopted Tabler as our default HTML template - and in this time, we have only grown more fond of it. We are truly convinced that it's the best free Bootstrap template for admin panels, and our partnership and commitment has only grown. This new version of Backpack comes with a new feature inside our Tabler theme... skins. + +Skins are a simple CSS file, that you can enable/not, to give your admin panel a completely different look. We're launching with one modern skin (that we call "non-liquid glass"). Soon enough, we'll follow up with a few more skins and... a way for you to _quickly_ create a custom skin, that will match your brand colors. + +### CRUD Lifecycle Hooks + +Previously when working with Operations, developers found themselves needing to _override_ an entire operation method, in order to do things before/after the routes/defaults/operation is set up. This created a lot of duplicate code, and made it hard to maintain. Now, you can use CRUD Lifecycle Hooks to add your own code before/after each operation method. This is a much cleaner way to add your own code, without having to override the entire method. [Read more](/docs/{{version}}/crud-operations#lifecycle-hooks). + +### Re-usable Filters - Inside Custom Pages or Operations ![](https://backpackforlaravel.com/uploads/docs/filters/filters-in-custom-page.png) @@ -39,29 +69,34 @@ Starting with this Backpack version, you can use the [filters](/docs/{{version}} Filters can now be used inside [Custom Views for your List operation](https://backpackforlaravel.com/docs/{{version}}/crud-operation-list-entries#custom-views-for-listoperation-pro). This means once the admin has selected the Custom View, they can further drill down in the list, using the filters. But not only that... you can _remove_ the general filters and add entirely new filters, just for that Custom View. -### Browser Tests - -// TODO - - ## Changed +### New Versions for All Assets + +We've bumped the version of ALL javascript and CSS assets we have, across the board. By upgrading to Backpack v7, you're automatically getting the best they have to offer - including Tabler, Bootstrap, Datatables etc. + ### Uploaders -// TODO +We've ironed out all the quirks of Uploaders (and uploaders inside repeatables etc). This needed a few small breaking changes, but nothing that should affect you, if you haven't created custom uploaders. Try them again - they should all work fine now! ### Moved TinyMCE and CKEditor fields & columns -// TODO +We've moved the TinyMCE & CKeditor fields & columns from PRO to their own addons - released under open-source licenses. Please note that the underlying JS libraries are under GPLv2 license - which means you should not use them inside paid projects without purchasing a license from their respective creators. ### Basset -// TODO +A revolution in how easy it is to load CSS and JS assets in PHP, but we found out the hard way that making things easy is... _hard_. We're glad to tell you we've finally fixed most problems that came with Basset - and it's more reliable than ever. Additionally, you can now: +- name your assets, to easily use the same asset in multiple places; +- publish the assetmap, to override assets from vendor packages; +- use Basset on localhost (to code without an internet connection); +- store your assets in Git, so there's zero need to run basset in production; + +For more information, check out [the docs for Basset's next version](https://github.com/Laravel-Backpack/basset/tree/next). ### Parent Theme -// TODO +// TODO: docs ## Removed diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index b48b3ed4..f16d003e 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -4,6 +4,8 @@ This will guide you to upgrade from Backpack v6 to v7. The steps are color-coded by the probability that you will need it for your application: High, Medium and Low. **At the very least, please read what's in bold**. +> IMPORTANT NOTE: This upgrade guide is NOT AT ALL final. We do not recommend you upgrade your existing project to v7. We're working on making the upgrade process easier for you. We will let you know when this changes. + ## Requirements @@ -26,7 +28,7 @@ Please make sure your project respects the requirements below, before you start ## Upgrade Steps -Step 0. **[Upgrade to Laravel 11](https://laravel.com/docs/11.x/upgrade) if you don't use it yet, then test to confirm your app is working fine.** +Step 0. **[Upgrade to Laravel 12](https://laravel.com/docs/12.x/upgrade) if you don't use it yet, then test to confirm your app is working fine.** ### Composer @@ -34,29 +36,29 @@ Please make sure your project respects the requirements below, before you start Step 1. Update your ```composer.json``` file to require: ``` - "backpack/crud": "v7-dev", + "backpack/crud": "^7.0@dev", ``` Step 2. Bump the version of any first-party Backpack add-ons you have installed (eg. `backpack/pro`, `backpack/editable-columns` etc.) to the versions that support Backpack v6. For 3rd-party add-ons, please check each add-on's Github page. Here's a quick list of 1st party packages and versions: ```js - "backpack/crud": "v7-dev", - "backpack/pro": "v3-dev", - "backpack/filemanager": "^3.0", - "backpack/theme-coreuiv2": "^1.0", - "backpack/theme-coreuiv4": "^1.0", - "backpack/theme-tabler": "^1.0", - "backpack/logmanager": "^5.0", - "backpack/settings": "^3.1", - "backpack/newscrud": "^5.0", - "backpack/permissionmanager": "^7.0", - "backpack/pagemanager": "^3.2", - "backpack/menucrud": "^4.0", - "backpack/backupmanager": "^5.0", - "backpack/editable-columns": "^3.0", - "backpack/revise-operation": "^2.0", - "backpack/medialibrary-uploaders": "^1.0", - "backpack/devtools": "^2.0", + "backpack/crud": "dev-next", + "backpack/pro": "dev-next", + "backpack/filemanager": "dev-next", + "backpack/theme-coreuiv2": "dev-next", + "backpack/theme-coreuiv4": "dev-next", + "backpack/theme-tabler": "dev-next", + "backpack/logmanager": "dev-next", + "backpack/settings": "dev-next", + "backpack/newscrud": "dev-next", + "backpack/permissionmanager": "dev-next", + "backpack/pagemanager": "dev-next", + "backpack/menucrud": "dev-next", + "backpack/backupmanager": "dev-next", + "backpack/editable-columns": "dev-next", + "backpack/revise-operation": "dev-next", + "backpack/medialibrary-uploaders": "dev-next", + "backpack/devtools": "dev-next", ``` Step 3. Let's get the latest Backpack and install it. If you get any conflicts with **Backpack 1st party add-ons**, most of the time you just need to move one version up, eg: from `backpack/menucrud: ^3.0` to `backpack/menucrud: ^4.0`. See the step above again. Please run: @@ -109,10 +111,10 @@ No changes needed. ### Views -**List Operation View** - The List Operation view got a huge change. We decoupled the datatable from the view, so that you can use the table anywhere you would like. -Most of the code is still identical but moved to `datatable.blade.php`. The `list.blade.php` view now only includes the mentioned datatable component. +**List Operation View** - The List Operation view got a huge change. We decoupled the datatable from the view, so that you can use the table anywhere you would like. +Most of the code is still identical but moved to `datatable.blade.php`. The `list.blade.php` view now only includes the mentioned datatable component. -If you had customized the `list.blade.php` you should move your customizations to `datatable.blade.php`. +If you had customized the `list.blade.php` you should move your customizations to `datatable.blade.php`. ### Security From 37491c853ee8052bab6d93f3b58e39e8d8da5eaf Mon Sep 17 00:00:00 2001 From: flartet Date: Mon, 30 Jun 2025 10:47:02 +0200 Subject: [PATCH 48/63] Update crud-columns.md bad field in join --- 6.x/crud-columns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/6.x/crud-columns.md b/6.x/crud-columns.md index 062e92d7..1ba20aa8 100644 --- a/6.x/crud-columns.md +++ b/6.x/crud-columns.md @@ -1542,7 +1542,7 @@ $this->crud->addColumn([ 'attribute' => 'name', // foreign key attribute that is shown to user 'orderable' => true, 'orderLogic' => function ($query, $column, $columnDirection) { - return $query->leftJoin('categories', 'categories.id', '=', 'articles.select') + return $query->leftJoin('categories', 'categories.id', '=', 'articles.category_id') ->orderBy('categories.name', $columnDirection)->select('articles.*'); } ]); From d1f93c3ff613c901d21659ce49632d0b5d68889b Mon Sep 17 00:00:00 2001 From: Pedro Martins Date: Tue, 1 Jul 2025 10:49:39 +0100 Subject: [PATCH 49/63] Update crud-columns.md in v7 to match v6 docs --- 7.x-dev/crud-columns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/7.x-dev/crud-columns.md b/7.x-dev/crud-columns.md index 63478d37..93986ef2 100644 --- a/7.x-dev/crud-columns.md +++ b/7.x-dev/crud-columns.md @@ -1498,7 +1498,7 @@ $this->crud->addColumn([ 'attribute' => 'name', // foreign key attribute that is shown to user 'orderable' => true, 'orderLogic' => function ($query, $column, $columnDirection) { - return $query->leftJoin('categories', 'categories.id', '=', 'articles.select') + return $query->leftJoin('categories', 'categories.id', '=', 'articles.category_id') ->orderBy('categories.name', $columnDirection)->select('articles.*'); } ]); From 6c46df2e576b77077f9889bc65342fb811006c2f Mon Sep 17 00:00:00 2001 From: Mohammad Emran Date: Wed, 2 Jul 2025 07:23:46 +0600 Subject: [PATCH 50/63] Update links to larave.com docs --- 6.x/base-how-to.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/6.x/base-how-to.md b/6.x/base-how-to.md index 4b8efe38..3e136130 100644 --- a/6.x/base-how-to.md +++ b/6.x/base-how-to.md @@ -51,7 +51,7 @@ In order to place something else inside that view, like [widgets](/docs/{{versio ``` To use information from the database, you can: -- [use view composers](https://laravel.com/docs/5.7/views#view-composers) to push variables inside this view, when it's loaded; +- [use view composers](https://laravel.com/docs/views#view-composers) to push variables inside this view, when it's loaded; - load all your dashboard information using AJAX calls, if you're loading charts, reports, etc, and the DB queries might take a long time; - use the full namespace for your models, like ```\App\Models\Product::count()```; @@ -290,7 +290,7 @@ This is a default in Backpack v4. Backpack's authentication uses a completely separate authentication driver, provider, guard and password broker. They're all named ```backpack```, and registered in the vendor folder, invisible to you. -If you need a separate login for user, just go ahead and create it. [Add the Laravel authentication, like instructed in the Laravel documentation](https://laravel.com/docs/5.7/authentication#authentication-quickstart): ```php artisan make:auth```. You'll then have: +If you need a separate login for user, just go ahead and create it. [Add the Laravel authentication, like instructed in the Laravel documentation](https://laravel.com/docs/authentication#authentication-quickstart): ```php artisan make:auth```. You'll then have: - the user login at ```/login``` -> using the AuthenticationController Laravel provides - the admin login at ```/admin/login``` -> using the AuthenticationControllers Backpack provides @@ -440,7 +440,7 @@ This will make the registration process pick up a view you can create, in ```res In Backpack CRUD 6.2 we introduced the ability to require email verification when accessing Backpack routes. To enable this feature please do the following: -**Step 1** - Make sure your user model (usually `App\Models\User`) implements the `Illuminate\Contracts\Auth\MustVerifyEmail` contract. [More info](https://laravel.com/docs/10.x/verification#model-preparation). +**Step 1** - Make sure your user model (usually `App\Models\User`) implements the `Illuminate\Contracts\Auth\MustVerifyEmail` contract. [More info](https://laravel.com/docs/verification#model-preparation). ```php Date: Thu, 3 Jul 2025 09:21:27 +0600 Subject: [PATCH 51/63] Update links to Laravel docs --- 7.x-dev/base-how-to.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/7.x-dev/base-how-to.md b/7.x-dev/base-how-to.md index 4b8efe38..3e136130 100644 --- a/7.x-dev/base-how-to.md +++ b/7.x-dev/base-how-to.md @@ -51,7 +51,7 @@ In order to place something else inside that view, like [widgets](/docs/{{versio ``` To use information from the database, you can: -- [use view composers](https://laravel.com/docs/5.7/views#view-composers) to push variables inside this view, when it's loaded; +- [use view composers](https://laravel.com/docs/views#view-composers) to push variables inside this view, when it's loaded; - load all your dashboard information using AJAX calls, if you're loading charts, reports, etc, and the DB queries might take a long time; - use the full namespace for your models, like ```\App\Models\Product::count()```; @@ -290,7 +290,7 @@ This is a default in Backpack v4. Backpack's authentication uses a completely separate authentication driver, provider, guard and password broker. They're all named ```backpack```, and registered in the vendor folder, invisible to you. -If you need a separate login for user, just go ahead and create it. [Add the Laravel authentication, like instructed in the Laravel documentation](https://laravel.com/docs/5.7/authentication#authentication-quickstart): ```php artisan make:auth```. You'll then have: +If you need a separate login for user, just go ahead and create it. [Add the Laravel authentication, like instructed in the Laravel documentation](https://laravel.com/docs/authentication#authentication-quickstart): ```php artisan make:auth```. You'll then have: - the user login at ```/login``` -> using the AuthenticationController Laravel provides - the admin login at ```/admin/login``` -> using the AuthenticationControllers Backpack provides @@ -440,7 +440,7 @@ This will make the registration process pick up a view you can create, in ```res In Backpack CRUD 6.2 we introduced the ability to require email verification when accessing Backpack routes. To enable this feature please do the following: -**Step 1** - Make sure your user model (usually `App\Models\User`) implements the `Illuminate\Contracts\Auth\MustVerifyEmail` contract. [More info](https://laravel.com/docs/10.x/verification#model-preparation). +**Step 1** - Make sure your user model (usually `App\Models\User`) implements the `Illuminate\Contracts\Auth\MustVerifyEmail` contract. [More info](https://laravel.com/docs/verification#model-preparation). ```php Date: Tue, 22 Jul 2025 14:25:01 +0100 Subject: [PATCH 52/63] update upgrade guide --- 7.x-dev/upgrade-guide.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index 3ffd2138..e6cc40f2 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -42,8 +42,8 @@ Please make sure your project respects the requirements below, before you start Step 2. Bump the version of any first-party Backpack add-ons you have installed (eg. `backpack/pro`, `backpack/editable-columns` etc.) to the versions that support Backpack v6. For 3rd-party add-ons, please check each add-on's Github page. Here's a quick list of 1st party packages and versions: ```js - "backpack/crud": "dev-next", - "backpack/pro": "dev-next", + "backpack/crud": "^7.0@dev", + "backpack/pro": "^3.0@dev", "backpack/filemanager": "dev-next", "backpack/theme-coreuiv2": "dev-next", "backpack/theme-coreuiv4": "dev-next", @@ -91,7 +91,19 @@ No changes needed. ### Config -No changes needed. +**Theme Tabler** - The default layout for theme tabler has changed. If you had the tabler config published you are good to go. **In case you don't have the tabler theme config published** and want to keep the old layout, you should publish it by running `php artisan vendor:publish --tag="theme-tabler-config"` and changing: +```diff +- 'layout' => 'horizontal', ++ 'layout' => 'horizontal_overlap', +``` +You should also remove the glass skin and fuzzy background from the theme styles: +```diff +'styles' => [ + base_path('vendor/backpack/theme-tabler/resources/assets/css/skins/backpack-color-palette.css'), +- base_path('vendor/backpack/theme-tabler/resources/assets/css/skins/glass.css'), +- base_path('vendor/backpack/theme-tabler/resources/assets/css/skins/fuzzy-background.css'), + ], +``` ### CrudControllers @@ -106,7 +118,7 @@ No changes needed. ### CSS & JS Assets -No changes needed. + ### Views @@ -143,9 +155,10 @@ If the table view still looks wonky (search bar out of place, big + instead of e ### Upgrade Add-ons -For any addons you might have upgraded, please double-check if they have an upgrade guide. For example: -- Xx package has the upgrade guide here; -- Yy package has the upgrade guide here; +**backpack/file-manager** Using the File Manager package? Most of the views that weren't in use were removed, and the dependencies were bumped. If you didn't do any customization you should delete the `resources/views/vendor/elfinder` (`rm -rf resources/views/vendor/elfinder`) folder. +No need to publish any views anymore if you are not customizing them. If you were, publish the new view files (`php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="elfinder-views"`). Then apply your customization on the new files, now located at: `resources/views/vendor/backpack/filemanager/` + +Additional the `browse` and `browse_multiple` **fields/columns** are now part of this package. If you previously made any modifications to this fields/columns you should publish the new views (`php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="filemanger-fields"` and `php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="filemanager-columns"`), and carry over the modifications from the old files to this new files. --- From 4c90b08674972c3eff3dfd7f0016b18e88f46e29 Mon Sep 17 00:00:00 2001 From: Karan Datwani Date: Wed, 23 Jul 2025 17:54:24 +0530 Subject: [PATCH 53/63] Add "backpack/generators": "dev-next", --- 7.x-dev/upgrade-guide.md | 1 + 1 file changed, 1 insertion(+) diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index e6cc40f2..a8c677ec 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -59,6 +59,7 @@ Please make sure your project respects the requirements below, before you start "backpack/revise-operation": "dev-next", "backpack/medialibrary-uploaders": "dev-next", "backpack/devtools": "dev-next", + "backpack/generators": "dev-next", ``` Step 3. Let's get the latest Backpack and install it. If you get any conflicts with **Backpack 1st party add-ons**, most of the time you just need to move one version up, eg: from `backpack/menucrud: ^3.0` to `backpack/menucrud: ^4.0`. See the step above again. Please run: From c5c50dfae2cdd4e4c48f6db32dfabd1728a152ff Mon Sep 17 00:00:00 2001 From: Karan Datwani Date: Wed, 23 Jul 2025 21:54:03 +0530 Subject: [PATCH 54/63] note --- 7.x-dev/upgrade-guide.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index a8c677ec..3317f72a 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -62,6 +62,8 @@ Please make sure your project respects the requirements below, before you start "backpack/generators": "dev-next", ``` +> **Note:** To install Backpack v7 beta and its add-ons, set `"minimum-stability": "beta"` in your `composer.json`. + Step 3. Let's get the latest Backpack and install it. If you get any conflicts with **Backpack 1st party add-ons**, most of the time you just need to move one version up, eg: from `backpack/menucrud: ^3.0` to `backpack/menucrud: ^4.0`. See the step above again. Please run: ```bash @@ -92,7 +94,7 @@ No changes needed. ### Config -**Theme Tabler** - The default layout for theme tabler has changed. If you had the tabler config published you are good to go. **In case you don't have the tabler theme config published** and want to keep the old layout, you should publish it by running `php artisan vendor:publish --tag="theme-tabler-config"` and changing: +**Theme Tabler** - The default layout for theme tabler has changed. If you had the tabler config published you are good to go. **In case you don't have the tabler theme config published** and want to keep the old layout, you should publish it by running `php artisan vendor:publish --tag="theme-tabler-config"` and changing: ```diff - 'layout' => 'horizontal', + 'layout' => 'horizontal_overlap', @@ -156,10 +158,10 @@ If the table view still looks wonky (search bar out of place, big + instead of e ### Upgrade Add-ons -**backpack/file-manager** Using the File Manager package? Most of the views that weren't in use were removed, and the dependencies were bumped. If you didn't do any customization you should delete the `resources/views/vendor/elfinder` (`rm -rf resources/views/vendor/elfinder`) folder. +**backpack/file-manager** Using the File Manager package? Most of the views that weren't in use were removed, and the dependencies were bumped. If you didn't do any customization you should delete the `resources/views/vendor/elfinder` (`rm -rf resources/views/vendor/elfinder`) folder. No need to publish any views anymore if you are not customizing them. If you were, publish the new view files (`php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="elfinder-views"`). Then apply your customization on the new files, now located at: `resources/views/vendor/backpack/filemanager/` -Additional the `browse` and `browse_multiple` **fields/columns** are now part of this package. If you previously made any modifications to this fields/columns you should publish the new views (`php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="filemanger-fields"` and `php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="filemanager-columns"`), and carry over the modifications from the old files to this new files. +Additional the `browse` and `browse_multiple` **fields/columns** are now part of this package. If you previously made any modifications to this fields/columns you should publish the new views (`php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="filemanger-fields"` and `php artisan vendor:publish --provider="Backpack\FileManager\FileManagerServiceProvider" --tag="filemanager-columns"`), and carry over the modifications from the old files to this new files. --- From 2a6b65e4e3f5107a83d5913f52620cfcb713a30c Mon Sep 17 00:00:00 2001 From: Pedro Martins Date: Tue, 19 Aug 2025 18:43:56 +0100 Subject: [PATCH 55/63] update json column docs docs for https://github.com/Laravel-Backpack/CRUD/pull/5845 --- 7.x-dev/crud-columns.md | 1 + 1 file changed, 1 insertion(+) diff --git a/7.x-dev/crud-columns.md b/7.x-dev/crud-columns.md index 93986ef2..a06774b3 100644 --- a/7.x-dev/crud-columns.md +++ b/7.x-dev/crud-columns.md @@ -446,6 +446,7 @@ Display database stored JSON in a prettier way to your users. 'label' => 'JSON', 'type' => 'json', // 'escaped' => false, // echo using {!! !!} instead of {{ }}, in order to render HTML + 'toggle' => true //show a toggle button on the column that show/hide the json contents ], ``` From ddb7f4f77f06ca1f6b0473bc0c6078e379f5c361 Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 10 Oct 2025 16:37:35 +0100 Subject: [PATCH 56/63] add modal form docs --- 7.x-dev/base-components.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index 139b2d70..ac02028d 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -90,7 +90,7 @@ These are the components that Backpack uses inside the default CRUD operations. ![Backpack v7 Dataform component](https://backpackforlaravel.com/uploads/v7/dataform_component.jpg) -This component helps you show a form _anywhere you want_, so the admin to easily create or edit an entries for an Eloquent model. The dataform component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: +This component helps you show a form _anywhere you want_, so the admin can easily create or edit an entries for an Eloquent model. The dataform component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: ```html @@ -118,6 +118,38 @@ This component helps you show a form _anywhere you want_, so the admin to easily
+ +### Dataform Modal + +![Backpack v7 Dataform Modal component](https://backpackforlaravel.com/uploads/v7/dataform_component.jpg) + +This component helps you show a form _anywhere you want_ inside a modal, so the admin can easily create or edit an entry for an Eloquent model without having to refresh the whole page. The dataform modal component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: + +```html + +``` + +**Configuration options:** +- `name='invoice_form'` - by default, a name will be generated; but you can pick one you can recognize; +- `operation='create'` - by default, the datatable component will pick up everything that controller sets up for the Create operation; if you want to change the operation it will initialize, you can pass this parameter; +- `:entry="\App\Models\Invoice::find(1)"` - if you want to use UpdateOperation or a custom form operation that needs the entry; +- `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove fields, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; + +**Advanced example:** + +```html + +``` +
+ ### Datatable From a9f03c199982e093f717dc73daf438ff4909242f Mon Sep 17 00:00:00 2001 From: pxpm Date: Fri, 10 Oct 2025 17:42:45 +0100 Subject: [PATCH 57/63] wip --- 7.x-dev/base-components.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index ac02028d..fa9f63a9 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -150,6 +150,8 @@ This component helps you show a form _anywhere you want_ inside a modal, so the ```
+> **NOTE**: The tinymce and date_picker (jquery version) does not properly work in this context. Please use any alternative. + ### Datatable From f0b0d184cf37f587ac12253a957d858e33faba6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Mon, 20 Oct 2025 15:24:57 +0300 Subject: [PATCH 58/63] Update composer.json requirement for backpack/crud --- 7.x-dev/upgrade-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index 3317f72a..26f1a737 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -36,13 +36,13 @@ Please make sure your project respects the requirements below, before you start Step 1. Update your ```composer.json``` file to require: ``` - "backpack/crud": "^7.0@dev", + "backpack/crud": "^7.0.0-beta", ``` Step 2. Bump the version of any first-party Backpack add-ons you have installed (eg. `backpack/pro`, `backpack/editable-columns` etc.) to the versions that support Backpack v6. For 3rd-party add-ons, please check each add-on's Github page. Here's a quick list of 1st party packages and versions: ```js - "backpack/crud": "^7.0@dev", + "backpack/crud": "^7.0.0-beta", "backpack/pro": "^3.0@dev", "backpack/filemanager": "dev-next", "backpack/theme-coreuiv2": "dev-next", From a7dce0ddb35b1fbc2f575e4f69fa55d68b171017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Thu, 23 Oct 2025 08:57:03 +0300 Subject: [PATCH 59/63] Update Backpack add-ons and configuration options Updated version requirements for Backpack add-ons and added new configuration options for operations. --- 7.x-dev/upgrade-guide.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/7.x-dev/upgrade-guide.md b/7.x-dev/upgrade-guide.md index 26f1a737..d09616e2 100644 --- a/7.x-dev/upgrade-guide.md +++ b/7.x-dev/upgrade-guide.md @@ -43,7 +43,7 @@ Please make sure your project respects the requirements below, before you start ```js "backpack/crud": "^7.0.0-beta", - "backpack/pro": "^3.0@dev", + "backpack/pro": "^3.0.0-alpha", "backpack/filemanager": "dev-next", "backpack/theme-coreuiv2": "dev-next", "backpack/theme-coreuiv4": "dev-next", @@ -94,7 +94,16 @@ No changes needed. ### Config -**Theme Tabler** - The default layout for theme tabler has changed. If you had the tabler config published you are good to go. **In case you don't have the tabler theme config published** and want to keep the old layout, you should publish it by running `php artisan vendor:publish --tag="theme-tabler-config"` and changing: +Step X. **Operation Config Files** - We have added new configuration options in the files inside `config/backpack/operations/`. If you have those files published, it is recommended that you copy the new options in your files too. + +Step X. **Show Operation New Default** - inside `config/backpack/operations/show.php` you'll find a new option, to choose which component will be used on the show operation. By default it's the new component `bp-datagrid`, but you can switch to `bp-datalist` if you want to keep the same look as before: + +```php + // Which component to use for displaying the Show page? + 'component' => 'bp-datalist', // options: bp-datagrid, bp-datalist, or a custom component alias +``` + +Step X. **Theme Tabler** - The default layout for theme tabler has changed. If you had the tabler config published you are good to go. **In case you don't have the tabler theme config published** and want to keep the old layout, you should publish it by running `php artisan vendor:publish --tag="theme-tabler-config"` and changing: ```diff - 'layout' => 'horizontal', + 'layout' => 'horizontal_overlap', From bac899e88a7b2dab1fd2893db3cf9829e4d550c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20T=C4=83b=C4=83citu?= Date: Thu, 23 Oct 2025 10:30:08 +0300 Subject: [PATCH 60/63] Add RTL text direction configuration instructions Added instructions for setting text direction to RTL in UI configuration. --- 7.x-dev/base-how-to.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/7.x-dev/base-how-to.md b/7.x-dev/base-how-to.md index 3e136130..8d2a90a1 100644 --- a/7.x-dev/base-how-to.md +++ b/7.x-dev/base-how-to.md @@ -6,6 +6,17 @@ ## Look and feel + +### Text direction: LTR or RTL + +By default, the text direction is set to left-to-right. If your UI is in Arabic, Hebrew or any other language that needs to show right-to-left, you can easily enable that - just go to `config/backpack/ui.php` and change the `html_direction` variable to `rtl`: + +``` + // Direction, according to language + // (left-to-right vs right-to-left) + 'html_direction' => 'ltr', +``` + ### Customize the menu or sidebar From 63f4ecccfe9826b7e3aa9a65642c766da6bb1023 Mon Sep 17 00:00:00 2001 From: pxpm Date: Tue, 28 Oct 2025 16:52:00 +0000 Subject: [PATCH 61/63] wip --- 7.x-dev/base-components.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index fa9f63a9..231f7968 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -97,7 +97,6 @@ This component helps you show a form _anywhere you want_, so the admin can easil ``` **Configuration options:** -- `name='invoice_form'` - by default, a name will be generated; but you can pick one you can recognize; - `operation='create'` - by default, the datatable component will pick up everything that controller sets up for the Create operation; if you want to change the operation it will initialize, you can pass this parameter; - `:entry="\App\Models\Invoice::find(1)"` - if you want to use UpdateOperation or a custom form operation that needs the entry; - `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove fields, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; @@ -123,16 +122,17 @@ This component helps you show a form _anywhere you want_, so the admin can easil ![Backpack v7 Dataform Modal component](https://backpackforlaravel.com/uploads/v7/dataform_component.jpg) -This component helps you show a form _anywhere you want_ inside a modal, so the admin can easily create or edit an entry for an Eloquent model without having to refresh the whole page. The dataform modal component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: +This component helps you show a form _anywhere you want_ inside a modal, so the admin can easily create or edit an entry for an Eloquent model without having to refresh the whole page. + +To use this component you are required to add `CreateInModalOperation` and/or `UpdateInModalOperation` in your CrudController. The dataform modal component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: ```html ``` **Configuration options:** -- `name='invoice_form'` - by default, a name will be generated; but you can pick one you can recognize; -- `operation='create'` - by default, the datatable component will pick up everything that controller sets up for the Create operation; if you want to change the operation it will initialize, you can pass this parameter; -- `:entry="\App\Models\Invoice::find(1)"` - if you want to use UpdateOperation or a custom form operation that needs the entry; +- `operation='createInModal'` - by default, the component will pick up everything that controller sets up for the Create operation; if you want to change the operation it will initialize, you can pass this parameter, eg: `updateInModal` +- `:entry="\App\Models\Invoice::find(1)"` - if you want to use UpdateInModalOperation or a custom form operation that needs the entry; - `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove fields, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; **Advanced example:** @@ -141,7 +141,7 @@ This component helps you show a form _anywhere you want_ inside a modal, so the ### Datatable From 7a7cd52b62c65ec84cddf886fba600fb1c4e8be5 Mon Sep 17 00:00:00 2001 From: pxpm Date: Tue, 28 Oct 2025 16:56:23 +0000 Subject: [PATCH 62/63] wip --- 7.x-dev/base-components.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index 231f7968..ef7e21e1 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -126,6 +126,12 @@ This component helps you show a form _anywhere you want_ inside a modal, so the To use this component you are required to add `CreateInModalOperation` and/or `UpdateInModalOperation` in your CrudController. The dataform modal component is a extension of a CrudController - so a CrudController for that entity needs to be already set up, and passed to this component as a parameter: +First, in your CrudController, either remove `CreateOperation` in favor of `CreateInModalOperation`, or you can keep both operations. Having both of them is usefull if you want your ListOperation to still show the regular "Create" button, but you would like also to have the possibility to create this entity somewhere else in your application using a modal form. + +```php +use \Backpack\DataformModal\Http\Controllers\Operations\CreateInModalOperation; +``` + ```html ``` From 9e2f8a2a9cd4acc742dff7249a955fc137ffbc26 Mon Sep 17 00:00:00 2001 From: Pedro Martins Date: Fri, 7 Nov 2025 10:44:37 +0000 Subject: [PATCH 63/63] add save action docs (#640) * add save action docs --- 7.x-dev/base-components.md | 31 +++++++++++++ 7.x-dev/crud-save-actions.md | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/7.x-dev/base-components.md b/7.x-dev/base-components.md index ef7e21e1..dd5da5a9 100644 --- a/7.x-dev/base-components.md +++ b/7.x-dev/base-components.md @@ -100,6 +100,8 @@ This component helps you show a form _anywhere you want_, so the admin can easil - `operation='create'` - by default, the datatable component will pick up everything that controller sets up for the Create operation; if you want to change the operation it will initialize, you can pass this parameter; - `:entry="\App\Models\Invoice::find(1)"` - if you want to use UpdateOperation or a custom form operation that needs the entry; - `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove fields, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; +- `:save-actions="[]"` - provide an array of save action definitions or save action classes to replace the defaults (see [Custom save actions](#dataform-custom-save-actions)); +- `:form-inside-card="true"` - render the form inside a Backpack card wrapper so it visually matches the default create/update screens; leave it `false` to output only the raw form markup. **Advanced example:** @@ -115,6 +117,33 @@ This component helps you show a form _anywhere you want_, so the admin can easil /> ``` + +#### Custom save actions + +The Dataform component can swap out the default `Save and back / edit / new` buttons with your own logic. Pass an array to the `:save-actions` attribute containing save action classes (or definitions) that implement Backpack's `SaveActionInterface`: + +```php +@php + use App\Backpack\Crud\SaveActions\SaveAndApprove; + use Backpack\CRUD\app\Library\CrudPanel\SaveActions\SaveAndBack; +@endphp + + +``` + +Each entry in the array can be: +- an instance of a class that implements `SaveActionInterface` (recommended); +- the fully qualified class name of a save action (the container will resolve it); +- a plain array definition (see [`crud-save-actions.md`](crud-save-actions.md)). + +Backpack will replace the default actions for that form, honour the order defined by each class, and fallback to the first action if no default applies. +
@@ -140,6 +169,7 @@ use \Backpack\DataformModal\Http\Controllers\Operations\CreateInModalOperation; - `operation='createInModal'` - by default, the component will pick up everything that controller sets up for the Create operation; if you want to change the operation it will initialize, you can pass this parameter, eg: `updateInModal` - `:entry="\App\Models\Invoice::find(1)"` - if you want to use UpdateInModalOperation or a custom form operation that needs the entry; - `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove fields, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; +- `:save-actions="[]"` - replace the default modal buttons with your own save action classes. **Advanced example:** @@ -172,6 +202,7 @@ Useful if you want to show the entries in the database, for an Eloquent model. T **Configuration options:** - `name='invoices_datatable'` - by default, a name will be generated; but you can pick one you can recognize; - `operation='list'` - by default, the datatable component will pick up everything that controller sets up for the List operation; if you want to change the operation it will initialize, you can pass this parameter; +- `:useFixedHeader="false"` - set this to explicitly enable or disable the sticky header; it defaults to the operation's `useFixedHeader` setting, falling back to `true`; - `:setup="function($crud, $parent) {}"` - if you want to make changes to the operation setup (eg. add/remove columns, configure functionality), you can use this parameter; the closure passed here will be run _after_ the setup of that operation had already completed; **Advanced example:** diff --git a/7.x-dev/crud-save-actions.md b/7.x-dev/crud-save-actions.md index 4fb61c85..679aac24 100644 --- a/7.x-dev/crud-save-actions.md +++ b/7.x-dev/crud-save-actions.md @@ -16,6 +16,91 @@ There are four save actions registered by Backpack by default. They are: - ```save_and_new``` (Save and go to create new entity page) - ```save_and_preview``` (Save and go to show the current entity) + +## Save Action Classes + +Save actions are now first-class citizens. Instead of maintaining large array definitions in each CrudController, you can encapsulate the behaviour inside PHP classes that implement `Backpack\CRUD\app\Library\CrudPanel\SaveActions\SaveActionInterface`. Backpack ships with `SaveAndBack`, `SaveAndEdit`, `SaveAndNew`, and `SaveAndPreview` as examples, and also provides `SaveAndList` for projects that want an explicit "Save and go to list" button. + +### Quick start + +1. **Create a class** inside your application (for example `app/Backpack/Crud/SaveActions/SaveAndApprove.php`). +2. **Extend** `AbstractSaveAction` (recommended) or implement `SaveActionInterface` directly. +3. **Override** the methods that describe your button. +4. **Register** the class with `CRUD::addSaveAction()` / `CRUD::replaceSaveActions()` or pass it to Blade components like ``. + +```php +hasAccess('update') && $crud->entry?->canBeApproved(); + } + + public function getRedirectUrl(CrudPanel $crud, Request $request, $itemId = null): ?string + { + return route('admin.invoices.approve', $itemId ?? $request->input('id')); + } +} +``` + +> **Tip:** `AbstractSaveAction` already implements `toArray()`, order handling, and sensible defaults. Override only what you need. If you must store additional data, you can still return a custom array by implementing `SaveActionInterface` yourself. + +### Registering class-based actions + +Inside your CrudController you can now pass the class instead of an array: + +```php +use App\Backpack\Crud\SaveActions\SaveAndApprove; + +CRUD::replaceSaveActions([ + new SaveAndApprove(), + \Backpack\CRUD\app\Library\CrudPanel\SaveActions\SaveAndBack::class, +]); +``` + +Backpack recognizes three inputs when registering save actions: +- an instantiated save action class; +- the fully qualified class name (it is resolved via the container so dependencies can be injected); +- the legacy associative array definition (still supported). + +The action `order` is taken from the class (or array) and Backpack reorders conflicts automatically. If you need to adjust the order later you can still call `CRUD::orderSaveActions()`. + +### Using classes in Blade components + +The `bp-dataform` component accept save action classes through the `:save-actions` attribute. This allows you to reuse the same custom buttons outside CrudControllers: + +```php + +``` + +When no save actions are provided, Backpack falls back to the defaults registered on the controller. + ## Save Actions API