Files
Javier Braña 78d1dbf45a feat: Phase 1 - Redis config, Dashboard cache, Report cache, N+1 fixes, observers
- Add predis/predis for Redis support
- Configure cache/queue defaults to redis in config + .env.example
- Create DashboardController with 60s cache for dashboard queries
- Add cache (5min) to ReportController::generate() and preview()
- Add FeatureObserver, InspectionObserver, IssueObserver for cache invalidation
- Fix N+1 in ProjectMap (eager load template, images), TaskManager (subtasks.parentTask)
- Register observers in AppServiceProvider

Tests: 101 passing (319 assertions)
2026-08-31 09:44:33 +02:00

98 lines
2.7 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\DTO\ReportFilters;
use App\Exports\ProjectReportExport;
use App\Models\Project;
use App\Services\ReportGenerator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Maatwebsite\Excel\Facades\Excel;
class ReportController extends Controller
{
/**
* Show report builder for a project
*/
public function show(Project $project)
{
$this->authorizeProjectAccess($project);
return view('reports.builder', [
'project' => $project,
]);
}
/**
* Generate report (HTML preview or download)
*/
public function generate(Request $request, Project $project)
{
$this->authorizeProjectAccess($project);
$filters = ReportFilters::fromRequest($request->all());
$cacheKey = "report:{$project->id}:".md5(json_encode($filters->toArray()));
$data = Cache::remember($cacheKey, 300, function () use ($project, $filters) {
$generator = new ReportGenerator($project, $filters);
return $generator->generate();
});
$format = $filters->format;
if ($format === 'excel') {
return $this->downloadExcel($project, $filters, $data);
}
// HTML format (default) - render printable view
return view('reports.complete', $data);
}
/**
* Preview partial (AJAX)
*/
public function preview(Request $request, Project $project)
{
$this->authorizeProjectAccess($project);
$filters = ReportFilters::fromRequest($request->all());
$cacheKey = "report:{$project->id}:".md5(json_encode($filters->toArray()));
$data = Cache::remember($cacheKey, 300, function () use ($project, $filters) {
$generator = new ReportGenerator($project, $filters);
return $generator->generate();
});
return view('reports.partials._preview', $data);
}
/**
* Download Excel export
*/
protected function downloadExcel(Project $project, ReportFilters $filters, array $data)
{
$export = new ProjectReportExport($project, $filters, $data);
$filename = 'informe_'.$project->name.'_'.now()->format('Ymd_His').'.xlsx';
return Excel::download($export, $filename);
}
/**
* Authorize access to project
*/
protected function authorizeProjectAccess(Project $project): void
{
$user = Auth::user();
if ($user->can('manage all')) {
return;
}
if (! $project->users()->where('user_id', $user->id)->exists()) {
abort(403, 'No tienes acceso a este proyecto.');
}
}
}