EnsurePhotoThumbnails.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Console\Commands;
  4. use App\Models\File;
  5. use App\Services\FileService;
  6. use Illuminate\Console\Command;
  7. use Illuminate\Support\Facades\Storage;
  8. class EnsurePhotoThumbnails extends Command
  9. {
  10. protected $signature = 'photos:ensure-thumbnails
  11. {--overwrite : Пересоздать существующие миниатюры}
  12. {--dry-run : Только проверить, без создания миниатюр}';
  13. protected $description = 'Проверяет наличие миниатюр для загруженных фотографий и создаёт отсутствующие';
  14. public function handle(FileService $fileService): int
  15. {
  16. $dryRun = (bool) $this->option('dry-run');
  17. $overwrite = (bool) $this->option('overwrite');
  18. $checked = 0;
  19. $missing = 0;
  20. $created = 0;
  21. $overwriteCandidates = 0;
  22. $overwritten = 0;
  23. $skipped = 0;
  24. $failed = 0;
  25. $missingSources = 0;
  26. File::query()
  27. ->where(function ($query): void {
  28. $query->where('mime_type', 'like', 'image/%')
  29. ->orWhere('path', 'like', '%.jpg')
  30. ->orWhere('path', 'like', '%.jpeg')
  31. ->orWhere('path', 'like', '%.png')
  32. ->orWhere('path', 'like', '%.webp');
  33. })
  34. ->orderBy('id')
  35. ->chunkById(100, function ($files) use ($fileService, $dryRun, $overwrite, &$checked, &$missing, &$created, &$overwriteCandidates, &$overwritten, &$skipped, &$failed, &$missingSources): void {
  36. foreach ($files as $file) {
  37. if (!$fileService->isImageFile($file) || !$file->path || $fileService->isThumbnailPath($file->path)) {
  38. $skipped++;
  39. continue;
  40. }
  41. $checked++;
  42. if (!Storage::disk('public')->exists($file->path)) {
  43. $skipped++;
  44. $missingSources++;
  45. if ($this->getOutput()->isVerbose()) {
  46. $this->warn("Нет исходного файла: #{$file->id} {$file->path}");
  47. }
  48. continue;
  49. }
  50. $thumbnailPath = $fileService->thumbnailPath($file->path);
  51. if (Storage::disk('public')->exists($thumbnailPath)) {
  52. if (!$overwrite) {
  53. continue;
  54. }
  55. $overwriteCandidates++;
  56. if ($dryRun) {
  57. $this->line("Будет перезаписана миниатюра: #{$file->id} {$thumbnailPath}");
  58. continue;
  59. }
  60. if ($fileService->ensureThumbnail($file, true)) {
  61. $overwritten++;
  62. $this->line("Перезаписана миниатюра: #{$file->id} {$thumbnailPath}");
  63. } else {
  64. $failed++;
  65. $this->warn("Не удалось перезаписать миниатюру: #{$file->id} {$file->path}");
  66. }
  67. continue;
  68. }
  69. $missing++;
  70. if ($dryRun) {
  71. $this->line("Нет миниатюры: #{$file->id} {$thumbnailPath}");
  72. continue;
  73. }
  74. if ($fileService->ensureThumbnail($file)) {
  75. $created++;
  76. $this->line("Создана миниатюра: #{$file->id} {$thumbnailPath}");
  77. } else {
  78. $failed++;
  79. $this->warn("Не удалось создать миниатюру: #{$file->id} {$file->path}");
  80. }
  81. }
  82. });
  83. $this->info("Проверено фото: {$checked}. Нет миниатюр: {$missing}. Создано: {$created}. К перезаписи: {$overwriteCandidates}. Перезаписано: {$overwritten}. Пропущено: {$skipped}. Нет исходников: {$missingSources}. Ошибок: {$failed}.");
  84. return $failed > 0 ? self::FAILURE : self::SUCCESS;
  85. }
  86. }