creonit/verification-code-bundle
Installation:
composer require creonit/verification-code-bundle
Add the bundle to config/bundles.php:
return [
// ...
Creonit\VerificationCodeBundle\CreonitVerificationCodeBundle::class => ['all' => true],
];
Basic Configuration:
Update config/packages/creonit_verification_code.yaml with default values:
creonit_verification_code:
generator:
config:
length: 6 # Default code length
First Use Case: Trigger a verification code for a phone number via the API route:
POST /api/verification-code/send?scope=phone&key=+1234567890
scopes.phone.key_pattern.Sending Verification Codes: Use the API endpoint to trigger code generation and delivery (e.g., SMS/email):
// In a controller or service
$verificationCodeService = $this->get('creonit_verification_code.service');
$result = $verificationCodeService->send('phone', '+1234567890');
scope: Key from scopes (e.g., phone, email).key: User identifier (e.g., phone number, email).template (for custom delivery logic).Validation: Verify a submitted code:
$isValid = $verificationCodeService->validate('phone', '+1234567890', '123456');
true if the code matches and hasn’t expired (based on max_age in config).Custom Scopes:
Define new scopes in config/packages/creonit_verification_code.yaml:
scopes:
email:
key_pattern: '/^[^\s@]+@[^\s@]+\.[^\s@]+$/' # Basic email regex
max_age: 300 # 5 minutes
attempt_time: 60 # 1 minute between attempts
Delivery Logic:
Extend the bundle’s Delivery service to integrate with SMS/email providers (e.g., Twilio, Mailgun). Override:
// src/Service/VerificationCodeDelivery.php
use Creonit\VerificationCodeBundle\Delivery\VerificationCodeDeliveryInterface;
class CustomVerificationCodeDelivery implements VerificationCodeDeliveryInterface {
public function send(string $scope, string $key, string $code): bool {
// Custom logic (e.g., Twilio API call)
return true;
}
}
Register the service in services.yaml:
services:
Creonit\VerificationCodeBundle\Delivery\VerificationCodeDeliveryInterface: '@App\Service\CustomVerificationCodeDelivery'
Database Storage:
By default, codes are stored in the session. For persistence, implement a custom Storage service:
use Creonit\VerificationCodeBundle\Storage\VerificationCodeStorageInterface;
class DatabaseVerificationCodeStorage implements VerificationCodeStorageInterface {
public function store(string $scope, string $key, string $code, int $maxAge): void {
// Save to DB (e.g., using Doctrine)
}
public function retrieve(string $scope, string $key): ?string {
// Fetch from DB
}
}
Bind it in services.yaml:
services:
Creonit\VerificationCodeBundle\Storage\VerificationCodeStorageInterface: '@App\Service\DatabaseVerificationCodeStorage'
Rate Limiting:
Use the attempt_time config to enforce delays between retries. For stricter control, integrate with Laravel’s throttle middleware or a package like spatie/rate-limiter.
Regex Patterns:
key_pattern in scopes uses PCRE syntax. Test patterns thoroughly (e.g., +1 (123) 456-7890 vs. +11234567890).key_pattern: '/^\+(?:[0-9] ?){6,14}[0-9]$/'
Session Storage:
Time Zones:
max_age and attempt_time use the server’s time zone. Ensure consistency with config/app.php:
'timezone' => 'UTC', // or your preferred timezone
Custom Generator Validation:
AbstractCodeGenerator, always call parent::validateConfig() to inherit default validation:
protected function validateConfig(array $config) {
parent::validateConfig($config); // Inherit base validation
// Add custom checks
}
Log Delivery Failures:
Wrap delivery logic in a try-catch to log errors:
try {
$delivery->send($scope, $key, $code);
} catch (\Exception $e) {
\Log::error("Failed to send verification code to {$key}: " . $e->getMessage());
}
Check Code Expiry: Use Tinker to inspect stored codes (if using session storage):
php artisan tinker
>> session()->get('verification_codes');
Event Listeners: Subscribe to events for custom logic (e.g., logging, analytics):
// src/EventListener/VerificationCodeListener.php
use Creonit\VerificationCodeBundle\Event\VerificationCodeSentEvent;
class VerificationCodeListener {
public function onCodeSent(VerificationCodeSentEvent $event) {
// Example: Log to a custom table
\Log::info("Code sent to {$event->getKey()}");
}
}
Register in services.yaml:
services:
App\EventListener\VerificationCodeListener:
tags:
- { name: kernel.event_listener, event: creonit_verification_code.sent, method: onCodeSent }
Dynamic Scopes:
Load scopes dynamically (e.g., from a database) by implementing a ScopeProvider:
use Creonit\VerificationCodeBundle\Provider\ScopeProviderInterface;
class DatabaseScopeProvider implements ScopeProviderInterface {
public function getScopes(): array {
return [
'phone' => [
'key_pattern' => '/^\+...$/',
'max_age' => 180,
],
// ...
];
}
}
Bind in services.yaml:
services:
Creonit\VerificationCodeBundle\Provider\ScopeProviderInterface: '@App\Service\DatabaseScopeProvider'
Testing:
Mock the VerificationCodeService in tests:
$mockService = $this->createMock(VerificationCodeService::class);
$mockService->method('send')->willReturn(true);
$this->app->instance('creonit_verification_code.service', $mockService);
Overriding Defaults:
To override the default generator (e.g., NumericCodeGenerator), ensure the service ID matches exactly:
creonit_verification_code:
generator:
service: '@App\MyCodeGenerator' # Must match the service ID
Environment-Specific Config: Use Laravel’s environment variables for dynamic values:
scopes:
phone:
max_age: '%env(intVERIFICATION_CODE_MAX_AGE, 180)%'
How can I help you explore Laravel packages today?