183 lines
6.3 KiB
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(),
|
|
];
|
|
}
|
|
}
|