Files
hub/app/Console/Commands/MigrateProductImagePaths.php
kelly 84e81272a5 feat: Product and inventory management system with media improvements
- Complete product and inventory management system
- Media storage service with proper path conventions
- Image handling with dynamic resizing
- Database migrations for inventory tracking
- Import tools for legacy data migration
- Documentation improvements

- InventoryItem, InventoryMovement, InventoryAlert models with hashid support
- Purchase order tracking on inventory alerts
- Inventory dashboard for sellers
- Stock level monitoring and notifications

- MediaStorageService enforcing consistent path conventions
- Image controller with dynamic resizing capabilities
- Migration tools for moving images to MinIO
- Proper slug-based paths (not IDs or hashids)

- ImportProductsFromRemote command
- ImportAlohaSales, ImportThunderBudBulk commands
- ExploreRemoteDatabase for schema inspection
- Legacy data migration utilities

- Product variations table
- Remote customer mappings
- Performance indexes for stats queries
- Social media fields for brands
- Module flags for businesses

- New migrations for inventory, hashids, performance indexes
- New services: MediaStorageService
- New middleware: EnsureBusinessHasModule, EnsureUserHasCapability
- Import commands for legacy data
- Inventory models and controllers
- Updated views for marketplace and seller areas
- Documentation reorganization (archived old docs)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 18:40:54 -07:00

127 lines
4.3 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\Product;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class MigrateProductImagePaths extends Command
{
protected $signature = 'media:migrate-product-images {--dry-run : Show what would be migrated without making changes}';
protected $description = 'Migrate product images from old path (products/{id}/) to correct path (brands/{brand}/products/{sku}/images/)';
public function handle()
{
$dryRun = $this->option('dry-run');
if ($dryRun) {
$this->warn('🔍 DRY RUN MODE - No changes will be made');
$this->newLine();
}
$this->info('🚀 Starting product image migration...');
$this->newLine();
// Get all products with image_path
$products = Product::whereNotNull('image_path')
->with('brand.business')
->get();
$this->info("Found {$products->count()} products with images");
$this->newLine();
$stats = [
'total' => $products->count(),
'migrated' => 0,
'skipped_correct_path' => 0,
'skipped_missing' => 0,
'failed' => 0,
];
$progressBar = $this->output->createProgressBar($products->count());
$progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %message%');
$progressBar->setMessage('Starting...');
foreach ($products as $product) {
$progressBar->setMessage("Product #{$product->id}: {$product->name}");
try {
// Check if already using correct path pattern
if (preg_match('#^businesses/[^/]+/brands/[^/]+/products/[^/]+/images/#', $product->image_path)) {
$stats['skipped_correct_path']++;
$progressBar->advance();
continue;
}
// Check if old file exists
if (! Storage::exists($product->image_path)) {
$stats['skipped_missing']++;
$progressBar->clear();
$this->warn(" ⚠️ Product #{$product->id} - Image missing at: {$product->image_path}");
$progressBar->display();
$progressBar->advance();
continue;
}
// Build new path
$filename = basename($product->image_path);
$businessSlug = $product->brand->business->slug ?? 'unknown';
$brandSlug = $product->brand->slug ?? 'unknown';
$productSku = $product->sku;
$newPath = "businesses/{$businessSlug}/brands/{$brandSlug}/products/{$productSku}/images/{$filename}";
$oldPath = $product->image_path;
if (! $dryRun) {
// Copy file to new location on MinIO
$contents = Storage::get($oldPath);
Storage::put($newPath, $contents);
// Update database
$product->image_path = $newPath;
$product->save();
// Delete old file
Storage::delete($oldPath);
}
$stats['migrated']++;
} catch (\Exception $e) {
$stats['failed']++;
$progressBar->clear();
$this->error(" ✗ Failed to migrate product #{$product->id}: {$e->getMessage()}");
$progressBar->display();
}
$progressBar->advance();
}
$progressBar->finish();
$this->newLine(2);
// Show summary
$this->info('📊 Migration Summary:');
$this->table(
['Metric', 'Count'],
[
['Total Products', $stats['total']],
['✓ Migrated', $stats['migrated']],
['→ Already Correct Path', $stats['skipped_correct_path']],
['⊘ Missing Files', $stats['skipped_missing']],
['✗ Failed', $stats['failed']],
]
);
if ($dryRun) {
$this->newLine();
$this->warn('This was a dry run. Run without --dry-run to actually migrate the images.');
}
return $stats['failed'] > 0 ? 1 : 0;
}
}