Laravel 7 从数据库和磁盘中删除阵列或单个图像 - 删除 post 但不从数据库或磁盘中删除关联图像
Laravel 7 Delete array or single image from db and disk - Deletes post but not associated images from db nor disk
在Laravel 7,我有一个任务管理应用程序。我可以上传任务(posts 如果它是一个博客)和图像。我有一个按预期工作的多图像上传。当需要删除任务时,任务删除得很好,但图像留在数据库和磁盘中 public 到一个名为 task-images 的文件夹中。作为 Laravel 的新手,我正在努力解决这个问题。我尝试更改 filesystem.php
中的设置(我将使用注释掉的代码 post ),但是并没有像我预期的那样更改位置。最后,我希望能够在删除 post 时删除多个图像,还可以在单个图像上单击删除并将其从数据库和磁盘中删除。我正在为我的所有任务路线使用资源控制器。我不知道该怎么做,而且我发现的教程并没有真正解决我的具体问题。任何帮助将不胜感激。提前谢谢你。
这是我在 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
class 上,使用以下命令实现启动功能;
use Illuminate\Support\Facades\Storage;
public static function boot() {
parent::boot();
self::deleting(function($image) {
Storage::delete(Storage::path($image->name));
});
}
同样实现App\Task
中的boot方法class
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()
查找实例的痛苦
在Laravel 7,我有一个任务管理应用程序。我可以上传任务(posts 如果它是一个博客)和图像。我有一个按预期工作的多图像上传。当需要删除任务时,任务删除得很好,但图像留在数据库和磁盘中 public 到一个名为 task-images 的文件夹中。作为 Laravel 的新手,我正在努力解决这个问题。我尝试更改 filesystem.php
中的设置(我将使用注释掉的代码 post ),但是并没有像我预期的那样更改位置。最后,我希望能够在删除 post 时删除多个图像,还可以在单个图像上单击删除并将其从数据库和磁盘中删除。我正在为我的所有任务路线使用资源控制器。我不知道该怎么做,而且我发现的教程并没有真正解决我的具体问题。任何帮助将不胜感激。提前谢谢你。
这是我在 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
class 上,使用以下命令实现启动功能;
use Illuminate\Support\Facades\Storage;
public static function boot() {
parent::boot();
self::deleting(function($image) {
Storage::delete(Storage::path($image->name));
});
}
同样实现App\Task
中的boot方法class
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()