Complete Part 10

This commit is contained in:
Thuan Bui
2025-05-27 09:06:36 +09:00
parent 845c8e7a8b
commit b5d6fdcc19
6 changed files with 257 additions and 1 deletions
+89
View File
@@ -0,0 +1,89 @@
<?php
namespace App\Livewire;
use App\Models\Upload;
use Livewire\Attributes\Validate;
use Livewire\Component;
use Livewire\WithFileUploads;
class FileUpload extends Component
{
use WithFileUploads; // Sử dụng trait WithFileUploads để xử lý upload file trong Livewire.
#[Validate(['files.*' => 'image|max:2048'])] // Thuộc tính Validate dùng để kiểm tra các file upload phải là hình ảnh và dung lượng tối đa 2MB cho mỗi file.
public $files = []; // Khai báo array cho danh sách các file được chọn upload.
public $persistedUploads = []; // Khai báo array cho danh sách các file đã được upload thành công (được lưu trongatabase).
/**
* Lưu các file đã chọn vào thư mục lưu trữ cập nhật sở dữ liệu.
*
* @return void
*/
public function updatedFiles()
{
$this->validate();
//dd('Hello');
$uploadedFiles = $this->files;
$numberOfFiles = count($uploadedFiles); // Đếm số lượng file đã upload
foreach ($uploadedFiles as $file) {
// Lấy tên file gốc từ client
$originalFilename = $file->getClientOriginalName();
$originalFilenames[] = $originalFilename; // Thêm tên gốc vào array
// 3. Tạo bản ghi trong database cho model Upload:
// Lưu ý: Chúng ta chỉ cần lưu 'original_filename'.
// Các thông tin về đường dẫn file gốc và thumbnail sẽ do media-library quản lý.
$uploadEntry = Upload::create([
'original_filename' => $originalFilename,
]);
// 4. Đây là phần quan trọng nhất - Thêm file vào Media Library:
$uploadEntry->addMedia($file) // Thêm file vào Media Library
->toMediaCollection('images'); // Thêm file vào collection 'images'
}
$this->updatePersistedUploads();
$this->reset('files');
session()->flash('success', 'You have successfully uploaded ' . $numberOfFiles . ' files');
}
/**
* Xóa file đã upload khỏi thư mục lưu trữ sở dữ liệu.
*
* @param \App\Models\Upload $upload Model Upload cần xóa.
* @return void
*/
public function destroy(Upload $upload) {
$upload->delete();
$this->updatePersistedUploads();
session()->flash('success', 'You have successfully deleted ' . $upload->original_filename);
}
public function updatePersistedUploads() {
$this->persistedUploads = Upload::latest()->get();
}
/**
* Hàm được gọi khi component được khởi tạo.
* Lấy danh sách các file đã upload từ sở dữ liệu.
*
* @return void
*/
public function mount()
{
$this->updatePersistedUploads();
}
/**
* Render view cho component.
*
* @return \Illuminate\Contracts\View\View
*/
public function render()
{
return view('livewire.file-upload', [
'uploads' => $this->persistedUploads
]);
}
}
+1
View File
@@ -14,6 +14,7 @@
"laravel/framework": "^12.0",
"laravel/tinker": "^2.10.1",
"league/flysystem-aws-s3-v3": "^3.0",
"livewire/livewire": "^3.6",
"spatie/laravel-medialibrary": "^11.12"
},
"require-dev": {
Generated
+77 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f4b1d2eeabd1197b47a6aaeee6c183a7",
"content-hash": "b19804c926a2969b46bece1dbf5db61b",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -2437,6 +2437,82 @@
],
"time": "2024-12-08T08:18:47+00:00"
},
{
"name": "livewire/livewire",
"version": "v3.6.3",
"source": {
"type": "git",
"url": "https://github.com/livewire/livewire.git",
"reference": "56aa1bb63a46e06181c56fa64717a7287e19115e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/livewire/livewire/zipball/56aa1bb63a46e06181c56fa64717a7287e19115e",
"reference": "56aa1bb63a46e06181c56fa64717a7287e19115e",
"shasum": ""
},
"require": {
"illuminate/database": "^10.0|^11.0|^12.0",
"illuminate/routing": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/validation": "^10.0|^11.0|^12.0",
"laravel/prompts": "^0.1.24|^0.2|^0.3",
"league/mime-type-detection": "^1.9",
"php": "^8.1",
"symfony/console": "^6.0|^7.0",
"symfony/http-kernel": "^6.2|^7.0"
},
"require-dev": {
"calebporzio/sushi": "^2.1",
"laravel/framework": "^10.15.0|^11.0|^12.0",
"mockery/mockery": "^1.3.1",
"orchestra/testbench": "^8.21.0|^9.0|^10.0",
"orchestra/testbench-dusk": "^8.24|^9.1|^10.0",
"phpunit/phpunit": "^10.4|^11.5",
"psy/psysh": "^0.11.22|^0.12"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Livewire": "Livewire\\Livewire"
},
"providers": [
"Livewire\\LivewireServiceProvider"
]
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Livewire\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Caleb Porzio",
"email": "calebporzio@gmail.com"
}
],
"description": "A front-end framework for Laravel.",
"support": {
"issues": "https://github.com/livewire/livewire/issues",
"source": "https://github.com/livewire/livewire/tree/v3.6.3"
},
"funding": [
{
"url": "https://github.com/livewire",
"type": "github"
}
],
"time": "2025-04-12T22:26:52+00:00"
},
{
"name": "maennchen/zipstream-php",
"version": "3.1.2",
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Livewire Component</title>
<!-- Styles / Scripts -->
<script src="https://cdn.tailwindcss.com"></script>
@livewireStyles
</head>
<body class="bg-gray-100 font-sans antialiased">
{{ $slot }}
@livewireScripts
</body>
</html>
@@ -0,0 +1,71 @@
<div>
{{-- Upload File Form --}}
<div class="container mx-auto mt-10 p-6 bg-white rounded-lg shadow-md max-w-md">
<h1 class="text-2xl font-bold mb-6 text-center text-gray-700">Upload File</h1>
{{-- <form wire:submit.prevent="save"> --}}
<div class="mb-4">
@if ($files)
@foreach ($files as $file)
<img src="{{ $file->temporaryUrl() }}">
@endforeach
@endif
</div>
<div class="mb-4">
<input type="file" wire:model="files" wire:loading.attr="disabled" multiple>
</div>
<div wire:loading wire:target="files">Uploading...</div>
<div class="mb-4">
@error("files.*")
<p class="text-red-500 text-xs mt-2">{{ $message }}</p>
@enderror
</div>
{{-- <button type="submit"
class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Upload
</button> --}}
{{-- </form> --}}
</div>
{{-- Display Success Message --}}
@if (session("success"))
<div
class="container mx-auto mt-6 p-4 bg-green-100 border border-green-400 text-green-700 rounded-lg shadow-md max-w-md">
<p class="font-bold">Success!</p>
<p>{{ session("success") }}</p>
</div>
@endif
{{-- Display Uploaded File Info --}}
@if (count($uploads) > 0)
<div class="container mx-auto mt-10 p-10 bg-white rounded-lg shadow-md max-w-md">
<h2 class="text-xl font-semibold mb-4 text-gray-700">Previously Uploaded Files:</h2>
@foreach ($uploads as $upload)
<ul>
<li class="flex items-center justify-between mb-4">
<a class="flex items-center gap-4 py-2" href="{{ $upload->url }}" target="_blank">
<img src="{{ $upload->thumbnail_url }}" alt="{{ $upload->original_filename }}"
width="50" height="50">
<span
class="text-sm text-gray-700 hover:text-blue-600">{{ $upload->original_filename }}</span>
</a>
<button type="button"
onclick="if (confirm('Are you sure you want to delete this file?')) { @this.destroy({{ $upload->id }}) }"
wire:loading.attr="disabled"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">
Delete
</button>
<div wire:loading wire:target="destroy({{ $upload->id }})" class="text-gray-500 text-sm">
Deleting...
</div>
</li>
</ul>
@endforeach
</div>
@endif
</div>
+4
View File
@@ -1,6 +1,7 @@
<?php
use App\Http\Controllers\UploadController;
use App\Livewire\FileUpload;
use Illuminate\Support\Facades\Route;
@@ -11,3 +12,6 @@ Route::get('/', function () {
Route::get('/upload', [UploadController::class, 'index'])->name('upload.index');
Route::post('/upload', [UploadController::class, 'store'])->name('upload.store');
Route::delete('/upload/{upload}', [UploadController::class, 'destroy'])->name('upload.destroy');
Route::get('/upload-livewire', FileUpload::class)->name('upload-livewire');