Files
project-manager/src/Http/Controllers/ProjectController.php
T

116 lines
3.7 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use App\Exception\ApiException;
use App\Repository\CardStatusRepository;
use App\Repository\ProjectRepository;
use App\Support\Validator;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* CRUD for the authenticated user's projects. A project is only ever visible to
* its owner; anything else responds 404.
*/
final class ProjectController extends ProjectScopedController
{
private const TITLE_MAX = 255;
public function __construct(
ProjectRepository $projects,
private readonly CardStatusRepository $statuses,
/** Maximum number of projects a single owner may create. 0 means unlimited. */
private readonly int $maxProjectsPerOwner,
) {
parent::__construct($projects);
}
/**
* GET /api/projects
*/
public function index(Request $request, Response $response): Response
{
$projects = $this->projects->allForOwner($this->user($request)['id']);
return $this->json($response, ['projects' => array_map($this->present(...), $projects)]);
}
/**
* POST /api/projects
*/
public function store(Request $request, Response $response): Response
{
$ownerId = $this->user($request)['id'];
$validator = new Validator($this->body($request));
$title = $validator->requiredString('title', self::TITLE_MAX);
$validator->assert();
if ($this->maxProjectsPerOwner > 0 && $this->projects->countForOwner($ownerId) >= $this->maxProjectsPerOwner) {
throw new ApiException(
sprintf('You have reached the maximum of %d projects.', $this->maxProjectsPerOwner),
409,
);
}
$project = $this->projects->create($ownerId, $title);
$this->statuses->seedDefaults($project['id']);
return $this->json($response, ['project' => $this->present($project)], 201);
}
/**
* GET /api/projects/{projectId}
*/
public function show(Request $request, Response $response, array $args): Response
{
return $this->json($response, ['project' => $this->present($this->requireOwnedProject($request, $args))]);
}
/**
* PATCH /api/projects/{projectId}
*/
public function update(Request $request, Response $response, array $args): Response
{
$project = $this->requireOwnedProject($request, $args);
$validator = new Validator($this->body($request));
$title = $validator->requiredString('title', self::TITLE_MAX);
$validator->assert();
$updated = $this->projects->update($project['id'], $project['owner_id'], $title);
return $this->json($response, ['project' => $this->present($updated)]);
}
/**
* DELETE /api/projects/{projectId}
*/
public function destroy(Request $request, Response $response, array $args): Response
{
$this->projects->delete($this->requireOwnedProject($request, $args)['id']);
return $response->withStatus(204);
}
/**
* @param array{id: int, owner_id: int, title: string, card_count: int, completed_count: int, created_at: string, updated_at: string} $project
* @return array<string, mixed>
*/
private function present(array $project): array
{
return [
'id' => $project['id'],
'title' => $project['title'],
'owner_id' => $project['owner_id'],
'card_count' => $project['card_count'],
'completed_count' => $project['completed_count'],
'created_at' => $project['created_at'],
'updated_at' => $project['updated_at'],
];
}
}