dstpabuaran.com/app/DataFixes/FixRawMaterialMediaKeys.php

183 lines
6.3 KiB
PHP

<?php
namespace App\DataFixes;
use App\Models\RawMaterialPrice;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class FixRawMaterialMediaKeys extends BaseDataFix
{
public function key(): string
{
return 'raw-material-media-keys';
}
public function description(): string
{
return 'Fix s3_key & buat media record untuk RawMaterialPrice';
}
public function fix(): array
{
$disk = Storage::disk('s3');
$client = $disk->getClient();
$bucket = config('filesystems.disks.s3.bucket');
$this->info('Loading S3 file list...');
$s3Files = [];
$continuationToken = null;
do {
$params = [
'Bucket' => $bucket,
'Prefix' => 'raw-material/images/',
];
if ($continuationToken) {
$params['ContinuationToken'] = $continuationToken;
}
$result = $client->listObjectsV2($params);
foreach ($result['Contents'] ?? [] as $obj) {
$key = $obj['Key'];
if (str_contains($key, '/conversions/')) {
continue;
}
if (preg_match('#raw-material/images/\d{4}-\d{2}-\d{2}/(\d+)/[^/]+$#', $key, $m)) {
$s3Files[(int) $m[1]] = $key;
}
}
$continuationToken = $result['NextContinuationToken'] ?? null;
} while ($continuationToken);
$this->info('Found ' . count($s3Files) . ' files in S3.');
// Build filename → s3_key map for matching
$s3ByKey = [];
foreach ($s3Files as $modelId => $s3Key) {
$fileName = pathinfo($s3Key, PATHINFO_BASENAME);
$s3ByKey[$modelId][$fileName] = $s3Key;
}
$allPrices = RawMaterialPrice::all(['id', 'variant']);
$existingMediaAll = DB::table('media')
->where('model_type', 'App\\Models\\RawMaterialPrice')
->where('collection_name', 'images')
->get(['id', 'model_id', 'file_name', 'custom_properties']);
$mediaByModel = [];
foreach ($existingMediaAll as $m) {
$props = json_decode($m->custom_properties, true);
if (isset($props['module']) && $props['module'] === 'owner_verification_request') {
continue;
}
$mediaByModel[$m->model_id][] = $m;
}
$fixed = 0;
$fixedPath = 0;
$skipped = 0;
$noFile = 0;
$details = [];
foreach ($allPrices as $price) {
if (isset($mediaByModel[$price->id])) {
$allGood = true;
foreach ($mediaByModel[$price->id] as $media) {
$currentKey = data_get(json_decode($media->custom_properties, true), 's3_key');
if ($currentKey && str_starts_with($currentKey, 'raw-material/images/')) {
continue;
}
// Match by filename first, fallback to model_id
$correctKey = null;
if (isset($s3ByKey[$price->id][$media->file_name])) {
$correctKey = $s3ByKey[$price->id][$media->file_name];
} elseif (isset($s3Files[$price->id])) {
$correctKey = $s3Files[$price->id];
}
if ($correctKey) {
DB::table('media')
->where('id', $media->id)
->update([
'custom_properties' => DB::raw("'".addslashes(json_encode(['s3_key' => $correctKey]))."'"),
'updated_at' => now(),
]);
$details[] = [
'Price ID' => $price->id,
'Variant' => $price->variant,
'Action' => 'FIXED PATH',
'S3 Key' => $correctKey,
];
$fixedPath++;
$allGood = false;
}
}
if ($allGood) {
$skipped++;
}
continue;
}
if (! isset($s3Files[$price->id])) {
$noFile++;
continue;
}
$s3Key = $s3Files[$price->id];
$fileName = pathinfo($s3Key, PATHINFO_BASENAME);
DB::table('media')->insert([
'model_type' => 'App\\Models\\RawMaterialPrice',
'model_id' => $price->id,
'uuid' => Str::uuid()->toString(),
'collection_name' => 'images',
'name' => pathinfo($s3Key, PATHINFO_FILENAME),
'file_name' => $fileName,
'mime_type' => 'image/jpeg',
'disk' => 's3',
'conversions_disk' => 's3',
'size' => 0,
'manipulations' => '[]',
'custom_properties' => json_encode(['s3_key' => $s3Key]),
'generated_conversions' => '[]',
'responsive_images' => '[]',
'order_column' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
$details[] = [
'Price ID' => $price->id,
'Variant' => $price->variant,
'Action' => 'CREATED',
'S3 Key' => $s3Key,
];
$fixed++;
}
if (! empty($details)) {
$this->command->newLine();
$this->command->table(['Price ID', 'Variant', 'Action', 'S3 Key'], $details);
}
$this->info("Created new media: {$fixed}");
$this->info("Fixed s3_key path: {$fixedPath}");
$this->info("Skipped (already correct): {$skipped}");
$this->info("Skipped (no file in S3): {$noFile}");
return [
'fixed' => $fixed + $fixedPath,
'skipped' => $skipped,
'total' => $allPrices->count(),
];
}
}