Files
Laravel/app/Http/Controllers/ResumeBuilderController.php
David Melendez e25d53d054 init commit
2026-01-14 22:38:44 +01:00

357 lines
11 KiB
PHP

<?php
/**
* Resume Builder Controller
* Professional Resume Builder - Resume Creation and Management
*
* @author David Valera Melendez <david@valera-melendez.de>
* @created 2025-08-08
* @location Made in Germany 🇩🇪
*/
namespace App\Http\Controllers;
use App\Http\Requests\Resume\StoreResumeRequest;
use App\Http\Requests\Resume\UpdateResumeRequest;
use App\Models\Resume;
use App\Interfaces\ResumeRepositoryInterface;
use App\Interfaces\UserRepositoryInterface;
use App\Services\ResumeService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
/**
* Resume Builder Controller
* Handles resume creation, editing, and management with repository pattern
*/
class ResumeBuilderController extends Controller
{
/**
* Resume repository instance
*/
protected ResumeRepositoryInterface $resumeRepository;
/**
* User repository instance
*/
protected UserRepositoryInterface $userRepository;
/**
* ResumeService instance
*/
protected ResumeService $resumeService;
/**
* Create a new controller instance with dependency injection
*/
public function __construct(
ResumeRepositoryInterface $resumeRepository,
UserRepositoryInterface $userRepository,
ResumeService $resumeService
) {
$this->resumeRepository = $resumeRepository;
$this->userRepository = $userRepository;
$this->resumeService = $resumeService;
$this->middleware('auth');
}
/**
* Display a listing of user's resumes
*/
public function index(Request $request): View
{
$userId = Auth::id();
// Get paginated resumes using repository
$resumes = $this->resumeRepository->getPaginatedUserResumes($userId, 12);
// Get resume statistics using repository
$resumeStats = $this->resumeRepository->getResumeStatistics($userId);
return view('resume-builder.index', [
'title' => 'My Resumes - Resume Builder',
'resumes' => $resumes,
'resumeStats' => $resumeStats
]);
}
/**
* Show the form for creating a new resume
*/
public function create(): View
{
$userId = Auth::id();
// Check if user can create more resumes
if (!$this->resumeRepository->canUserCreateMoreResumes($userId, 10)) {
return redirect()->route('resume-builder.index')
->with('error', 'You have reached the maximum number of resumes allowed.');
}
$templates = $this->resumeService->getAvailableTemplates();
return view('resume-builder.create', [
'title' => 'Create New Resume',
'templates' => $templates
]);
}
/**
* Store a newly created resume
*/
public function store(StoreResumeRequest $request): RedirectResponse
{
try {
$userId = Auth::id();
// Check if user can create more resumes
if (!$this->resumeRepository->canUserCreateMoreResumes($userId, 10)) {
return back()->withErrors([
'title' => 'You have reached the maximum number of resumes allowed.'
])->withInput();
}
$resumeData = $request->validated();
$resumeData['user_id'] = $userId;
// Create resume using repository
$resume = $this->resumeRepository->create($resumeData);
// Update completion percentage
$this->resumeRepository->updateCompletionPercentage($resume->id);
logger()->info('Resume created', [
'user_id' => $userId,
'resume_id' => $resume->id,
'title' => $resume->title
]);
return redirect()->route('resume-builder.edit', $resume)
->with('success', 'Resume created successfully! Start building your professional CV.');
} catch (\Exception $e) {
logger()->error('Resume creation error', [
'error' => $e->getMessage(),
'user_id' => Auth::id()
]);
return back()->withErrors([
'title' => 'Unable to create resume. Please try again.'
])->withInput();
}
}
/**
* Show the form for editing the specified resume
*/
public function edit(Resume $resume): View
{
$this->authorize('update', $resume);
return view('resume-builder.edit', [
'title' => 'Edit Resume - ' . $resume->title,
'resume' => $resume,
'templates' => $this->resumeService->getAvailableTemplates()
]);
}
/**
* Update the specified resume
*/
public function update(UpdateResumeRequest $request, Resume $resume): RedirectResponse
{
$this->authorize('update', $resume);
try {
$resumeData = $request->validated();
// Update resume using repository
$this->resumeRepository->update($resume->id, $resumeData);
// Update completion percentage
$this->resumeRepository->updateCompletionPercentage($resume->id);
logger()->info('Resume updated', [
'user_id' => Auth::id(),
'resume_id' => $resume->id
]);
return back()->with('success', 'Resume updated successfully!');
} catch (\Exception $e) {
logger()->error('Resume update error', [
'error' => $e->getMessage(),
'user_id' => Auth::id(),
'resume_id' => $resume->id
]);
return back()->withErrors([
'title' => 'Unable to update resume. Please try again.'
])->withInput();
}
}
/**
* Display the specified resume preview
*/
public function preview(Resume $resume): View
{
$this->authorize('view', $resume);
// Increment view count using repository
$this->resumeRepository->incrementViewCount($resume->id);
return view('resume-builder.preview', [
'title' => 'Preview - ' . $resume->title,
'resume' => $resume
]);
}
/**
* Remove the specified resume
*/
public function destroy(Resume $resume): RedirectResponse
{
$this->authorize('delete', $resume);
try {
// Delete resume using repository
$this->resumeRepository->delete($resume->id);
logger()->info('Resume deleted', [
'user_id' => Auth::id(),
'resume_id' => $resume->id,
'title' => $resume->title
]);
return redirect()->route('resume-builder.index')
->with('success', 'Resume deleted successfully.');
} catch (\Exception $e) {
logger()->error('Resume deletion error', [
'error' => $e->getMessage(),
'user_id' => Auth::id(),
'resume_id' => $resume->id
]);
return back()->withErrors([
'error' => 'Unable to delete resume. Please try again.'
]);
}
}
/**
* Download resume as PDF
*/
public function downloadPdf(Resume $resume)
{
$this->authorize('view', $resume);
try {
// Increment download count using repository
$this->resumeRepository->incrementDownloadCount($resume->id);
return $this->resumeService->generatePdf($resume);
} catch (\Exception $e) {
logger()->error('PDF generation error', [
'error' => $e->getMessage(),
'user_id' => Auth::id(),
'resume_id' => $resume->id
]);
return back()->withErrors([
'error' => 'Unable to generate PDF. Please try again.'
]);
}
}
/**
* Duplicate an existing resume
*/
public function duplicate(Resume $resume): RedirectResponse
{
$this->authorize('view', $resume);
try {
$userId = Auth::id();
// Check if user can create more resumes
if (!$this->resumeRepository->canUserCreateMoreResumes($userId, 10)) {
return back()->withErrors([
'error' => 'You have reached the maximum number of resumes allowed.'
]);
}
$newTitle = $resume->title . ' (Copy)';
$duplicatedResume = $this->resumeRepository->duplicateResume($resume->id, $userId, $newTitle);
logger()->info('Resume duplicated', [
'user_id' => $userId,
'original_resume_id' => $resume->id,
'new_resume_id' => $duplicatedResume->id
]);
return redirect()->route('resume-builder.edit', $duplicatedResume)
->with('success', 'Resume duplicated successfully!');
} catch (\Exception $e) {
logger()->error('Resume duplication error', [
'error' => $e->getMessage(),
'user_id' => Auth::id(),
'resume_id' => $resume->id
]);
return back()->withErrors([
'error' => 'Unable to duplicate resume. Please try again.'
]);
}
}
/**
* Search user's resumes
*/
public function search(Request $request): \Illuminate\Http\JsonResponse
{
$query = $request->input('query', '');
$userId = Auth::id();
if (empty($query)) {
return response()->json([]);
}
$resumes = $this->resumeRepository
->getUserResumes($userId)
->filter(function ($resume) use ($query) {
return stripos($resume->title, $query) !== false ||
stripos($resume->description, $query) !== false;
})
->take(10)
->values();
return response()->json($resumes);
}
/**
* Get resume analytics
*/
public function analytics(Resume $resume): \Illuminate\Http\JsonResponse
{
$this->authorize('view', $resume);
$analytics = [
'view_count' => $resume->view_count,
'download_count' => $resume->download_count,
'completion_percentage' => $resume->completion_percentage,
'last_viewed_at' => $resume->last_viewed_at,
'last_downloaded_at' => $resume->last_downloaded_at,
'created_at' => $resume->created_at,
'updated_at' => $resume->updated_at,
];
return response()->json($analytics);
}
}