avtonom/limit-number-calls-bundle
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require avtonom/limit-number-calls-bundle ~1.1
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3):
return [
// ...
Avtonom\LimitNumberCallsBundle\AvtonomLimitNumberCallsBundle::class => ['all' => true],
Snc\RedisBundle\SncRedisBundle::class => ['all' => true],
];
Redis Configuration (in config/packages/snc_redis.yaml):
snc_redis:
clients:
default:
type: predis
dsn: redis://localhost
alias: snc_redis_lnc
Define Rules (in config/packages/avtonom_limit_number_calls.yaml):
avtonom_limit_number_calls:
rules:
login_attempts:
time_period: 60000000 # 1 minute in microseconds
maximum_number: 5
blocking_duration: 300 # 5 minutes in seconds
subject_class: App\Entity\User
subject_method: [getEmail]
First Use Case: Check if a user can perform an action (e.g., login) without exceeding limits:
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
public function loginAction(AuthorizationCheckerInterface $checker, User $user)
{
if (!$checker->isGranted('login_attempts', $user)) {
throw new \RuntimeException('Too many login attempts. Try again later.', 429);
}
// Proceed with login logic...
}
Rule Definition:
config/packages/avtonom_limit_number_calls.yaml with:
time_period: Window for allowed requests (microseconds).maximum_number: Max allowed requests in time_period.blocking_duration: Lockout duration if exceeded (seconds).subject_class: Entity/class to extract values from (e.g., User).subject_method: Method(s) to fetch unique identifiers (e.g., [getEmail], [getIp, getUserAgent]).group (e.g., sms_group) for shared logic.Integration with Security:
// Symfony 4+
if (!$this->authorizationChecker->isGranted('sms_group', $smsRequest)) {
throw new TooManyRequestsHttpException();
}
$this->container->get('avtonom_limit_number_calls.checker')->check('rule_name', $object);
Logging Requests:
php bin/console avtonom:limit-calls:add login_attempts $user->getEmail()
$this->container->get('avtonom_limit_number_calls.logger')->log('rule_name', $value);
Handling Blocked Requests:
429 Too Many Requests for blocked users:
if (!$checker->isGranted('rule_name', $object)) {
return new JsonResponse(['error' => 'Too many requests'], 429);
}
Group-Based Rules:
sms_group):
rules:
sms_1m_10:
group: sms_group
time_period: 60000000
maximum_number: 10
sms_1m_1:
group: sms_group
time_period: 60000000
maximum_number: 1
$checker->isGranted('sms_group', $smsRequest);
Dynamic Rule Loading:
$rules = $this->fetchRulesFromDatabase();
$this->container->get('avtonom_limit_number_calls.manager')->setRules($rules);
Custom Voter:
use Avtonom\LimitNumberCallsBundle\Security\Voter\LimitNumberCallsVoter;
class CustomVoter extends LimitNumberCallsVoter {
protected function supports($attribute, $subject) {
return $attribute === 'custom_rule' && $subject instanceof CustomEntity;
}
}
services.yaml:
services:
App\Security\CustomVoter:
tags: [security.voter]
Event-Based Logging:
kernel.request) to auto-log requests:
$this->container->get('avtonom_limit_number_calls.logger')->log('rule_name', $value);
Redis Cluster Support:
snc_redis for clustering:
snc_redis:
clients:
default:
type: predis
dsn: redis://cluster-node1:6379,redis://cluster-node2:6379
Redis Connection Issues:
php bin/console snc:redis:ping
6379:6379).Microsecond Precision:
time_period uses microseconds, not milliseconds. Convert carefully:
# 1 minute = 60 seconds = 60 * 1,000,000 microseconds
time_period: 60000000
Subject Method Mismatches:
subject_method returns null or invalid data, the rule may fail silently. Validate methods:
$value = $object->getEmail(); // Ensure this returns a string/unique value
Blocking Duration:
blocking_duration is in seconds, not microseconds. A value of 600 = 10 minutes.Rule Overrides:
enabled: false in config does not remove it from checks. Use null or omit the rule to exclude it entirely.Symfony Version Compatibility:
security.authorization_checker is used (not security.context).Memory Leaks:
blocking_duration, but monitor memory usage with:
php bin/console avtonom:limit-calls:status
Check Blocked Values:
php bin/console avtonom:limit-calls:status
Clear Statistics:
php bin/console avtonom:limit-calls:clear email@example.com
Log Manual Requests:
php bin/console avtonom:limit-calls:add login_attempts user@example.com
Enable Debugging:
logging: true in snc_redis config to log Redis operations:
snc_redis:
clients:
default:
logging: true
Custom Error Handling:
throw new \RuntimeException('Rule "login_attempts" blocked. Retry in ' . $remainingSeconds . ' seconds.', 429);
Avtonom\LimitNumberCallsBundle\Storage\StorageInterface to use PostgreSQL or Memcached:
class CustomStorage implements StorageInterface {
public function increment($key, $ttl) { /* ... */ }
public function isBlocked($key) { /* ... */ }
}
services.yaml:
services:
Avtonom\LimitNumberCallsBundle\Storage\
How can I help you explore Laravel packages today?