100 lines
4.7 KiB
PHP
100 lines
4.7 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Enums\ProjectStatus;
|
||
use App\Http\Requests\StoreProjectRequest;
|
||
use App\Http\Requests\UpdateProjectRequest;
|
||
use App\Models\Project;
|
||
use App\Services\ProjectUrlNormalizer;
|
||
use Illuminate\Database\QueryException;
|
||
use Illuminate\Http\RedirectResponse;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Validation\ValidationException;
|
||
use Illuminate\View\View;
|
||
|
||
class ProjectController extends Controller
|
||
{
|
||
public function index(Request $request): View
|
||
{
|
||
$this->authorize('viewAny', Project::class);
|
||
$archived = $request->string('filter')->toString() === 'archived';
|
||
$projects = $request->user()->projects()
|
||
->where('status', $archived ? ProjectStatus::Archived : ProjectStatus::Active)
|
||
->withCount(['keywords' => fn ($query) => $query->active()])
|
||
->orderByDesc('id')->paginate(15)->withQueryString();
|
||
return view('projects.index', compact('projects', 'archived'));
|
||
}
|
||
|
||
public function create(): View
|
||
{
|
||
$this->authorize('create', Project::class);
|
||
return view('projects.create');
|
||
}
|
||
|
||
public function store(StoreProjectRequest $request, ProjectUrlNormalizer $normalizer): RedirectResponse
|
||
{
|
||
$normalized = $normalizer->normalize($request->string('website_url')->toString());
|
||
try {
|
||
$project = $request->user()->projects()->create([
|
||
'name' => $request->string('name')->trim()->toString(),
|
||
'domain' => $normalized->domain,
|
||
'url' => $normalized->url,
|
||
]);
|
||
} catch (QueryException $exception) {
|
||
$this->throwDuplicateValidation($exception);
|
||
}
|
||
return redirect()->route('projects.show', $project)->with('status', 'Proje oluşturuldu.');
|
||
}
|
||
|
||
public function show(Project $customerProject): View
|
||
{
|
||
$this->authorize('view', $customerProject);
|
||
$customerProject->load(['keywords' => fn ($q) => $q->active()->orderBy('phrase'), 'keywords.serpChecks' => fn ($q) => $q->where('status', 'completed')->latest('checked_at')->with(['results' => fn ($r) => $r->where('is_project_domain', true)->orderBy('position')])]);
|
||
$rows = $customerProject->keywords->map(function ($keyword) { $checks=$keyword->serpChecks->filter(fn($c)=>$c->results->isNotEmpty())->values();$current=$checks->get(0);$previous=$checks->get(1);$rank=$current?->results->min('position');$prior=$previous?->results->min('position');return ['current'=>$rank,'change'=>($rank&&$prior)?$prior-$rank:null,'checked_at'=>$current?->checked_at]; });
|
||
$measured=$rows->whereNotNull('current');
|
||
return view('projects.show', ['project'=>$customerProject,'summary'=>['keywords'=>$customerProject->keywords->count(),'last_check'=>$rows->max('checked_at'),'average'=>$measured->isNotEmpty()?round($measured->avg('current'),1):null,'top10'=>$measured->where('current','<=',10)->count(),'winners'=>$rows->where('change','>',0)->count(),'losers'=>$rows->where('change','<',0)->count()]]);
|
||
}
|
||
|
||
public function edit(Project $customerProject): View
|
||
{
|
||
$this->authorize('update', $customerProject);
|
||
return view('projects.edit', ['project' => $customerProject]);
|
||
}
|
||
|
||
public function update(UpdateProjectRequest $request, Project $customerProject, ProjectUrlNormalizer $normalizer): RedirectResponse
|
||
{
|
||
$normalized = $normalizer->normalize($request->string('website_url')->toString());
|
||
try {
|
||
$customerProject->update([
|
||
'name' => $request->string('name')->trim()->toString(),
|
||
'domain' => $normalized->domain,
|
||
'url' => $normalized->url,
|
||
]);
|
||
} catch (QueryException $exception) {
|
||
$this->throwDuplicateValidation($exception);
|
||
}
|
||
return redirect()->route('projects.show', $customerProject)->with('status', 'Proje güncellendi.');
|
||
}
|
||
|
||
public function archive(Project $customerProject): RedirectResponse
|
||
{
|
||
$this->authorize('archive', $customerProject);
|
||
$customerProject->archive();
|
||
return redirect()->route('projects.index')->with('status', 'Proje arşivlendi.');
|
||
}
|
||
|
||
public function restore(Project $customerProject): RedirectResponse
|
||
{
|
||
$this->authorize('restore', $customerProject);
|
||
$customerProject->restoreProject();
|
||
return redirect()->route('projects.show', $customerProject)->with('status', 'Proje yeniden etkinleştirildi.');
|
||
}
|
||
|
||
private function throwDuplicateValidation(QueryException $exception): never
|
||
{
|
||
if (! in_array((string) $exception->getCode(), ['23000', '19'], true)) throw $exception;
|
||
throw ValidationException::withMessages(['website_url' => 'Bu alan adı hesabınızda zaten kayıtlı.']);
|
||
}
|
||
}
|