Initial habit tracker project

This commit is contained in:
2026-07-10 16:18:31 +02:00
commit 23416ee382
20 changed files with 1157 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
<?php
class Habit
{
public static function allForUser(int $userId, array $filters = []): array
{
$where = ['h.user_id = :user_id'];
$params = ['user_id' => $userId];
if (!empty($filters['category_id'])) {
$where[] = 'h.category_id = :category_id';
$params['category_id'] = (int) $filters['category_id'];
}
if (($filters['status'] ?? '') === 'done') {
$where[] = 'hl.id IS NOT NULL';
} elseif (($filters['status'] ?? '') === 'open') {
$where[] = 'hl.id IS NULL';
}
$sql = 'SELECT h.*, c.name AS category_name, c.color AS category_color,
CASE WHEN hl.id IS NULL THEN 0 ELSE 1 END AS done_today
FROM habits h
LEFT JOIN categories c ON c.id = h.category_id
LEFT JOIN habit_logs hl
ON hl.habit_id = h.id
AND hl.completed_on = CURRENT_DATE
WHERE ' . implode(' AND ', $where) . '
ORDER BY h.created_at DESC';
$statement = Database::connection()->prepare($sql);
$statement->execute($params);
return $statement->fetchAll();
}
public static function findForUser(int $id, int $userId): ?array
{
$statement = Database::connection()->prepare(
'SELECT * FROM habits WHERE id = :id AND user_id = :user_id LIMIT 1'
);
$statement->execute(['id' => $id, 'user_id' => $userId]);
$habit = $statement->fetch();
return $habit ?: null;
}
public static function create(int $userId, array $data): bool
{
$sql = 'INSERT INTO habits (user_id, category_id, title, description, target_per_week)
VALUES (:user_id, :category_id, :title, :description, :target_per_week)';
return Database::connection()->prepare($sql)->execute([
'user_id' => $userId,
'category_id' => $data['category_id'] ?: null,
'title' => $data['title'],
'description' => $data['description'],
'target_per_week' => (int) $data['target_per_week'],
]);
}
public static function update(int $id, int $userId, array $data): bool
{
$sql = 'UPDATE habits
SET category_id = :category_id,
title = :title,
description = :description,
target_per_week = :target_per_week
WHERE id = :id AND user_id = :user_id';
return Database::connection()->prepare($sql)->execute([
'id' => $id,
'user_id' => $userId,
'category_id' => $data['category_id'] ?: null,
'title' => $data['title'],
'description' => $data['description'],
'target_per_week' => (int) $data['target_per_week'],
]);
}
public static function delete(int $id, int $userId): bool
{
$statement = Database::connection()->prepare('DELETE FROM habits WHERE id = :id AND user_id = :user_id');
return $statement->execute(['id' => $id, 'user_id' => $userId]);
}
public static function toggleToday(int $id, int $userId): bool
{
$habit = self::findForUser($id, $userId);
if (!$habit) {
return false;
}
$db = Database::connection();
$check = $db->prepare(
'SELECT id FROM habit_logs WHERE habit_id = :habit_id AND completed_on = CURRENT_DATE LIMIT 1'
);
$check->execute(['habit_id' => $id]);
$log = $check->fetch();
if ($log) {
return $db->prepare('DELETE FROM habit_logs WHERE id = :id')->execute(['id' => $log['id']]);
}
$insert = $db->prepare('INSERT INTO habit_logs (habit_id, completed_on) VALUES (:habit_id, CURRENT_DATE)');
return $insert->execute(['habit_id' => $id]);
}
}