schema([ FileUpload::make('file') ->label('CSV file') ->acceptedFileTypes(['text/csv', 'text/plain']) ->directory('imports') ->required(), ]); } public function doImport(): void { $this->validate(); $path = $this->form->getState()['file'] ?? null; if (!$path || !Storage::disk('public')->exists($path)) { Notification::make()->danger()->title('File not found')->send(); return; } $fullPath = Storage::disk('public')->path($path); [$ok, $fail] = $this->importEmotionsCsv($fullPath); Notification::make() ->success() ->title("Imported {$ok} rows") ->body($fail ? "{$fail} failed" : null) ->send(); } private function importEmotionsCsv(string $file): array { $handle = fopen($file, 'r'); if (!$handle) { return [0, 0]; } $ok = 0; $fail = 0; $headers = fgetcsv($handle, 0, ','); if (!$headers) { return [0, 0]; } $map = array_flip($headers); while (($row = fgetcsv($handle, 0, ',')) !== false) { try { DB::transaction(function () use ($row, $map, &$ok) { $nameDe = trim($row[$map['name_de']] ?? ''); $nameEn = trim($row[$map['name_en']] ?? ''); if (empty($nameDe) && empty($nameEn)) { throw new \Exception('Name is required.'); } $emotion = Emotion::create([ 'name' => ['de' => $nameDe, 'en' => $nameEn], 'icon' => $row[$map['icon']] ?? null, 'color' => $row[$map['color']] ?? null, 'description' => [ 'de' => $row[$map['description_de']] ?? null, 'en' => $row[$map['description_en']] ?? null, ], 'sort_order' => (int)($row[$map['sort_order']] ?? 0), 'is_active' => (int)($row[$map['is_active']] ?? 1) ? 1 : 0, ]); $eventTypes = $row[$map['event_types']] ?? ''; if ($eventTypes) { $slugs = array_filter(array_map('trim', explode('|', $eventTypes))); if ($slugs) { $eventTypeIds = DB::table('event_types')->whereIn('slug', $slugs)->pluck('id')->all(); $emotion->eventTypes()->attach($eventTypeIds); } } $ok++; }); } catch (\Throwable $e) { $fail++; } } fclose($handle); return [$ok, $fail]; } }