turahe / laravel-counters
management for counters in laravel system
Requires
- php: ^8.4
- illuminate/database: ^11.0 || ^12.0
- illuminate/support: ^11.0 || ^12.0
Requires (Dev)
- laravel/framework: ^11.0 || ^12.0
- laravel/pint: ^1.17
- orchestra/testbench: ^9.0 || ^10.0 || ^11.0
- phpunit/phpunit: ^10.0
This package is auto-updated.
Last update: 2025-08-08 06:21:49 UTC
README
A modern, optimized counter management package for Laravel 11/12 with PHP 8.4 support.
A flexible and powerful counter management system for Laravel applications. Easily track and manage various types of counters like page views, downloads, user actions, and more without cluttering your database schema.
🚀 Features
- ✅ PHP 8.4 Optimized: Uses readonly properties, constructor property promotion, match expressions, and improved type declarations
- ✅ Laravel 11/12 Compatible: Modern service provider patterns and dependency injection
- ✅ High Performance: Built-in caching, bulk operations, and optimized database queries
- ✅ Type Safe: Full type declarations and strict typing throughout
- ✅ Modern Patterns: Uses modern PHP and Laravel patterns and best practices
- ✅ Comprehensive Testing: Full test coverage with modern testing practices
- Model-specific counters: Associate counters with any Eloquent model
- Global counters: System-wide counters for general statistics
- Cookie-based tracking: Prevent duplicate increments from the same user
- Flexible configuration: Customizable table names and settings
- Artisan commands: Create counters via command line
- Laravel 10-12 support: Compatible with modern Laravel versions
- PHP 8.2+ support: Built for modern PHP applications
📋 Table of Contents
Installation
Requirements
- PHP: 8.4 or higher
- Laravel: 11.x or 12.x
Step-by-Step Installation
- Install the package via Composer:
composer require turahe/laravel-counters
- Publish the configuration and migrations:
php artisan vendor:publish --tag=counters-config
This will publish:
- Configuration file:
config/counter.php
- Migration file:
database/migrations/xxxx_xx_xx_xxxxxx_create_counters_tables.php
- Run the migrations:
php artisan migrate
This creates the counters
and counterables
tables in your database.
Quick Start
1. Create a Counter
use Turahe\Counters\Models\Counter; // Create a counter for page views Counter::create([ 'key' => 'page_views', 'name' => 'Page Views', 'initial_value' => 0, 'step' => 1 ]);
2. Use with Models
use Turahe\Counters\Traits\HasCounter; class Post extends Model { use HasCounter; // Your model code... }
3. Track Views
// In your controller public function show(Post $post) { $post->incrementCounter('page_views'); return view('posts.show', compact('post')); }
4. Global Counters
use Turahe\Counters\Facades\Counters; // Track total downloads Counters::increment('total_downloads');
Usage
Model Counters
Add the HasCounter
trait to any model you want to track:
use Turahe\Counters\Traits\HasCounter; class Post extends Model { use HasCounter; // Your model code... }
Available Methods
// Add a counter to a model $post->addCounter('views'); // Get counter value $views = $post->getCounterValue('views'); // Increment counter $post->incrementCounter('views'); // Decrement counter $post->decrementCounter('views', 2); // Decrement by 2 // Reset counter to initial value $post->resetCounter('views'); // Remove counter from model $post->removeCounter('views'); // Check if model has counter if ($post->hasCounter('views')) { // Do something }
Global Counters
Use the Counters
facade for system-wide counters:
use Turahe\Counters\Facades\Counters; // Create a counter Counters::create('total_downloads', 'Total Downloads', 0, 1); // Get counter value $downloads = Counters::getValue('total_downloads'); // Increment counter Counters::increment('total_downloads'); // Decrement counter Counters::decrement('total_downloads', 2); // Set specific value Counters::setValue('total_downloads', 100); // Reset to initial value Counters::reset('total_downloads');
Cookie-based Tracking
Prevent duplicate increments from the same user:
// Only increment if user doesn't have cookie Counters::incrementIfNotHasCookies('daily_visitors'); Counters::decrementIfNotHasCookies('available_slots');
API Reference
Model Methods (HasCounter Trait)
Method | Description | Parameters |
---|---|---|
addCounter($key, $initialValue = null) |
Add counter to model | $key : Counter key, $initialValue : Optional initial value |
getCounter($key) |
Get counter object | $key : Counter key |
getCounterValue($key) |
Get counter value | $key : Counter key |
hasCounter($key) |
Check if model has counter | $key : Counter key |
incrementCounter($key, $step = null) |
Increment counter | $key : Counter key, $step : Optional step value |
decrementCounter($key, $step = null) |
Decrement counter | $key : Counter key, $step : Optional step value |
resetCounter($key, $initialValue = null) |
Reset counter | $key : Counter key, $initialValue : Optional reset value |
removeCounter($key) |
Remove counter from model | $key : Counter key |
Global Counter Methods (Counters Facade)
Method | Description | Parameters |
---|---|---|
create($key, $name, $initialValue = 0, $step = 1) |
Create a counter | $key : Counter key, $name : Display name, $initialValue : Initial value, $step : Step value |
get($key) |
Get counter object | $key : Counter key |
getValue($key, $default = null) |
Get counter value | $key : Counter key, $default : Default value if not found |
setValue($key, $value) |
Set counter value | $key : Counter key, $value : New value |
setStep($key, $step) |
Set counter step | $key : Counter key, $step : Step value |
increment($key, $step = null) |
Increment counter | $key : Counter key, $step : Optional step value |
decrement($key, $step = null) |
Decrement counter | $key : Counter key, $step : Optional step value |
reset($key) |
Reset counter | $key : Counter key |
incrementIfNotHasCookies($key) |
Increment if no cookie | $key : Counter key |
decrementIfNotHasCookies($key) |
Decrement if no cookie | $key : Counter key |
Configuration
The package configuration is located at config/counter.php
:
return [ 'models' => [ 'counter' => Turahe\Counters\Models\Counter::class, ], 'tables' => [ 'table_name' => 'counters', 'table_pivot_name' => 'counterables', ], 'database_connection' => env('COUNTER_DB_CONNECTION'), ];
Customizing Table Names
You can customize the table names in the configuration:
'tables' => [ 'table_name' => 'my_counters', 'table_pivot_name' => 'my_counterables', ],
Artisan Commands
Create Counter
Create a counter via command line:
php artisan make:counter page_views "Page Views" 0 1
Parameters:
page_views
: Counter key"Page Views"
: Display name0
: Initial value1
: Step value
Testing
The package includes comprehensive tests. Run them with:
./vendor/bin/phpunit
Test Coverage
- ✅ Model counter operations
- ✅ Global counter operations
- ✅ Cookie-based tracking
- ✅ Exception handling
- ✅ Database operations
- ✅ Configuration flexibility
Common Usage Patterns
✅ Best Practices
- Always create counters before using them:
// Create the counter first Counter::create([ 'key' => 'page_views', 'name' => 'Page Views', 'initial_value' => 0, 'step' => 1 ]); // Then use it $post->incrementCounter('page_views');
- Use meaningful counter keys:
// Good $post->incrementCounter('article_views'); $user->incrementCounter('login_count'); // Avoid generic names $post->incrementCounter('count');
- Handle counter existence gracefully:
if ($post->hasCounter('views')) { $post->incrementCounter('views'); } else { $post->addCounter('views'); $post->incrementCounter('views'); }
❌ Common Mistakes
- Don't forget to run migrations:
php artisan migrate
- Don't use counters without creating them first:
// This might fail if counter doesn't exist $post->incrementCounter('undefined_counter'); // Better approach $post->addCounter('new_counter'); $post->incrementCounter('new_counter');
Performance Optimizations
Caching
The package includes built-in caching for counter lookups, significantly improving performance for frequently accessed counters.
Bulk Operations
Use bulk operations to update multiple counters efficiently:
// Bulk increment $results = Counters::bulkIncrement(['counter1', 'counter2'], 5); // Bulk decrement $results = Counters::bulkDecrement(['counter1', 'counter2'], 3);
Database Indexes
The migration includes optimized indexes for better query performance.
Testing
Run the test suite:
composer test
PHP 8.4 Features Used
- Readonly Properties: Immutable data structures
- Constructor Property Promotion: Cleaner class definitions
- Match Expressions: Modern control flow
- Named Arguments: Self-documenting function calls
- Improved Type Declarations: Better type safety
- Strict Types: Enforced type checking
Laravel 11/12 Features Used
- Modern Service Providers: Deferrable providers for better performance
- Improved Dependency Injection: Constructor injection and type hints
- Enhanced Model Features: Better relationships and scopes
- Modern Command Structure: Improved Artisan commands
Example Seeder
Example seeder for creating counters:
use Illuminate\Database\Seeder; use Turahe\Counters\Models\Counter; class CounterSeeder extends Seeder { public function run() { // Create global counters Counter::create([ 'key' => 'total_downloads', 'name' => 'Total Downloads', 'initial_value' => 0, 'step' => 1 ]); Counter::create([ 'key' => 'daily_visitors', 'name' => 'Daily Visitors', 'initial_value' => 0, 'step' => 1 ]); // Create model-specific counters Counter::create([ 'key' => 'page_views', 'name' => 'Page Views', 'initial_value' => 0, 'step' => 1 ]); } }
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
This package is open-sourced software licensed under the MIT license.
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with ❤️ by Nur Wachid