Laravel Box Adapter is a Laravel package for interacting with the Box API.
- Easily access to the Box API for managing files and folders.
- Supports Filament for file upload.
Box API Reference:
https://developer.box.com/reference/
Registering a developer client for the Box API:
https://app.box.com/developers/console/newapp
Steps:
- Select Custom App
- Step 1 of 2, fill in the app name and purpose input.
- Step 2 of 2, select an authentication method:
User Authentication (OAuth 2.0) - After create custom app, go to
Configurationtab in your platform app. - Copy
Client ID&Client SecretinOAuth 2.0 Credentialssection to your.envfile. - Add redirect URI for your callback url in
OAuth 2.0 Redirect URIssection, you can add your callback localhost url.
- PHP:
^8.2 - Illuminate support:
^11.0 - Guzzlehttp guzzle:
^7.0 - League flysystem:
^3.0 - Ramsey uuid:
^4.0
This package can also be used with:
- Filament:
^3.0|^4.0
Require this package with Composer, in the root directory of your project.
composer require gzai/laravel-box-adapterTo publish the config, run the vendor publish command:
php artisan vendor:publish --provider="Gzai\LaravelBoxAdapter\BoxAdapterServiceProvider" --tag=laravel-box-adapter-configThis will create a new file named config/box.php
The config/box.php config file contains:
return [
'client_id' => env('BOX_CLIENT_ID'),
'client_secret' => env('BOX_CLIENT_SECRET'),
'redirect' => env('BOX_REDIRECT_URI'),
'authorize_url' => 'https://account.box.com/api/oauth2/authorize',
'token_url' => 'https://api.box.com/oauth2/token',
'api_url' => 'https://api.box.com/2.0',
'upload_url' => 'https://upload.box.com/api/2.0',
'routes_enabled' => true,
'user_enabled' => true,
'redirect_callback' => false,
'redirect_callback_url' => '',
'download_folder' => 'box_download',
'folder' => [
'parent' => 0,
],
];Breaking it down:
-
routes_enabledto accommodate Authentication Box and get Callback from Box. Set it tofalseif you want to create your own logic. -
user_enabledis indicates whether thetokenbelongs to a specific user or can be used globally. Set it totruefor a user-specific token, orfalsefor a globally usable token. -
redirect_callbackto accommodate redirect after the API callback Box, set it totruefor redirect to a specific url inredirect_callback_url. -
redirect_callback_urla specific url when you want to redirect after login to Box. -
download_foldera specific folder when you want to download a file to your project path. -
folderadd folders ID of your Box folder. The parent folder is used for the root folder.
To publish the migration, run the vendor publish command:
php artisan vendor:publish --provider="Gzai\LaravelBoxAdapter\BoxAdapterServiceProvider" --tag=laravel-box-adapter-migrationsThis will create a new file named database/migrations/xxxx_xx_xx_xxxxxx_create_box_tokens_table.php
Run the migration:
php artisan migrateAdd the environment variables to your .env file:
BOX_CLIENT_ID=[Client ID]
BOX_CLIENT_SECRET=[Client Secret]
BOX_REDIRECT_URI=http://localhost:9000/box/callbackPlease adjust with your client id, client secret and redirect url.
If your config box routes_enabled is true, you will get 3 additional routes:
php artisan route:listResult:
GET|HEAD box/login
GET|HEAD box/callback
GET|HEAD box/me
You can access Http://localhost:9000/box/login to login with your box account credential, and then you will be redirected to Http://localhost:9000/box/callback.
Add Box service
use Gzai\LaravelBoxAdapter\Facades\Box;Route::get('box/folder/get', function() {
$folderId = 000000000000; // you can change to specific folder id box
// get folder information in box
return Box::getFolder($folderId);
});Route::get('box/folder/exists', function() {
$folderId = 000000000000; // you can change to specific folder id box
// get status folder exists in box
return Box::folderExists($folderId);
});Route::get('box/folder/create', function() {
$folderName = 'new_folder';
$folderId = config('box.folder.parent'); // you can change to specific folder id box
// create folder in box
return Box::createFolder($folderName, $folderId);
});Route::get('box/folder/delete', function() {
$folderId = 000000000000; // you can change to specific folder id box
// delete folder in box
return Box::deleteFolder($folderId);
});Route::get('box/folder/items', function() {
$folderId = 000000000000; // you can change to specific folder id box
// get folder items in box
return Box::getFolderItems($folderId);
});Route::get('box/folder/search', function() {
$folderName = 'new_folder';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new folder.
// During this time, the folder you’re searching for through the Search API might not be found until the indexing is finished.
// search folders by folder name in box
return Box::getFoldersByName($folderName, $folderParentId);
});Route::get('box/folder/search/id', function() {
$folderName = 'new_folder';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new folder.
// During this time, the folder you’re searching for through the Search API might not be found until the indexing is finished.
// search specific folder and get the folder id by folder name in box
return Box::getFolderIdByName($folderName, $folderParentId);
});Route::get('box/folder/search/exists', function() {
$folderName = 'new_folder';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new folder.
// During this time, the folder you’re searching for through the Search API might not be found until the indexing is finished.
// search specific folder and get status folder exists by folder name in box
return Box::getFolderExistsByName($folderName, $folderParentId);
});Route::get('box/folder/search/exactly', function() {
$folderName = 'new_folder';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new folder.
// During this time, the folder you’re searching for through the Search API might not be found until the indexing is finished.
// search specific folder and get status folder exists by folder name in box
return Box::getFolderExactlyByName($folderName, $folderParentId);
});Box Search Indexing Reference:
https://developer.box.com/guides/search/indexing/
Add Box service
use Gzai\LaravelBoxAdapter\Facades\Box;Route::get('box/file/get', function() {
$fileId = 000000000000; // you can change to specific file id box
// get file information in box
return Box::getFile($fileId);
});Route::get('box/file/exists', function() {
$fileId = 000000000000; // you can change to specific file id box
// get status file exists in box
return Box::fileExists($fileId);
});Route::get('box/file/move', function() {
$fileId = 000000000000; // you can change to specific file id box
$parentId = 000000000000; // you can change to specific folder id box
// move file in box
return Box::moveFile($fileId, $parentId);
// or
$newName = 'new_file_name.jpg'; // you can change to new file name with original file extension
return Box::moveFile($fileId, $parentId, $newName);
});Route::get('box/file/copy', function() {
$fileId = 000000000000; // you can change to specific file id box
$parentId = 000000000000; // you can change to specific folder id box
// copy file in box
return Box::copyFile($fileId, $parentId);
// or
$newName = 'new_file_name.jpg'; // you can change to new file name with original file extension
return Box::copyFile($fileId, $parentId, $newName);
});Route::get('box/file/delete', function() {
$fileId = 000000000000; // you can change to specific file id box
// delete file in box
return Box::deleteFile($fileId);
});Route::get('box/file/temporary_url', function() {
$fileId = 000000000000; // you can change to specific file id box
$timeSeconds = 30;
// create temporary link file in box
return Box::createTemporaryLink($fileId, $timeSeconds);
});Route::get('box/file/search', function() {
$fileName = '0199B8F2D13E6930B317C121AB41C.pdf';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new file.
// During this time, the file you’re searching for through the Search API might not be found until the indexing is finished.
// search files by name in box
return Box::getFilesByName($fileName, $folderParentId);
});Route::get('box/file/search/id', function() {
$fileName = '0199B8F2D13E6930B317C121AB41C.pdf';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new file.
// During this time, the file you’re searching for through the Search API might not be found until the indexing is finished.
// seach specific file and get the file id by name in box
return Box::getFileIdByName($fileName, $folderParentId);
});Route::get('box/file/search/exists', function() {
$fileName = '0199B8F2D13E6930B317C121AB41C.pdf';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new file.
// During this time, the file you’re searching for through the Search API might not be found until the indexing is finished.
// seach specific file and get status file exists by name in box
return Box::getFileExistsByName($fileName, $folderParentId);
});Route::get('box/file/search/exactly', function() {
$fileName = '0199B8F2D13E6930B317C121AB41C.pdf';
$folderParentId = config('box.folder.parent'); // you can change to specific folder id box
// note:
// Box may take some time to complete its indexing process for a new file.
// During this time, the file you’re searching for through the Search API might not be found until the indexing is finished.
// seach specific file and get specific file by name in box
return Box::getFileExactlyByName($fileName, $folderParentId);
});Route::get('box/file/upload', function() {
$file = 'app/public/logo.png';
$filePath = storage_path($file);
$folderParentId = 000000000000; // you can change to specific file id box
return Box::uploadFile($filePath, $folderParentId);
});Route::get('box/file/download/force', function() {
$fileId = 000000000000; // you can change to specific file id box
// download file in box
return Box::downloadFile($fileId);
});Route::get('box/file/download/directory', function() {
$fileId = 000000000000; // you can change to specific file id box
// download file in box and save it to the directory according to box config download_folder
return Box::downloadFile($fileId, true);
// or
$folderName = 'new_folder';
// download file in box and save it to the directory according to custom folder name
return Box::downloadFile($fileId, true, $folderNmae);
});Box Adapter can also be used in Laravel Storage
Add Storage
use Illuminate\Support\Facades\Storage;$path = 'folder_a';
return Storage::disk('box')->directoryExists($path);$path = 'folder_a';
return Storage::disk('box')->files($path);$path = 'folder_a';
return Storage::disk('box')->allFiles($path);$path = 'folder_a';
return Storage::disk('box')->directories($path);$path = 'folder_a';
return Storage::disk('box')->allDirectories($path);$path = 'test_folder';
return Storage::disk('box')->makeDirectory($path);$path = 'test_folder';
return Storage::disk('box')->deleteDirectory($path);$path = 'folder_a/01K5B9BGPGDMR5KCS883NM39K3.png';
return Storage::disk('box')->exists($path);$path = 'folder_c/0199F048051772AD8AF7154E2A33D23A.jpg';
return Storage::disk('box')->url($path);$path = 'folder_c/0199F048051772AD8AF7154E2A33D23A.jpg';
$expiration = now()->addMinutes(5);
return Storage::disk('box')->temporaryUrl($path, $expiration);$path_a = 'folder_c/0199F048051772AD8AF7154E2A33D23A.jpg';
$path_b = 'folder_b/0199F048051772AD8AF7154E2A33D23A.jpg';
return Storage::disk('box')->move($path_a, $path_b);$path_a = 'folder_b/0199F048051772AD8AF7154E2A33D23A.jpg';
$path_b = 'folder_c/0199F048051772AD8AF7154E2A33D23A.jpg';
return Storage::disk('box')->copy($path_a, $path_b);$fileName = Box::fileName() . '.jpg';
$path = 'folder_c/'. $fileName;
$content = Storage::get('download/0199BDC0C7C9729B8C7850A96CDEAE21.jpg');
Storage::disk('box')->put($path, $content);
// or
$resource = fopen(storage_path('app/download/0199BDC0C7C9729B8C7850A96CDEAE21.jpg'), 'r');
Storage::disk('box')->put($path, $resource);$path = 'folder_c/0199F0453FCC72DAA0A19FBD63C2B520.jpg';
return Storage::disk('box')->delete($path);$path = 'folder_c/0199F048051772AD8AF7154E2A33D23A.jpg';
return Storage::disk('box')->get($path);$path = 'folder_c/0199F048051772AD8AF7154E2A33D23A.jpg';
$pathExplode = explode('/', $path);
$fileName = last($pathExplode);
return Storage::disk('box')->download($path, $fileName);If you are using Laravel Filament, you can easily integrate the Laravel Box Adapter with the FileUpload component.
You can add disk('box') and use fileUploadBox() method in your Filament FileUpload.
Because Box doesn’t have a public asset URL, we set previewable(false) method in fileUploadBox() to disable file preview.
Forms\Components\FileUpload::make('attachment')
->disk('box')
->directory('folder')
->required()
->fileUploadBox(),When a file is successfully uploaded to Box, you will receive the file ID and folder ID Box data in session.
You can store these IDs before saving your data to the database.
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['parent_id'] = session()->has('parentIdBox') && !empty(session('parentIdBox')) ? session('parentIdBox') : null;
$data['file_id'] = session()->has('fileIdBox') && !empty(session('fileIdBox')) ? session('fileIdBox') : null;
// deleting the parentIdBox & fileIdBox sessions
session()->forget(['parentIdBox', 'fileIdBox']);
return $data;
}or you can update these IDs before saving your data to the database.
use Illuminate\Database\Eloquent\Model;protected function handleRecordUpdate(Model $record, array $data): Model
{
// you can delete old file in box
if ( session()->has('fileIdBox') && !empty(session('fileIdBox')) && $data['attachment'] != null ) {
Box::deleteFile($record->file_id);
}
$data['parent_folder_id'] = session()->has('parentIdBox') && !empty(session('parentIdBox')) ? session('parentIdBox') : $record->parent_folder_id;
$data['file_id'] = session()->has('fileIdBox') && !empty(session('fileIdBox')) ? session('fileIdBox') : $record->file_id;
$data['attachment'] = ( $data['attachment'] != null ) ? $data['attachment'] : $record->attachment;
// deleting the parentIdBox & fileIdBox sessions
session()->forget(['parentIdBox', 'fileIdBox']);
$record->update($data);
return $record;
}Since Filament v4 has a different implementation of saveUploadedFileUsing() compared to Filament v3, you can pass the file ID and folder ID Box data using the Laravel session.
Please see the changelog
Contributing are welcome.