问题描述
在Laravel 7中,我有一个任务管理应用程序。我可以上传任务(如果是博客,则为帖子)和图像。我有多个图像上传按预期方式工作。当需要删除一个任务时,该任务可以删除,但是图像保留在数据库和磁盘中,而磁盘和磁盘则公开在名为task-images的文件夹中。作为Laravel的新手,我正在努力解决这个问题。我试图更改filesystem.PHP
中的设置(我将用注释掉的代码发布该设置),但这并没有像我期望的那样更改位置。最后,我希望能够在删除帖子时删除多个图像,并单击单个图像上的“删除”,然后从数据库和磁盘中删除该图像。我正在为所有任务路由使用资源控制器。我不知道该如何处理,发现的教程并没有真正解决我的特定问题。任何帮助将不胜感激。预先谢谢你。
这是我在TaskController.PHP
的任务控制器
<?PHP
namespace App\Http\Controllers;
use App\Task;
use App\Image;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class TasksController extends Controller
{
public function index()
{
$tasks = Task::orderBy('created_at','desc')->paginate(10);
return view('/tasks')->with('tasks',$tasks);
}
public function create()
{
return view('tasks.create');
}
public function store(Request $request)
{
$this->validate($request,[
'task_name' => 'required','task_description' => 'required',]);
// Create Task
$user = Auth::user();
$task = new Task();
$data = $request->all();
$task->user_id = $user->id;
$task = $user->task()->create($data);
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ','-',$name);
$file->move('task-images',$name);
$task->image()->create(['name' => $name]);
$images = new Image;
$images->name = $name;
}
}
$task->task_name = $request->input('task_name');
$task->task_description = $request->input('task_description');
$task->task_priority = $request->input('task_priority');
$task->task_assigned_by = $request->input('task_assigned_by');
$task->task_assigned_to = $request->input('task_assigned_to');
$task->task_to_be_completed_date = $request->input('task_to_be_completed_date');
$task->task_notes = $request->input('task_notes');
$task->task_status = $request->task_status;
$task->save();
return redirect('/home')->with('success','Task Created');
}
public function edit($id)
{
$task = Task::find($id);
return view('tasks.edit',['task' => $task]);
}
public function update(Request $request,$id)
{
$this->validate($request,]);
$task = Task::find($id);
$task->task_name = $request->input('task_name');
$task->task_description = $request->input('task_description');
$task->task_priority = $request->input('task_priority');
$task->task_assigned_by = $request->input('task_assigned_by');
$task->task_assigned_to = $request->input('task_assigned_to');
$task->task_to_be_completed_date = $request->input('task_to_be_completed_date');
$task->task_notes = $request->input('task_notes');
$task->task_status = $request->input('task_status');
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ',$name);
$task->image()->create(['name' => $name]);
}
}
$task->update();
return redirect('/home')->with('success','Task Updated');
}
public function show($id)
{
$task = Task::find($id);
return view('tasks.show')->with('task',$task);
}
public function destroy($id)
{
$task = Task::findOrFail($id);
// $image = '/task-images/' . $task->image;
Storage::delete($task->image);
$task->delete();
return redirect('home')->with('success','Task Deleted');
}
}
'disks' => [
'local' => [
'driver' => 'local','root' => storage_path('app'),// 'root' => public_path('task-images'),],
...
在我自己的表演模板中,show.blade.PHP
已完成,以防代码冲突。
@extends('layouts.master')
@section('content')
<div class="container">
<a href="/home" class="btn bg-purple mb-4">Go Back</a>
<div class="card p-3">
<div class="row">
<div class="col-md-4 col-sm-12">
<h3>Task</h3>
<p>{{ $task->task_name }}</p>
<h3>Assigned On:</h3>
<p>{{ $task->created_at->format('m/d/Y') }}</p>
<h3>Assigned To:</h3>
<p>{{ $task->task_assigned_to }}</p>
</div>
<div class="col-md-4 col-sm-12">
<h3>Task Description</h3>
<p>{{ $task->task_description }}</p>
<h3>Priority</h3>
<p>{{ $task->task_priority }}</p>
<h3>Status</h3>
<p>{{ $task->task_status }}</p>
</div>
<div class="col-md-4 col-sm-12">
<h3>Test Environment Date:</h3>
<p>{{ $task->task_to_be_completed_date }}</p>
<h3>Notes</h3>
<p>{{ $task->task_notes }}</p>
<h3>Action</h3>
<div style="display: inline;">
<a href="/tasks/{{$task->id}}/edit" class="btn btn-sm btn-primary mr-2">
<i class="fa fa-edit"></i> Edit
</a>
</div>
<form style="display: inline;" action="/tasks/{{ $task->id }}" method="POST" class="">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm ml-1 mr-1">
<i class="fa fa-trash"></i> Delete
</button>
</form>
</div>
<div class="col-md-12">
<h5>Images</h5>
<hr />
<div class="row">
@if($task->image->count()>0)
@for($i=0; $i < count($images = $task->image()->get()); $i++)
<div class="col-lg-4 col-md-6 col-sm-12">
<a href="#" class="thumbnail" data-toggle="modal" data-target="#lightBox"><img class="w-50 mb-2" src="/task-images/{{ $images[$i]['name'] }}" alt=""></a>
<form style="display: inline;" action="/tasks/{{ $task->name }}" method="POST" class="">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm ml-1 mr-1">
<i class="fa fa-trash"></i> Delete
</button>
</form>
</div>
@endfor
@else
<p>No images found</p>
@endif
</div>
<br />
</div>
</div>
</div>
</div>
<!--Modal Start-->
<div id="lightBox" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog">
<button type="button" class="close hidden" data-dismiss="modal" aria-hidden="true">×</button>
<div class="modal-content">
<div class="modal-body">
<img class="w-100" src="" alt="" />
</div>
</div>
</div>
</div>
<!--Modal End-->
@endsection
@section('scripts')
<script>
$(document).ready(function() {
var $lightBox = $('#lightBox');
$('[data-target="#lightBox"]').on('click',function(event) {
var $img = $(this).find('img'),src = $img.attr('src'),alt = $img.attr('alt'),css = {
'maxWidth': $(window).width() - 100,'maxHeight': $(window).height() - 100
};
$lightBox.find('.close').addClass('hidden');
$lightBox.find('img').attr('src',src);
$lightBox.find('img').attr('alt',alt);
$lightBox.find('img').css(css);
});
$lightBox.on('shown.bs.modal',function (e) {
var $img = $lightBox.find('img');
$lightBox.find('.modal-dialog').css({'width': $img.width()});
$lightBox.find('.close').removeClass('hidden');
});
});
</script>
@endsection
<?PHP
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Image;
class Task extends Model
{
protected $fillable = [
'task_name','task_priority','task_assigned_to','task_assigned_by','task_description','task_to_be_completed_date','task_status','task_notes'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function image()
{
// return $this->hasMany('App\Image');
return $this->hasMany(Image::class);
}
}
最后是我的图像模型Image.PHP
<?PHP
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Task;
class Image extends Model
{
protected $fillable = [
'task_id','name',];
protected $uploads = '/task-images/';
public function getFileAttribute($image)
{
return $this->uploads . $image;
}
public function task()
{
// return $this->belongsTo('App\Task','task_id');
return $this->belongsTo(Task::class);
}
}
如果我缺少什么,请告诉我,以便我编辑问题。再次感谢您提前帮助我解决此问题。我整个星期都在为此挠头。干杯。
修改 在按照以下建议在模型中实现启动功能后,我收到一个错误,指出无效参数用于foreach。我跑了一个dd($ task);下图显示了结果。
最终编辑
下面的答案适合我的情况。我确实需要编辑一些东西来最终确定分辨率:
在Task.PHP
中,我将foreach更改为以下内容。
foreach($task->image ?: [] as $image)
我在模型中声明了图像而不是图像,这导致了问题。添加三元运算符也有助于代码不会引发任何错误。
在我的TasksController.PHP中,我使用相同的三元运算符更改了更新和创建函数,如下所示:
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files ?: [] as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ',$name);
$task->image()->create(['name' => $name]);
}
}
我希望这可以帮助其他遇到相同问题的人。感谢@GrumpyCrouton和@lagBox为解决此问题以及@ user3563950提供的帮助 没有他们,我还是会再挣扎几个星期。
解决方法
在您的App\Image
类上,使用以下命令实现启动功能;
use Illuminate\Support\Facades\Storage;
public static function boot() {
parent::boot();
self::deleting(function($image) {
Storage::delete(Storage::path($image->name));
});
}
还可以在App\Task
类中实现启动方法
use Illuminate\Support\Facades\Storage;
public static function boot() {
parent::boot();
self::deleting(function($task) {
foreach($task->images as $image) {
$image->delete();
}
});
}
现在在您的TaskController
上实现如下的destroy
方法;
public function destroy($id)
{
$task = Task::findOrFail($id);
$task->delete();
return redirect('home')->with('success','Task Deleted');
}
作为奖励,学习Laravel model binding可以减轻使用findOrFail()
查找实例的痛苦