php - Laravel 7 从数据库和磁盘中删除数组或单个图像 - 从数据库或磁盘中删除帖子但不关联图像
问题描述
在 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_name' => 'required',
'task_description' => 'required',
]);
$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);
$file->move('task-images', $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');
}
}
filesystem.php(只是磁盘部分)
'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
在我的任务模型中Task.php
,我有:
<?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);
$file->move('task-images', $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
还要在类中实现boot方法
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 模型绑定以减轻使用查找实例的痛苦findOrFail()
推荐阅读
- ios - iOS:Jpeg 压缩增加了图像的大小(Swift)
- discord.js - Discord.js:如何在消息中发送 .txt 文件的内容?
- erlang - 无法在 MAC OSX Mojave 上安装 asdf erlang
- node.js - html-pdf:无法加载 PhantomJS 模块。使用 aws ec2 时,您必须使用“options.phantomPath”设置 PhantomJS 二进制文件的路径
- c# - Azure 数字孪生 API 无法使用教程中所述的 DefaultAzureCredential 身份验证方法
- java - 大型 jpa 删除的最佳垃圾收集器
- google-cloud-platform - 通过 Terraform 配置没有外部 IP 的 GCP VM 实例
- angular - 角度 e2e 测试不必要地等待
- php - 在新选项卡上打开图像
- javascript - 如何通过按帐户/ID/类别分组来对值求和?