tourze / counter-bundle
Symfony Counter Bundle
Installs: 32
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/tourze/counter-bundle
Requires
- php: ^8.1
- doctrine/common: ^3.5
- doctrine/dbal: ^4.0
- doctrine/doctrine-bundle: ^2.13
- doctrine/orm: ^3.0
- doctrine/persistence: ^3.1 || ^4
- easycorp/easyadmin-bundle: ^4
- nesbot/carbon: ^2.72 || ^3
- psr/log: ^3|^2|^1
- symfony/config: ^6.4
- symfony/console: ^6.4
- symfony/dependency-injection: ^6.4
- symfony/doctrine-bridge: ^6.4
- symfony/event-dispatcher: ^6.4
- symfony/framework-bundle: ^6.4
- symfony/http-kernel: ^6.4
- symfony/service-contracts: ^3.5
- symfony/yaml: ^6.4 || ^7.1
- tourze/bundle-dependency: 0.0.*
- tourze/doctrine-indexed-bundle: 0.0.*
- tourze/doctrine-timestamp-bundle: 0.0.*
- tourze/symfony-cron-job-bundle: 0.1.*
- tourze/symfony-integration-test-kernel: 0.0.*
- tourze/symfony-lock-command-bundle: 0.0.*
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.0
- symfony/phpunit-bridge: ^6.4
README
A high-performance Symfony bundle for managing counters and statistics with automatic entity counting, manual operations, and scheduled updates.
Table of Contents
- Features
- Installation
- Requirements
- Configuration
- Usage
- Advanced Features
- Architecture
- Best Practices
- Troubleshooting
- Contributing
- License
Features
- π Automatic Entity Counting - Tracks entity counts through Doctrine events
- π Performance Optimized - Uses estimation for large tables (>1M records)
- π Real-time Updates - Counters update automatically on entity changes
- β° Scheduled Refresh - Cron-based counter synchronization
- π― Custom Providers - Extensible counter provider system
- π Thread-safe Operations - Lock mechanism prevents concurrent updates
- π Context Support - Store additional metadata with counters
Installation
composer require tourze/counter-bundle
Requirements
- PHP 8.1+
- Symfony 6.4+
- Doctrine ORM 3.0+
Configuration
1. Enable the Bundle
Register the bundle in config/bundles.php:
return [ // ... CounterBundle\CounterBundle::class => ['all' => true], ];
2. Update Database Schema
# Create the counter table php bin/console doctrine:schema:update --force # Or use migrations php bin/console doctrine:migrations:diff php bin/console doctrine:migrations:migrate
Usage
Basic Counter Operations
use CounterBundle\Repository\CounterRepository; use CounterBundle\Provider\EntityTotalCountProvider; class StatisticsService { public function __construct( private readonly CounterRepository $counterRepository, private readonly EntityTotalCountProvider $countProvider ) {} public function getStatistics(): array { // Get counter by name $userCounter = $this->counterRepository->findOneBy([ 'name' => 'App\Entity\User::total' ]); // Manual increment/decrement $this->countProvider->increaseEntityCounter('App\Entity\Product'); $this->countProvider->decreaseEntityCounter('App\Entity\Product'); return [ 'users' => $userCounter?->getCount() ?? 0, 'products' => $this->counterRepository->findOneBy([ 'name' => 'App\Entity\Product::total' ])?->getCount() ?? 0, ]; } }
Automatic Entity Counting
The bundle automatically tracks entity counts through Doctrine listeners:
namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Product { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] private ?int $id = null; // ... other properties } // Counters are automatically created: // - "App\Entity\Product::total" - Total count of products
Custom Counter Providers
Create custom counters by implementing CounterProvider:
use CounterBundle\Provider\CounterProvider; use CounterBundle\Entity\Counter; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; #[AutoconfigureTag('app.counter.provider')] class OrderStatisticsProvider implements CounterProvider { public function __construct( private readonly OrderRepository $orderRepository ) {} public function getCounters(): iterable { // Pending orders counter $pendingCount = $this->orderRepository->count(['status' => 'pending']); $pendingCounter = new Counter(); $pendingCounter->setName('orders.pending') ->setCount($pendingCount) ->setContext(['status' => 'pending']); yield $pendingCounter; // Completed orders counter $completedCount = $this->orderRepository->count(['status' => 'completed']); $completedCounter = new Counter(); $completedCounter->setName('orders.completed') ->setCount($completedCount) ->setContext(['status' => 'completed']); yield $completedCounter; } }
Scheduled Updates
Counters are automatically refreshed every hour at minute 30:
# Run the refresh command manually php bin/console counter:refresh-counter # Or set up cron job 30 * * * * php /path/to/project/bin/console counter:refresh-counter
Performance Optimization
The bundle automatically optimizes counting for large tables:
// For tables with <1M records: uses COUNT(*) // For tables with >1M records: uses table statistics from information_schema $counter = $this->countProvider->getCounterByEntityClass( 'App\Entity\LargeTable' ); // Automatically uses estimation for performance
Advanced Features
Context Storage
Store additional metadata with counters:
$counter = new Counter(); $counter->setName('api.requests') ->setCount(1000) ->setContext([ 'endpoint' => '/api/users', 'method' => 'GET', 'date' => '2024-01-01' ]);
Event Listeners
The bundle provides event subscribers for automatic counting:
- EntityListener- Tracks entity creation/deletion
- Implements ResetInterfacefor memory management
- Uses batch processing to minimize database queries
Console Commands
# Refresh all counters php bin/console counter:refresh-counter # The command is lockable to prevent concurrent execution
Architecture
Components
- Entity/Counter - The main counter entity with timestamp support
- Repository/CounterRepository - Repository for counter operations
- Provider/EntityTotalCountProvider - Handles entity counting logic
- EventSubscriber/EntityListener - Tracks Doctrine events
- Command/RefreshCounterCommand - Scheduled counter updates
Database Schema
CREATE TABLE table_count ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) UNIQUE NOT NULL, count INT NOT NULL DEFAULT 0, context JSON, create_time DATETIME NOT NULL, update_time DATETIME NOT NULL );
Best Practices
- Use providers for complex counters - Don't calculate counts in real-time for complex queries
- Leverage context - Store filtering criteria in context for debugging
- Monitor performance - Check logs for estimation warnings on large tables
- Regular updates - Ensure cron job is running for accurate counts
Troubleshooting
Counters not updating
- 
Check if entity listener is registered: php bin/console debug:event-dispatcher doctrine.orm.entity_manager 
- 
Verify cron job is running: php bin/console debug:command counter:refresh-counter 
Performance issues
- 
Check table sizes: SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = 'your_database'; 
- 
Monitor query performance in Symfony profiler 
Contributing
Please see CONTRIBUTING.md for details.
License
The MIT License (MIT). Please see License File for more information.