PHPackages                             verseles/progressable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. verseles/progressable

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

verseles/progressable
=====================

A Laravel (not only) package to track and manage progress for different tasks or processes.

v2.3.0(2w ago)13310[1 PRs](https://github.com/verseles/progressable/pulls)MITPHPPHP &gt;=8.4CI passing

Since Mar 5Pushed 2w ago1 watchersCompare

[ Source](https://github.com/verseles/progressable)[ Packagist](https://packagist.org/packages/verseles/progressable)[ RSS](/packages/verseles-progressable/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (21)Versions (24)Used By (0)

Progressable
============

[](#progressable)

A Laravel [(not only)](#without-laravel) package to track and manage progress for different tasks or processes.

[![CI](https://camo.githubusercontent.com/c614122624cd668655f264b33c7220bc5a3387ded838fbc7cd4551db981d26c1/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f76657273656c65732f70726f677265737361626c652f706870756e69742e796d6c3f7374796c653d666f722d7468652d6261646765266c6162656c3d4349)](https://camo.githubusercontent.com/c614122624cd668655f264b33c7220bc5a3387ded838fbc7cd4551db981d26c1/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f76657273656c65732f70726f677265737361626c652f706870756e69742e796d6c3f7374796c653d666f722d7468652d6261646765266c6162656c3d4349)[![Codecov](https://camo.githubusercontent.com/c740bbf3abfe4e5ee9e0f89f0cbdd8b41aed7961939ca2e7bc56b6d0dae991f3/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f76657273656c65732f70726f677265737361626c653f7374796c653d666f722d7468652d6261646765)](https://camo.githubusercontent.com/c740bbf3abfe4e5ee9e0f89f0cbdd8b41aed7961939ca2e7bc56b6d0dae991f3/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f76657273656c65732f70726f677265737361626c653f7374796c653d666f722d7468652d6261646765)[![PHP Version](https://camo.githubusercontent.com/91743f7832b13fc9d66cd81299e62a7fdebe1c59aa247909d59ca78eeca417ed/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f76657273656c65732f70726f677265737361626c653f7374796c653d666f722d7468652d6261646765)](https://camo.githubusercontent.com/91743f7832b13fc9d66cd81299e62a7fdebe1c59aa247909d59ca78eeca417ed/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f76657273656c65732f70726f677265737361626c653f7374796c653d666f722d7468652d6261646765)

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require verseles/progressable
```

Optionally, you can publish the config file with:

```
php artisan vendor:publish --provider="Verseles\Progressable\ProgressableServiceProvider" --tag="config"
```

Configuration
-------------

[](#configuration)

The published config file provides the following options:

```
return [
    'ttl' => env('PROGRESSABLE_TTL', 1140),           // Cache TTL in minutes (default: 19 hours)
    'prefix' => env('PROGRESSABLE_PREFIX', 'progressable'), // Cache key prefix
    'precision' => env('PROGRESSABLE_PRECISION', 2),  // Default decimal precision
];
```

Usage
-----

[](#usage)

This package provides a main trait: `Progressable`.

### With Laravel

[](#with-laravel)

The `Progressable` trait can be used in any class that needs to track progress.

"Local" refers to the progress of your class/model/etc, while "Overall" represents the average of all Progressable instances using the same unique name.

For parallel jobs, use one stable overall key for the parent operation and one stable local key per worker. The default cache-backed store updates each local entry independently under a cache lock when the cache driver supports atomic locks. Under heavy contention, Laravel may throw `Illuminate\Contracts\Cache\LockTimeoutException` if the lock cannot be acquired before the wait timeout.

```
$progress->setOverallUniqueName("routine-run:{$runId}");
$progress->setLocalKey("module:{$moduleId}");
$progress->setLocalProgress(42);
```

Custom `setCustomSaveData()` / `setCustomGetData()` callbacks still receive the full progress snapshot, so custom storage should implement its own concurrency control for parallel writers.

### Basic Example

[](#basic-example)

```
use Verseles\Progressable\Progressable;

class MyFirstTask
{
    use Progressable;

    public function __construct()
    {
        $this->setOverallUniqueName('my-job')->resetOverallProgress();
    }

    public function run()
    {
        foreach (range(1, 100) as $value) {
            $this->setLocalProgress($value);
            echo "Overall Progress: " . $this->getOverallProgress() . "%" . PHP_EOL;
        }
    }
}
```

### Available Methods

[](#available-methods)

#### Progress Management

[](#progress-management)

MethodDescription`setOverallUniqueName(string $name)`Set the progress group identifier`setLocalProgress(float $progress)`Set progress for this instance (0-100)`getLocalProgress(?int $precision)`Get current progress (default precision from config)`incrementLocalProgress(float $amount = 1)`Increment progress by amount (can be negative)`resetLocalProgress()`Reset instance progress to 0`getOverallProgress(?int $precision)`Get average progress of all instances`resetOverallProgress()`Clear all progress data for the group`removeLocalFromOverall()`Remove this instance from overall calculation`getEstimatedTimeRemaining()`Get estimated time remaining in seconds for this instance`getOverallEstimatedTimeRemaining()`Get estimated time remaining in seconds for the overall progress#### Status Checks

[](#status-checks)

MethodDescription`isComplete()`Check if local progress is 100%`isOverallComplete()`Check if overall progress is 100%#### Metadata &amp; Status Messages

[](#metadata--status-messages)

MethodDescription`setStatusMessage(?string $message)`Set a status message for this instance`getStatusMessage()`Get the current status message`setMetadata(array $metadata)`Set metadata array for this instance`getMetadata()`Get all metadata`addMetadata(string $key, mixed $value)`Add/update a single metadata value`getMetadataValue(string $key, mixed $default)`Get a single metadata value#### Event Callbacks

[](#event-callbacks)

MethodDescription`onProgressChange(callable $callback)`Called when progress changes: `fn($new, $old, $instance)``onComplete(callable $callback)`Called when progress reaches 100%: `fn($instance)`#### Configuration

[](#configuration-1)

MethodDescription`setTTL(int $minutes)`Set cache time-to-live`getTTL()`Get current TTL`setPrecision(int $decimals)`Set decimal precision for progress values`getPrecision()`Get current precision`setPrefixStorageKey(string $prefix)`Set custom cache key prefix (before setting unique name)`setLocalKey(string $key)`Set custom identifier for this instance`getLocalKey()`Get current instance identifier#### Custom Storage (for non-Laravel usage)

[](#custom-storage-for-non-laravel-usage)

MethodDescription`setCustomSaveData(callable $callback)`Set custom save callback`setCustomGetData(callable $callback)`Set custom get callback### Example with Callbacks and Metadata

[](#example-with-callbacks-and-metadata)

```
use Verseles\Progressable\Progressable;

class FileProcessor
{
    use Progressable;

    public function process(array $files)
    {
        $this->setOverallUniqueName('file-processing')
            ->resetOverallProgress()
            ->onProgressChange(fn($new, $old) => logger("Progress: {$old}% -> {$new}%"))
            ->onComplete(fn() => logger("All files processed!"));

        $increment = 100 / count($files);

        foreach ($files as $index => $file) {
            $this->setStatusMessage("Processing: {$file}")
                ->addMetadata('current_file', $file)
                ->addMetadata('files_processed', $index + 1);

            $this->processFile($file);
            $this->incrementLocalProgress($increment);
        }
    }
}
```

### Without Laravel

[](#without-laravel)

You can use the `Progressable` trait without Laravel by providing custom save and get data callbacks:

```
use Verseles\Progressable\Progressable;

$storage = [];

$saveCallback = function ($key, $data, $ttl) use (&$storage) {
    $storage[$key] = $data;
};

$getCallback = function ($key) use (&$storage) {
    return $storage[$key] ?? [];
};

$obj = new class { use Progressable; };
$obj
    ->setCustomSaveData($saveCallback)
    ->setCustomGetData($getCallback)
    ->setOverallUniqueName('my-task')
    ->resetOverallProgress()
    ->setLocalProgress(25);

echo $obj->getLocalProgress(); // 25
```

Testing
-------

[](#testing)

```
# Run tests
composer test

# Check code style
composer lint:test

# Fix code style
composer lint

# Run static analysis
composer analyse
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.

Changelog
---------

[](#changelog)

Please see [CHANGELOG.md](CHANGELOG.md) for recent changes.

License
-------

[](#license)

The Progressable package is open-sourced software licensed under the [MIT license](./LICENSE.md).

###  Health Score

53

—

FairBetter than 96% of packages

Maintenance97

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity69

Established project with proven stability

 Bus Factor1

Top contributor holds 88.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~56 days

Recently: every ~208 days

Total

16

Last Release

15d ago

Major Versions

v1.5.0 → v2.0.02024-05-20

PHP version history (2 changes)1.0.0PHP &gt;=8.2

v2.1.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/934b53b68624e78343e3f3367897cbaf5fb01475511a1650d2c99c972c810ec6?d=identicon)[insign](/maintainers/insign)

---

Top Contributors

[![insign](https://avatars.githubusercontent.com/u/1113045?v=4)](https://github.com/insign "insign (53 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (4 commits)")[![google-labs-jules[bot]](https://avatars.githubusercontent.com/in/842251?v=4)](https://github.com/google-labs-jules[bot] "google-labs-jules[bot] (3 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/verseles-progressable/health.svg)

```
[![Health](https://phpackages.com/badges/verseles-progressable/health.svg)](https://phpackages.com/packages/verseles-progressable)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[propaganistas/laravel-disposable-email

Disposable email validator

6023.0M7](/packages/propaganistas-laravel-disposable-email)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

44855.7k](/packages/harris21-laravel-fuse)[illuminate/pagination

The Illuminate Pagination package.

12234.1M1.0k](/packages/illuminate-pagination)[illuminate/pipeline

The Illuminate Pipeline package.

9349.2M281](/packages/illuminate-pipeline)[illuminate/session

The Illuminate Session package.

9939.3M849](/packages/illuminate-session)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
