Files
WebAPP/app/Http/Controllers/Admin/ListGeneratorController.php
Rhino 2e24a40d68 Stand: SMTP-Test, Admin-Mail-Tab, Notifiable-Fix, Lazy-Quill
- Fix: Notifiable-Trait zum User-Model hinzugefuegt (behebt notify()-500er)
- Installer: SMTP-Verbindungstest mit EsmtpTransport + Ueberspringen-Link
- Admin: Neuer E-Mail-Tab mit SMTP-Konfiguration + Verbindungstest
- Admin: Lazy Quill-Initialisierung (nur sichtbare Locale wird geladen)
- Uebersetzungen: 17 neue Mail-Keys in allen 6 Sprachen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:30:37 +01:00

256 lines
8.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Models\File;
use App\Models\FileCategory;
use App\Models\Player;
use App\Models\Team;
use App\Models\User;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\View\View;
class ListGeneratorController extends Controller
{
public function create(): View
{
$teams = Team::where('is_active', true)->orderBy('name')->get();
return view('admin.list-generator.create', compact('teams'));
}
public function store(Request $request): View
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'subtitle' => 'nullable|string|max:255',
'notes' => 'nullable|string|max:2000',
'team_id' => 'nullable|exists:teams,id',
'source' => 'required|in:players,parents,freetext',
'freetext_rows' => 'nullable|required_if:source,freetext|string|max:50000',
'columns' => 'nullable|array',
'custom_columns' => 'nullable|array',
'custom_columns.*' => 'string|max:100',
]);
$columns = $this->buildColumns($validated);
$rows = $this->buildRows($validated, $columns);
// Auto-detect orientation and font size for single-page PDF
$colCount = count($columns);
$rowCount = count($rows);
$orientation = $colCount > 4 ? 'landscape' : 'portrait';
// Font size calculation for single-page fit
$fontSize = 10;
if ($rowCount > 35) {
$fontSize = 7;
} elseif ($rowCount > 25) {
$fontSize = 8;
} elseif ($rowCount > 15) {
$fontSize = 9;
}
$viewData = [
'title' => $validated['title'],
'subtitle' => $validated['subtitle'] ?? null,
'notes' => $validated['notes'] ?? null,
'columns' => $columns,
'rows' => $rows,
'generatedAt' => now(),
'orientation' => $orientation,
'fontSize' => $fontSize,
];
// Generate PDF
$pdf = Pdf::loadView('admin.list-generator.document', $viewData)
->setPaper('a4', $orientation);
$pdfContent = $pdf->output();
// Save to file library
$category = FileCategory::where('slug', 'allgemein')->firstOrFail();
$storedName = Str::uuid() . '.pdf';
Storage::disk('local')->put('files/' . $storedName, $pdfContent);
$file = new File([
'file_category_id' => $category->id,
'original_name' => Str::slug($validated['title']) . '.pdf',
'mime_type' => 'application/pdf',
'size' => strlen($pdfContent),
]);
$file->stored_name = $storedName;
$file->disk = 'private';
$file->uploaded_by = auth()->id();
$file->save();
ActivityLog::log('created', __('admin.log_list_generated', ['title' => $validated['title']]), 'File', $file->id);
return view('admin.list-generator.result', [
'title' => $validated['title'],
'subtitle' => $validated['subtitle'] ?? null,
'notes' => $validated['notes'] ?? null,
'columns' => $columns,
'rows' => $rows,
'file' => $file,
]);
}
private function buildColumns(array $data): array
{
$columns = ['name' => __('ui.name')];
$selected = $data['columns'] ?? [];
$playerColumns = [
'team' => __('admin.nav_teams'),
'jersey_number' => __('admin.jersey_number'),
'birth_year' => __('admin.birth_year'),
'parents' => __('admin.parents'),
'photo_permission' => __('admin.photo_permission'),
];
$parentColumns = [
'team' => __('admin.nav_teams'),
'email' => __('ui.email'),
'phone' => __('admin.phone'),
'children' => __('admin.children'),
];
$available = match ($data['source']) {
'players' => $playerColumns,
'parents' => $parentColumns,
default => [],
};
foreach ($selected as $col) {
if (isset($available[$col])) {
$columns[$col] = $available[$col];
}
}
foreach (($data['custom_columns'] ?? []) as $i => $header) {
$header = trim($header);
if ($header !== '') {
$columns['custom_' . $i] = $header;
}
}
return $columns;
}
private function buildRows(array $data, array $columns): array
{
if ($data['source'] === 'freetext') {
return $this->buildFreetextRows($data);
}
if ($data['source'] === 'players') {
return $this->buildPlayerRows($data, $columns);
}
return $this->buildParentRows($data, $columns);
}
private function buildPlayerRows(array $data, array $columns): array
{
$query = Player::with(['team', 'parents'])->where('is_active', true);
if (!empty($data['team_id'])) {
$query->where('team_id', $data['team_id']);
}
$query->orderBy('last_name')->orderBy('first_name');
$players = $query->get();
$rows = [];
foreach ($players as $player) {
$row = ['name' => $player->full_name];
if (isset($columns['team'])) {
$row['team'] = $player->team->name ?? '';
}
if (isset($columns['jersey_number'])) {
$row['jersey_number'] = $player->jersey_number ?? '';
}
if (isset($columns['birth_year'])) {
$row['birth_year'] = $player->birth_year ?? '';
}
if (isset($columns['parents'])) {
$row['parents'] = $player->parents->map(fn ($p) => $p->name)->implode(', ') ?: '';
}
if (isset($columns['photo_permission'])) {
$row['photo_permission'] = $player->photo_permission ? __('ui.yes') : __('ui.no');
}
foreach ($columns as $key => $header) {
if (str_starts_with($key, 'custom_')) {
$row[$key] = '';
}
}
$rows[] = $row;
}
return $rows;
}
private function buildParentRows(array $data, array $columns): array
{
$query = User::with('children.team')->where('is_active', true);
if (!empty($data['team_id'])) {
$query->whereHas('children', fn ($q) => $q->where('team_id', $data['team_id']));
}
$query->orderBy('name');
$users = $query->get();
$rows = [];
foreach ($users as $user) {
$row = ['name' => $user->name];
if (isset($columns['team'])) {
$teamNames = $user->children->pluck('team.name')->filter()->unique()->implode(', ');
$row['team'] = $teamNames ?: '';
}
if (isset($columns['email'])) {
$row['email'] = $user->email;
}
if (isset($columns['phone'])) {
$row['phone'] = $user->phone ?? '';
}
if (isset($columns['children'])) {
$row['children'] = $user->children->map(fn ($c) => $c->first_name)->implode(', ') ?: '';
}
foreach ($columns as $key => $header) {
if (str_starts_with($key, 'custom_')) {
$row[$key] = '';
}
}
$rows[] = $row;
}
return $rows;
}
private function buildFreetextRows(array $data): array
{
$lines = array_filter(
array_map('trim', explode("\n", $data['freetext_rows'] ?? '')),
fn ($line) => $line !== ''
);
// Maximum 200 Zeilen — DoS-Schutz (V10)
$lines = array_slice($lines, 0, 200);
return array_map(fn ($line) => ['name' => $line], array_values($lines));
}
}