Nova 提供了幾種不同類型的字段: File
, Image
, 和 Avatar
. File
字段不僅在文件上傳中最為常見,而且也是
Image
和 Avatar
字段類的基類。在接下來的說明中,我們會探索這些不同的字段以及他們之間的異同.
為了說明 Nova 文件上傳字段的行為,假設(shè)我們的應(yīng)用有上傳「用戶頭像」的功能。因此我們會在 users
表中新建一個叫做 profile_photo
的列。這個列將會記錄用戶頭像在磁盤上的路徑,或者當(dāng)我們使用云存儲(例如 Amazon S3、七牛云)時,記錄用戶頭像的鏈接地址。
接下來,我們將文件字段附加到 User
資源上。在這個例子中,我們將會創(chuàng)建該字段并將底層文件存儲在名為 public
的磁盤中。這個磁盤名必須與 config/filesystems.php
配置文件中的磁盤名對應(yīng):
use Laravel\Nova\Fields\File;
File::make('Profile Photo')->disk('public')
當(dāng)使用該字段上傳文件時,Nova 將用 Laravel 的 文件系統(tǒng) 在你選擇的磁盤上存儲該文件,并生成一個隨機(jī)文件名。文件存儲之后,Nova 將在底層數(shù)據(jù)庫列里保存該文件的相對路徑。
為了演示 File
字段的默認(rèn)行為,讓我們來看一個以相同方式存儲文件的等效路由:
use Illuminate\Http\Request;
Route::post('/photo', function (Request $request) {
$path = $request->profile_photo->store('/', 'public');
$request->user()->update([
'profile_photo' => $path,
]);
});
當(dāng)然,文件存儲之后,你可以在應(yīng)用中使用 Laravel 的 Storage
Facade 檢索出該文件:
use Laravel\Support\Facades\Storage;
Storage::get($user->profile_photo);
Storage::url($user->profile_photo);
Image
字段的行為恰好和 File
字段相像;但是,Image
字段并不會在 Nova 面板里顯示一個文件路徑,而是展示一個底層文件的縮略圖預(yù)覽。Image
字段的所有配置和自定義選項都鏡像了 File
字段:
use Laravel\Nova\Fields\Image;
Image::make('Profile Photo')->disk('public')
Avatar
字段的行為恰好和 File
字段相像;但是,Avatar
字段并不會在 Nova 面板里顯示一個文件路徑,而是展示一個底層文件的縮略圖預(yù)覽。Avatar
字段的所有配置和自定義選項都鏡像了 File
字段:
use Laravel\Nova\Fields\Avatar;
Avatar::make('Poster')->disk('public')
除了展示底層文件的縮略圖預(yù)覽之外,Avatar
字段也會自動顯示在 Nova 的搜索結(jié)果中。Avatar
字段不局限于「用戶」資源,你也可以在 Nova 應(yīng)用程序的任何資源里添加 Avatar
字段:
存儲系統(tǒng)除了能夠存儲文件到指定的路徑以外,你也可以通過 Nova 的指令存儲文件的元數(shù)據(jù)(比如:原客戶端的文件名和文件的大?。?,你可以使用 storeOriginalName
和 storeSize
方法完成這些操作。 這些方法都能夠接收你想要存儲的信息的參數(shù)
use Illuminate\Http\Request;
use Laravel\Nova\Fields\File;
use Laravel\Nova\Fields\Text;
/**
* 從上傳資源獲取相應(yīng)的字段用去展示。
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function fields(Request $request)
{
return [
// ...
File::make('Attachment')
->disk('s3')
->storeOriginalName('attachment_name')
->storeSize('attachment_size'),
Text::make('Attachment Name')->exceptOnForms(),
Text::make('Attachment Size')
->exceptOnForms()
->displayUsing(function ($value) {
return number_format($value / 1024, 2).'kb';
}),
];
}
存儲原始客戶端的文件名有一個好處就是能夠用用原文件名下載文件。例如,你可以在應(yīng)用程序的路由中執(zhí)行下面的操作:
use Laravel\Support\Facades\Storage;
Route::get('/download', function () {
$user = $request->user();
return Storage::download(
$user->attachment, $user->attachment_name
);
})
文件的下載
當(dāng)你使用
storeOriginalName
方法,在 Nova 的控制臺下載文件字段
File
字段,Image
,Avatar
字段可以標(biāo)記 prunable
,當(dāng)與文件的關(guān)聯(lián)模型從數(shù)據(jù)庫刪除的時候,prunable 方法能夠命令 Nova 從存儲庫中刪除文件:
File::make('Profile Photo')->disk('public')->prunable()
Nova 不刪除的情況
Nova 僅僅會自動刪除哪些初始化關(guān)聯(lián)刪除的模型,其他沒有配置的可能需要模型自己實現(xiàn)文件的刪除邏輯了。
之前我們了解到,默認(rèn)情況下,Nova 使用 Illuminate\Http\UploadedFile
類的 store
方法存儲文件。然而,你可以按照你的程序的需求完全自定義這個行為。
如果你只需要自定義磁盤上所存儲的文件的名字或路徑,可以使用 File
字段的 path
和 storeAs
方法:
use Illuminate\Http\Request;
File::make('Attachment')
->disk('s3')
->path($request->user()->id.'-attachments')
->storeAs(function (Request $request) {
return sha1($request->attachment->getClientOriginalName());
})
然而,如果你想要掌控一個字段的上所有的文件存儲邏輯,你可以用 store
方法。store
方法接收一個回調(diào)函數(shù),通過它接收進(jìn)來的 HTTP 請求以及請求所關(guān)聯(lián)的模型實例:
use Illuminate\Http\Request;
File::make('Attachment')
->store(function (Request $request, $model) {
return [
'attachment' => $request->attachment->store('/', 's3'),
'attachment_name' => $request->attachment->getClientOriginalName(),
'attachment_size' => $request->attachment->getSize(),
];
})
正如你所見,上例中,store
回調(diào)函數(shù)返回了一個鍵值對的數(shù)組。這些鍵 / 值對被映射到模型實例上,然后才保存到數(shù)據(jù)庫中,這使得你能夠在存儲文件后更新一個或多個模型的數(shù)據(jù)庫列。
當(dāng)然,在一個閉包中執(zhí)行所有的文件存儲邏輯可能會導(dǎo)致你的資源變得臃腫。因為這個原因,Nova 允許你傳遞一個 "可調(diào)用的" 對象到 store
方法:
File::make('Attachment')->store(new StoreAttachment)
這個可調(diào)用的對象應(yīng)當(dāng)是一個簡單的 PHP 類,并且有一個 __invoke
方法:
<?php
namespace App\Nova;
use Illuminate\Http\Request;
class StoreAttachment
{
/**
* 存儲上傳的文件
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Database\Eloquent\Model $model
* @return array
*/
public function __invoke(Request $request, $model)
{
return [
'attachment' => $request->attachment->store('/', 's3'),
'attachment_name' => $request->attachment->getClientOriginalName(),
'attachment_size' => $request->attachment->getSize(),
];
}
}
當(dāng)文件從 Nova 管理員面板中被刪除,Nova 將自動移除底層存儲中的文件,并在字段相關(guān)聯(lián)列中插入 NULL
值。
如果你想要重寫這個行為并提供你自己的文件刪除的實現(xiàn),你可以使用 delete
方法。類似于上面討論的 store
方法,delete
方法接受一個回調(diào)函數(shù),該函數(shù)接收進(jìn)來的 HTTP 請求和該請求相關(guān)聯(lián)的模型實例:
use Illuminate\Http\Request;
use Laravel\Support\Facades\Storage;
File::make('Attachment')
->disk('s3')
->delete(function (Request $request, $model) {
if (! $model->attachment) {
return;
}
Storage::disk($this->disk)->delete($model->attachment);
return [
'attachment' => null,
'attachment_name' => null,
'attachment_size' => null,
];
})
從上例中可以看出,delete
回調(diào)函數(shù)返回一個鍵值對的數(shù)組。這些鍵 / 值對被映射到模型實例上,然后才保存到數(shù)據(jù)庫中,這使得你能夠在存儲文件后更新一個或多個模型的數(shù)據(jù)庫列。通常來說,當(dāng)刪除一個字段時,你將插入 NULL
值到相關(guān)的數(shù)據(jù)庫列中。
當(dāng)然,在一個閉包中執(zhí)行所有的文件刪除邏輯可能會導(dǎo)致資源變得臃腫。由于這個原因,Nova 允許你傳遞一個 "可調(diào)用的" 對象到 delete
方法中:
File::make('Attachment')->delete(new DeleteAttachment)
這個可調(diào)用對象應(yīng)當(dāng)是一個簡單的 PHP 類,并且有一個 __invoke
方法:
<?php
namespace App\Nova;
use Illuminate\Http\Request;
use Laravel\Support\Facades\Storage;
class DeleteAttachment
{
/**
* 刪除字段關(guān)聯(lián)的文件
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Database\Eloquent\Model $model
* @return array
*/
public function __invoke(Request $request, $model)
{
if (! $model->attachment) {
return;
}
Storage::disk($this->disk)->delete($model->attachment);
return [
'attachment' => null,
'attachment_name' => null,
'attachment_size' => null,
];
}
}
默認(rèn)情況下,Nova 是使用 Storage::url
的方法確定 URL,用來在資源詳細(xì)頁上顯示圖片預(yù)覽。然而你也可以使用 preview
來自定義 URL 的生成。
對于 preview
方法接受一個返回預(yù)覽 URL 的調(diào)用。在調(diào)用中,你可以通過 $this->value
訪問字段的底層列值。如下所示:
use Laravel\Nova\Fields\Image;
use Laravel\Support\Facades\Storage;
Image::make('Profile Photo')
->disk('public')
->preview(function () {
return $this->value
? Storage::disk($this->disk)->url($this->value)
: null;
})
預(yù)覽尺寸
默認(rèn)情況系,Nova 的資源詳情頁將顯示寬為 318 像素預(yù)覽圖(為 “視網(wǎng)膜屏幕” 顯示寬為 636 像素) 。
默認(rèn)情況下,Nova 使用 Storage::url
確定 URL。用于在資源索引屏幕上和搜索結(jié)果中(當(dāng)使用 Avatar
字段時),顯示縮略圖預(yù)覽。 然而,你可以使用 thumbnail
方法來定制這個 URL 的生成。
這個 thumbnail
方法接受一個可以返回縮略圖 URL 的調(diào)用。在調(diào)用中,你可以通過 $this->value
訪問字段的底層列值。如下所示:
use Laravel\Nova\Fields\Image;
use Laravel\Support\Facades\Storage;
Image::make('Profile Photo')
->disk('public')
->thumbnail(function () {
return $this->value
? Storage::disk($this->disk)->url($this->value)
: null;
})
縮略圖尺寸
默認(rèn)情況下,Nova 顯示的縮略圖寬度為 32 像素(為 “視網(wǎng)膜屏幕” 顯示 64 像素)。
更多建議: