menu

arrow_back How do I delete multiple files when deleting a post and information in the database at the same time?

by
1 vote
I'm working on an admin - CRUD for the site. Each post has a gallery of images, information about which is stored in a separate database table. The image files are loaded and stored in /storage/app/public.

There was some problem with deleting image files from the storage folder when deleting a post. There is no problem with deleting information about these files in the database, but I have some misunderstanding how to delete a group of files linked to the post when deleting the post.

Please help. Can you tell me the most rational way?

//Pechnik -  модель/таблица содержит данные поста
//Images - модель/таблица содержит информацию о изображениях галереи

// - метод ресурсного контролера для удаления поста
public function destroy($id)
{
Images::where('pechnik_id', $id)->delete();
Pechnik::find($id)->delete();
return redirect()->route('admin.index')->with('success', 'Информаця успешно удалена');
}

4 Comments

I guess so
use Illuminate\Support\Facades\Storage;
//

public function destroy($id)
{
$images = Images::where('pechnik_id', $id);
$path = $images->get('path');
Storage::delete($path);
$images->delete();
Pechnik::find($id)->delete();
return redirect()->route('admin.index')->with('success', 'Информаця успешно удалена');
}
VicTHOR , Thanks for the help! I'm sure it should work, But in my case, when deleting records from the database, image files are still not deleted, remain on the disk.

I assume this is because $path = $images->get('img');'returns a -c object with file information and a path like: storage/images/file.jpeg
In my case, these files actually have a different path: storage/app/public/images/file.jpeg

Probably, to successfully delete the files, you need to change the data received in the $path variable about the paths of the storage/images/ files to the real path /storage/app/public/images/. But how to do this? Go through the loop using str_replace() at each iteration? Do you think there is any more rational way to solve the problem?
Maxim Volkov How are these paths saved? It should be simple /images/file.jpeg and Storage should load the default drive, in which the app/public path is relative to the Storage folder
// /config/filesystems.php

return [
'default' => env('FILESYSTEM_DRIVER', 'public'),

'disks' => [

'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],

'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
It might help to specify the drive... Storage::disk('public')->delete($path); Well, by the way, the loop on the photos should be run and in the loop to delete, I did not consider it)
onDelete('cascade');
indicate in the migration, in the table of the intermediate

3 Answers

by
 
Best answer
0 votes
I will describe the solution to this problem. My problem with simultaneous deletion of gallery files when deleting a post is solved as follows:
//Pechnik -  модель/таблица содержит данные поста
//Images - модель/таблица содержит информацию о изображениях галереи

// - метод ресурсного контролера для удаления поста
public function destroy($id)
{
$images = Images::where('pechnik_id', $id); //получаю колекцию файлов галереи превязанных к ID поста p из таблицы Images
$pathImages = $images->get('img'); //получаю данные наименование и путь файлов галереи превязанных к ID поста
if (!$pathImages->isEmpty()){
foreach ($pathImages as $img){
$path = $img->img;
Storage::disk('public')->delete(str_replace('storage', '', $path)); //в цикле удаляю фалы галереи превязанных к ID поста
}
}
$images->delete(); // удаляю записи в таблице Images:: о файлах галереи
$pechnik= Pechnik::find($id); // получаю данные поста по ID из таблицы Pechnik::
Pechnik::find($id)->delete(); // удаляю запись в таблице Pechnik:: - данные поста
return redirect()->route('admin.index')->with('success', 'Информаця успешно удалена');
}
by
1 vote
Look at the side of events https://laravel.com/docs/8.x/eloquent#events

// В контроллере картинки не трогаем
public function destroy($id)
{
Pechnik::destroy($id);
// return ..
}

// Pechnik.php
protected static function booted()
{
// При удалении удаляем связаные картинки
static::deleted(function (Pechnik $pechnik) {
// Обновлено, т.к. mass delete не вызывает событие для модели Image
// $pechnik->images()->delete();
// Подход тоже не оптимальный, лишние запросы к БД. Есть что улучшать.
foreach ($pechnik->images as $image) {
$image->delete();
}
});
}

// Image.php
protected static function booted()
{
// Удаление картинки из БД - удаляем файл
static::deleted(function (Image $image) {
// Удаляем файл
});
}

8 Comments

$pechnik->images()->delete();

Hmmm, do you think this will cause events for the Image model?

Maxim Volkov Read the documentation, because you know people on the Internet give advice that they hardly know what they are advising.
The approach is also not optimal, unnecessary queries to the database. There is something to improve.

You should read the documentation, the section on greedy loading, so as not to make a bunch of selections.

To remove the only best option in terms of labor costs and speed benefits, because you need to remove the image, which belongs to the model images.
And to know the path to the picture to delete, you need to get this model.
vism , Well yes, you're right, the mass delete event is not called.
jazzus , Yes, you're right of course. I just wrote the shortest version, as an example of implementation. I can't copy the whole document here.
There are observers for that
vism I agree here, if there are 3 pictures then instead of 'optimizing' we get a pointless complication of the code.
vism , What does greedy loading have to do with it? SELECT will be 1. But DELETE in the updated version is called for each model. I wrote about these unnecessary queries. If you have a lot of pictures, it would be better to loop through them to delete the files, and then do the original $pechnik->images()->delete();
Aleksey , Yes, that's right, there's no greedy loading. So it's optimal.
I wrote about these unnecessary requests. If you have a large number of images, it would be better to loop through them to delete the files, and then do the original $pechnik->images()->delete();

This is a match savings in programmers' labor and future support.
Of course, you can assume that there will be 10,000 pictures, but it is better to solve and refactor when it happens, than to anticipate hundreds of different rare problems and program it all.
Otherwise the budget will be 100 times overblown and the development time.
by
0 votes
At the remove Images event we need to implement the removal of an image from the disk. with this approach it does not matter if we remove images of a certain model or random ones.

https://laravel.com/docs/8.x/eloquent#observers