Drop the unused project description field entirely
It never got a UI home on the frontend -- removed from ProjectView a few sessions back and never restored anywhere -- so it was a fully live field (validated, stored, returned by the API, covered by tests) with no consumer. - Migration 011: ALTER TABLE projects DROP COLUMN description. - ProjectRepository: description dropped from ProjectRow, SELECT, create() and update() -- update() is now just a rename (string, not a $fields array; there was never more than one editable field once this left). - ProjectController: store()/update() no longer accept or validate it; update() drops the "provide at least one of title, description" branch, since title is unconditionally the only field now. - Frontend Project type, root README's API docs and curl example. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,6 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
final class ProjectController extends ProjectScopedController
|
||||
{
|
||||
private const TITLE_MAX = 255;
|
||||
private const DESCRIPTION_MAX = 2000;
|
||||
private const MAX_PROJECTS_PER_OWNER = 100;
|
||||
|
||||
public function __construct(
|
||||
@@ -47,7 +46,6 @@ final class ProjectController extends ProjectScopedController
|
||||
|
||||
$validator = new Validator($this->body($request));
|
||||
$title = $validator->requiredString('title', self::TITLE_MAX);
|
||||
$description = $validator->optionalString('description', self::DESCRIPTION_MAX) ?? '';
|
||||
$validator->assert();
|
||||
|
||||
if ($this->projects->countForOwner($ownerId) >= self::MAX_PROJECTS_PER_OWNER) {
|
||||
@@ -57,7 +55,7 @@ final class ProjectController extends ProjectScopedController
|
||||
);
|
||||
}
|
||||
|
||||
$project = $this->projects->create($ownerId, $title, $description);
|
||||
$project = $this->projects->create($ownerId, $title);
|
||||
$this->statuses->seedDefaults($project['id']);
|
||||
|
||||
return $this->json($response, ['project' => $this->present($project)], 201);
|
||||
@@ -79,19 +77,10 @@ final class ProjectController extends ProjectScopedController
|
||||
$project = $this->requireOwnedProject($request, $args);
|
||||
|
||||
$validator = new Validator($this->body($request));
|
||||
$fields = [];
|
||||
if ($validator->has('title')) {
|
||||
$fields['title'] = $validator->requiredString('title', self::TITLE_MAX);
|
||||
}
|
||||
if ($validator->has('description')) {
|
||||
$fields['description'] = $validator->optionalString('description', self::DESCRIPTION_MAX) ?? '';
|
||||
}
|
||||
if ($fields === [] && !$validator->failed()) {
|
||||
$validator->add('title', 'Provide at least one of: title, description.');
|
||||
}
|
||||
$title = $validator->requiredString('title', self::TITLE_MAX);
|
||||
$validator->assert();
|
||||
|
||||
$updated = $this->projects->update($project['id'], $project['owner_id'], $fields);
|
||||
$updated = $this->projects->update($project['id'], $project['owner_id'], $title);
|
||||
|
||||
return $this->json($response, ['project' => $this->present($updated)]);
|
||||
}
|
||||
@@ -107,7 +96,7 @@ final class ProjectController extends ProjectScopedController
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{id: int, owner_id: int, title: string, description: string, card_count: int, completed_count: int, created_at: string, updated_at: string} $project
|
||||
* @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
|
||||
@@ -115,7 +104,6 @@ final class ProjectController extends ProjectScopedController
|
||||
return [
|
||||
'id' => $project['id'],
|
||||
'title' => $project['title'],
|
||||
'description' => $project['description'],
|
||||
'owner_id' => $project['owner_id'],
|
||||
'card_count' => $project['card_count'],
|
||||
'completed_count' => $project['completed_count'],
|
||||
|
||||
@@ -24,7 +24,7 @@ abstract class ProjectScopedController extends Controller
|
||||
* by the authenticated user.
|
||||
*
|
||||
* @param array<string, string> $args
|
||||
* @return array{id: int, owner_id: int, title: string, description: string, card_count: int, completed_count: int, created_at: string, updated_at: string}
|
||||
* @return array{id: int, owner_id: int, title: string, card_count: int, completed_count: int, created_at: string, updated_at: string}
|
||||
*/
|
||||
protected function requireOwnedProject(Request $request, array $args): array
|
||||
{
|
||||
|
||||
@@ -11,14 +11,14 @@ use PDO;
|
||||
* Data access for the `projects` table.
|
||||
*
|
||||
* @phpstan-type ProjectRow array{
|
||||
* id: int, owner_id: int, title: string, description: string,
|
||||
* id: int, owner_id: int, title: string,
|
||||
* card_count: int, completed_count: int, created_at: string, updated_at: string
|
||||
* }
|
||||
*/
|
||||
final class ProjectRepository
|
||||
{
|
||||
private const SELECT = <<<'SQL'
|
||||
SELECT p.id, p.owner_id, p.title, p.description, p.created_at, p.updated_at,
|
||||
SELECT p.id, p.owner_id, p.title, p.created_at, p.updated_at,
|
||||
(SELECT COUNT(*) FROM cards c WHERE c.project_id = p.id) AS card_count,
|
||||
(SELECT COUNT(*) FROM cards c WHERE c.project_id = p.id AND c.complete = 1) AS completed_count
|
||||
FROM projects p
|
||||
@@ -68,15 +68,12 @@ final class ProjectRepository
|
||||
/**
|
||||
* @return ProjectRow
|
||||
*/
|
||||
public function create(int $ownerId, string $title, string $description): array
|
||||
public function create(int $ownerId, string $title): array
|
||||
{
|
||||
$stmt = $this->pdo->prepare(
|
||||
'INSERT INTO projects (owner_id, title, description) VALUES (:owner, :title, :description)'
|
||||
);
|
||||
$stmt = $this->pdo->prepare('INSERT INTO projects (owner_id, title) VALUES (:owner, :title)');
|
||||
$stmt->execute([
|
||||
'owner' => $ownerId,
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
]);
|
||||
|
||||
/** @var ProjectRow $project */
|
||||
@@ -86,23 +83,14 @@ final class ProjectRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{title?: string, description?: string} $fields
|
||||
* @return ProjectRow
|
||||
*/
|
||||
public function update(int $id, int $ownerId, array $fields): array
|
||||
public function update(int $id, int $ownerId, string $title): array
|
||||
{
|
||||
$sets = ['updated_at = ' . Database::nowExpr()];
|
||||
$params = ['id' => $id];
|
||||
|
||||
foreach (['title', 'description'] as $column) {
|
||||
if (array_key_exists($column, $fields)) {
|
||||
$sets[] = "{$column} = :{$column}";
|
||||
$params[$column] = $fields[$column];
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = $this->pdo->prepare('UPDATE projects SET ' . implode(', ', $sets) . ' WHERE id = :id');
|
||||
$stmt->execute($params);
|
||||
$stmt = $this->pdo->prepare(
|
||||
'UPDATE projects SET title = :title, updated_at = ' . Database::nowExpr() . ' WHERE id = :id'
|
||||
);
|
||||
$stmt->execute(['id' => $id, 'title' => $title]);
|
||||
|
||||
/** @var ProjectRow $project */
|
||||
$project = $this->findOwnedBy($id, $ownerId);
|
||||
|
||||
Reference in New Issue
Block a user