fix todo create/update: link category via todo_categories junction table, return single object (not array), include category_ids in response

This commit is contained in:
Jürg Hallenbarter
2026-05-13 14:08:24 +02:00
parent 7c81586d3f
commit fb9ff9d56b
2 changed files with 73 additions and 20 deletions

View File

@@ -63,6 +63,11 @@ class TodoController extends BaseController
$this->todoModel->insert($data); $this->todoModel->insert($data);
// Link category if provided
if (!empty($json['category_id'])) {
$this->linkCategory($data['id'], $json['category_id']);
}
// Manually log the activity // Manually log the activity
try { try {
$activityLogModel = new \App\Models\ActivityLogModel(); $activityLogModel = new \App\Models\ActivityLogModel();
@@ -79,9 +84,9 @@ class TodoController extends BaseController
log_message('error', 'Failed to log activity: ' . $e->getMessage()); log_message('error', 'Failed to log activity: ' . $e->getMessage());
} }
$todo = $this->todoModel->getByUserWithCategories($userId, $data['id']); $todos = $this->todoModel->getByUserWithCategories($userId, $data['id']);
return $this->successResponse($todo, 'Todo created successfully', 201); return $this->successResponse($todos[0] ?? null, 'Todo created successfully', 201);
} }
/** /**
@@ -91,13 +96,13 @@ class TodoController extends BaseController
public function show($id = null) public function show($id = null)
{ {
$userId = $this->getUserId(); $userId = $this->getUserId();
$todo = $this->todoModel->getByUserWithCategories($userId, $id); $todos = $this->todoModel->getByUserWithCategories($userId, $id);
if (!$todo) { if (empty($todos)) {
return $this->errorResponse('Todo not found', 404); return $this->errorResponse('Todo not found', 404);
} }
return $this->successResponse($todo, 'Todo retrieved successfully'); return $this->successResponse($todos[0], 'Todo retrieved successfully');
} }
/** /**
@@ -114,14 +119,26 @@ class TodoController extends BaseController
} }
$json = $this->request->getJSON(true); $json = $this->request->getJSON(true);
// Handle category update separately (not a column in todos table)
$hasCategoryUpdate = array_key_exists('category_id', $json);
if ($hasCategoryUpdate) {
$categoryId = $json['category_id'];
// Remove all existing category links
$this->todoCategoryModel->where('todo_id', $id)->delete();
// Link the new category
if (!empty($categoryId)) {
$this->linkCategory($id, $categoryId);
}
}
// Update todo fields
$allowedFields = ['title', 'description', 'status', 'due_date', 'due_time', 'sync_enabled', 'reminder_enabled', 'recurring_enabled', 'project_id']; $allowedFields = ['title', 'description', 'status', 'due_date', 'due_time', 'sync_enabled', 'reminder_enabled', 'recurring_enabled', 'project_id'];
$updateData = array_intersect_key($json, array_flip($allowedFields)); $updateData = array_intersect_key($json, array_flip($allowedFields));
if (empty($updateData)) { if (!empty($updateData)) {
return $this->errorResponse('No valid fields to update'); $this->todoModel->update($id, $updateData);
} }
$this->todoModel->update($id, $updateData);
// Manually log the activity // Manually log the activity
try { try {
@@ -139,9 +156,9 @@ class TodoController extends BaseController
log_message('error', 'Failed to log activity: ' . $e->getMessage()); log_message('error', 'Failed to log activity: ' . $e->getMessage());
} }
$todo = $this->todoModel->getByUserWithCategories($userId, $id); $updated = $this->todoModel->getByUserWithCategories($userId, $id);
return $this->successResponse($todo, 'Todo updated successfully'); return $this->successResponse($updated[0] ?? null, 'Todo updated successfully');
} }
/** /**
@@ -238,6 +255,34 @@ class TodoController extends BaseController
return $this->successResponse(null, 'Category removed from todo successfully'); return $this->successResponse(null, 'Category removed from todo successfully');
} }
/**
* Link a category to a todo
*/
private function linkCategory(string $todoId, string $categoryId): void
{
$userId = $this->getUserId();
// Verify category belongs to user
$categoryModel = new \App\Models\CategoryModel();
$category = $categoryModel->where('id', $categoryId)->where('user_id', $userId)->first();
if (!$category) {
return;
}
// Check if link already exists
$existing = $this->todoCategoryModel
->where('todo_id', $todoId)
->where('category_id', $categoryId)
->first();
if (!$existing) {
$this->todoCategoryModel->insert([
'todo_id' => $todoId,
'category_id' => $categoryId,
]);
}
}
private function generateUuid(): string private function generateUuid(): string
{ {
return sprintf( return sprintf(

View File

@@ -52,15 +52,23 @@ class TodoModel extends Model
return $builder->get()->getResultArray(); return $builder->get()->getResultArray();
} }
// Get todos by user with categories // Get todos by user with categories (optionally filtered by todo id)
public function getByUserWithCategories($userId) public function getByUserWithCategories($userId, $todoId = null)
{ {
return $this->select('todos.*, GROUP_CONCAT(categories.name) as category_names') $builder = $this->select('
->join('todo_categories', 'todos.id = todo_categories.todo_id', 'left') todos.*,
->join('categories', 'todo_categories.category_id = categories.id', 'left') GROUP_CONCAT(DISTINCT categories.id SEPARATOR \',\') as category_ids,
->where('todos.user_id', $userId) GROUP_CONCAT(DISTINCT categories.name SEPARATOR \', \') as category_names
->groupBy('todos.id') ')
->get() ->join('todo_categories', 'todos.id = todo_categories.todo_id', 'left')
->getResultArray(); ->join('categories', 'todo_categories.category_id = categories.id', 'left')
->where('todos.user_id', $userId)
->groupBy('todos.id');
if ($todoId) {
$builder->where('todos.id', $todoId);
}
return $builder->get()->getResultArray();
} }
} }