adachsoft / task-contracts
task-contracts
Requires
- php: ^8.3
- adachsoft/collection: ^3.0
- psr/clock: ^1.0
Requires (Dev)
- adachsoft/php-code-style: ^0.7
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^13.1
- rector/rector: ^2.4
- symplify/phpstan-rules: ^14.17
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
adachsoft/task-contracts provides PHP contracts, immutable DTOs, value objects, exceptions, and application use cases for task management. The package defines repository APIs without prescribing a storage engine.
Requirements
- PHP 8.3 or newer
adachsoft/collection3.xpsr/clock1.x
Installation
composer require adachsoft/task-contracts
The repository also contains the optional in-memory implementation:
composer require adachsoft/task-memory
Package structure
The main package contains:
- repository interfaces for tasks and comments;
- immutable task and comment DTOs;
- typed task and comment collections;
- task status resolution contracts and enum values;
- domain exceptions;
TaskServiceandCommentServiceapplication use cases;TaskServiceFactory, the recommended entry point for creating use cases.
adachsoft/task-memory provides InMemoryTaskRepository and InMemoryCommentRepository implementations for applications and tests. Other storage implementations can implement the repository interfaces independently.
Repository contracts
TaskRepositoryInterface
AdachSoft\TaskContracts\Interface\TaskRepositoryInterface
The interface supports finding, listing, updating, and deleting tasks; traversing task trees; managing dependencies; counting child tasks; and the following version 2.0 operations:
nextIdentity()returns the next available identifier without reserving it;add()atomically inserts a task and persists it with version1;save()updates an existing task using optimistic locking;addDependency()andremoveDependency()update the task version.
save() is no longer an upsert. It requires the DTO version to match the stored version and increments the version after a successful update. Repository reads return the current version and current dependencies.
CommentRepositoryInterface
AdachSoft\TaskContracts\Interface\CommentRepositoryInterface
The interface supports finding, listing, updating, and deleting comments, counting comments by task, and the version 2.0 operations:
nextIdentity(string $taskId)returns the next comment identifier without reserving it;add()atomically inserts a comment with version1;save()updates a comment using optimistic locking.
Task statuses
TaskStatusEnum contains:
use AdachSoft\TaskContracts\Enum\TaskStatusEnum;
TaskStatusEnum::TODO;
TaskStatusEnum::IN_PROGRESS;
TaskStatusEnum::DONE;
TaskStatusEnum::BLOCKED;
TaskStatusEnum::CANCELLED;
DTOs
TaskDto is a readonly object containing task identity, hierarchy, description, timestamps, status, dependencies, subtasks, and an optimistic-lock version.
CommentDto is a readonly object containing comment identity, task association, author, content, timestamps, and an optimistic-lock version.
The use-case DTOs are:
CreateTaskDtofor task creation;UpdateTaskDtofor partial task updates, including explicit root-task reassignment;TaskDetailsDtofor a task together with comment and subtask counts.
Application use cases
Create services through TaskServiceFactory:
use AdachSoft\TaskContracts\UseCase\TaskServiceFactory;
$taskService = TaskServiceFactory::createTaskService(
taskRepository: $taskRepository,
commentRepository: $commentRepository,
);
$commentService = TaskServiceFactory::createCommentService(
commentRepository: $commentRepository,
taskRepository: $taskRepository,
);
TaskService provides task creation, updates, status changes, deletion, task reads, tree queries, dependency management, and task listing. CommentService provides comment creation, editing, deletion, lookup, and listing by task.
The factory accepts an optional Psr\Clock\ClockInterface and configurable validation limits. When no clock is supplied, the package uses the system clock.
Generated task and comment identifiers are retried only when an atomic insert detects a collision. Concurrent modifications are never retried automatically; callers should reload the DTO and decide how to reconcile the change.
Exceptions
The package exposes dedicated exceptions for common failure cases:
TaskAlreadyExistsExceptionandCommentAlreadyExistsExceptionfor atomic insert collisions;ConcurrentModificationExceptionfor optimistic-lock version conflicts;InvalidTaskDataExceptionfor invalid identifiers and field values;- existing not-found exceptions for missing tasks and comments.
Example integration
Inject repository implementations into an application service or create the package use cases through the factory:
use AdachSoft\TaskContracts\Interface\TaskRepositoryInterface;
use AdachSoft\TaskContracts\Dto\TaskDto;
final class TaskReader
{
public function __construct(
private TaskRepositoryInterface $tasks,
) {
}
public function findTask(string $taskId): ?TaskDto
{
return $this->tasks->findById($taskId);
}
}
The concrete repository is intentionally not part of the main package. Select an implementation that matches the application environment and inject it through the interface.
Concurrency model
Repository writes use optimistic locking. add() assigns version 1; successful save(), addDependency(), and removeDependency() operations increment the stored version. A stale DTO causes ConcurrentModificationException instead of silently overwriting another client's changes.
See docs/adr/0001-task-storage-concurrency.md for the storage and concurrency decision record.
Development
Install development dependencies and run the quality checks:
composer install
vendor/bin/phpunit
vendor/bin/phpstan analyse src
vendor/bin/phpstan analyse tests
vendor/bin/rector process src
vendor/bin/rector process tests
vendor/bin/php-cs-fixer fix src
vendor/bin/php-cs-fixer fix tests
License
This library is released under the MIT License. See the LICENSE file for details.