charleslightjarvis/laravel-todo

A Laravel package to attach todo lists to any Eloquent model.

Maintainers

Package info

github.com/CharlesLightjarvis/laravel-todo

Homepage

pkg:composer/charleslightjarvis/laravel-todo

Fund package maintenance!

laravel-todo

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.1 2026-04-23 14:06 UTC

This package is auto-updated.

Last update: 2026-04-23 14:12:02 UTC


README

Latest Version on Packagist Total Downloads License

Attach todo lists to any Eloquent model in your Laravel application.

The Problem

In a Laravel application, multiple entities (User, Project, Team, Invoice...) often need their own todo list. Without a package, you have to:

  • Create a separate table for each entity type (user_todos, project_todos, team_todos...)
  • Duplicate models, scopes, and relationships
  • Maintain the same logic across multiple places
  • No unified API to interact with todos

The Solution

laravel-todo lets you attach todos to any Eloquent model with a single trait. One table, one logic, every model.

  • ✅ Attach todos to User, Project, Team, Invoice — anything
  • ✅ Fluent API via Trait and Facade
  • ✅ Built-in scopes: pending, completed, overdue, highPriority, dueToday
  • ✅ Polymorphic creator support (tracks who created the todo)
  • ✅ Zero duplication

Features

  • ✅ Polymorphic relationship – attach todos to any model (User, Project, Team, etc.)
  • ✅ Fluent API via Facade or Trait
  • ✅ Built-in scopes: pending(), completed(), overdue(), highPriority(), dueToday()
  • ✅ Status management: pending, in_progress, completed, cancelled
  • ✅ Priority levels: low, medium, high
  • ✅ Tracks who created each todo (polymorphic creator relation)
  • ✅ Zero UI – backend only, integrate however you want

Requirements

  • PHP 8.2 or higher
  • Laravel 11.0 or higher

Installation

Install the package via Composer:

composer require charleslightjarvis/laravel-todo

Publish the migration file:

php artisan vendor:publish --tag="todo-migrations"

Run the migrations:

php artisan migrate

Publish the configuration file (optional):

php artisan vendor:publish --tag="todo-config"

Configuration

The config file config/todo.php allows you to customize:

return [
    'prune_after_days' => 30,

    'models' => [
        'todo' => CharlesLightjarvis\Todo\Models\Todo::class,
    ],

    'todo_morph_key' => 'todoable_id',
];

Usage

1. Add the trait to your model

Add HasTodos to any Eloquent model you want to attach todos to:

use CharlesLightjarvis\Todo\Traits\HasTodos;

class User extends Model
{
    use HasTodos;
}

class Project extends Model
{
    use HasTodos;
}

2. Creating todos via the Trait

Use the todos() relation directly on any model that uses HasTodos:

$user = User::find(1);

// Create a todo on the model
$todo = $user->todos()->create([
    'title'    => 'Buy groceries',
    'priority' => 'high',
    'due_at'   => now()->addDays(2),
]);

// Create with addTodo() — optionally assign a creator
$todo = $user->addTodo([
    'title'    => 'Finish the report',
    'priority' => 'medium',
], $creator);

3. Querying todos via the Trait

All built-in scopes are available directly on the relation:

$user->todos()->pending()->get();
$user->todos()->inProgress()->get();
$user->todos()->completed()->get();
$user->todos()->cancelled()->get();

$user->todos()->highPriority()->get();
$user->todos()->overdue()->get();
$user->todos()->dueToday()->get();

// Scopes can be chained
$user->todos()->pending()->highPriority()->get();

4. Creating and querying todos via the Facade

The Todo facade provides a model-agnostic API — useful when you do not have a direct reference to the owning model instance:

use CharlesLightjarvis\Todo\Facades\Todo;

// Create a todo for any model
$todo = Todo::createFor($user, [
    'title'    => 'Fix navigation bug',
    'priority' => 'high',
    'due_at'   => now()->addWeek(),
]);

// Scope queries to a specific model
Todo::for($user)->pending()->get();
Todo::for($user)->highPriority()->get();
Todo::for($user)->overdue()->get();

// Count
Todo::for($user)->count();
Todo::for($user)->pending()->count();
Todo::for($user)->completed()->count();

5. Completing and cancelling todos

Both methods are ownership-aware — they silently return false if the todo does not belong to the model:

// Complete a todo
$user->completeTodo($todo);

// After completion
$todo->refresh();
$todo->status->value;  // 'completed'
$todo->completed_at;   // Carbon timestamp

// Cancel a todo
$user->cancelTodo($todo);

$todo->refresh();
$todo->status->value;  // 'cancelled'

// Another user cannot complete a todo they don't own
$otherUser->completeTodo($todo); // returns false, status unchanged

6. Accessing todo relations

// All todos attached to the model
$user->todos;

// All todos created by the model (via the creator relation)
$user->createdTodos;

7. Tracking who created a todo

// Via addTodo — pass the creator as the second argument
$todo = $project->addTodo(['title' => 'Review PR'], auth()->user());

// Or set creator fields manually
$todo = $project->todos()->create([
    'title'        => 'Review PR',
    'creator_type' => $user->getMorphClass(),
    'creator_id'   => $user->id,
]);

// Resolve the creator
$todo->creator; // returns the creator model

Available Scopes

Scope Description
pending() Status = pending
inProgress() Status = in_progress
completed() Status = completed
cancelled() Status = cancelled
overdue() Not completed + due_at in the past
highPriority() Priority = high
dueToday() due_at is today

Enums

The package provides two enums for type safety:

use CharlesLightjarvis\Todo\Enums\TodoStatusEnum;
use CharlesLightjarvis\Todo\Enums\TodoPriorityEnum;

// Status values
TodoStatusEnum::PENDING->value;      // 'pending'
TodoStatusEnum::IN_PROGRESS->value;  // 'in_progress'
TodoStatusEnum::COMPLETED->value;    // 'completed'
TodoStatusEnum::CANCELLED->value;    // 'cancelled'

// Priority values
TodoPriorityEnum::LOW->value;    // 'low'
TodoPriorityEnum::MEDIUM->value; // 'medium'
TodoPriorityEnum::HIGH->value;   // 'high'

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Contributions are welcome! Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please email charlestagne55@gmail.com instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.