Installation
Add the bundle to your composer.json:
composer require ekyna/subscription-bundle
Register the bundle in config/bundles.php (Symfony):
Ekyna\SubscriptionBundle\EkynaSubscriptionBundle::class => ['all' => true],
Database Migrations
Check the migrations/ folder in the bundle for tables (subscriptions, pricing, etc.). Run:
php artisan migrate
(Note: The package lacks a README for migrations, so inspect the bundle’s src/Resources/migrations for schema details.)
First Use Case: Create a Subscription Plan
Define a pricing plan via the Pricing entity:
use Ekyna\SubscriptionBundle\Entity\Pricing;
$pricing = new Pricing();
$pricing->setName('Premium Plan')
->setPrice(9.99)
->setCurrency('USD')
->setPeriod('monthly');
$em->persist($pricing);
$em->flush();
Key Classes to Explore
Ekyna\SubscriptionBundle\Entity\Subscription: Core subscription logic.Ekyna\SubscriptionBundle\Service\SubscriptionManager: Handles subscription lifecycle (e.g., activation, cancellation).Ekyna\SubscriptionBundle\Form\SubscriptionType: Pre-built forms for CRUD operations.Subscription Creation
Use the SubscriptionManager to create and manage subscriptions:
$subscription = $subscriptionManager->create(
$user, // User entity
$pricing, // Pricing entity
new \DateTime(),// Start date
new \DateTime('+1 year') // End date
);
Recurring Billing Integration Extend the bundle to hook into a payment processor (e.g., Stripe) by implementing:
use Ekyna\SubscriptionBundle\Event\SubscriptionEvent;
$dispatcher->addListener(SubscriptionEvent::PRE_CHARGE, function (SubscriptionEvent $event) {
// Call Stripe API here
});
User Access Control Check subscription status in middleware or policies:
public function authorize($user, $subscription)
{
return $user->getSubscriptions()->contains(function ($sub) use ($subscription) {
return $sub->getId() === $subscription->getId() && $sub->isActive();
});
}
Reporting Query active subscriptions with Doctrine:
$activeSubscriptions = $em->getRepository(Subscription::class)
->findBy(['endDate' => new \DateTime('>=' . date('Y-m-d'))]);
SubscriptionType for quick CRUD interfaces.# config/api_platform/resources.yaml
resources:
Ekyna\SubscriptionBundle\Entity\Subscription:
collectionOperations:
- get
itemOperations:
- get
SubscriptionManager in unit tests to isolate logic.Outdated Codebase
EventDispatcher without PSR-14).config/packages/ekyna_subscription.yaml to adapt to modern Laravel/Symfony:
services:
Ekyna\SubscriptionBundle\Service\SubscriptionManager:
arguments:
$entityManager: '@doctrine.orm.entity_manager'
Missing Documentation
README for migrations, entities, or events. Workaround:
src/Entity/ for fields (e.g., Subscription has user_id, pricing_id, start_date, end_date).SubscriptionManager methods.Hardcoded Logic
TODO) may require manual validation:
if ($pricing->getSubscriptions()->count() > 0) {
throw new \RuntimeException('Cannot edit pricing with active subscriptions.');
}
No Built-in Payment Handling
SubscriptionEvent::PRE_CHARGE to call Stripe/PayPal.Subscription field (e.g., paymentReference).Annotation mappings with your doctrine/orm config.services.yaml:
listeners:
Ekyna\SubscriptionBundle\EventListener\SubscriptionListener:
tags: ['kernel.event_listener']
Carbon for dates to avoid timezone issues:
$subscription->setEndDate(Carbon::now()->addYear());
Custom Fields
Add fields to Subscription via Doctrine extensions or a proxy:
// src/Entity/Subscription.php
/**
* @ORM\Column(nullable=true)
*/
private $customField;
Webhooks Listen for external payment events (e.g., Stripe webhooks) and update subscriptions:
$dispatcher->dispatch(new SubscriptionEvent(
SubscriptionEvent::PAYMENT_SUCCESS,
$subscription
));
Testing
Use SubscriptionManager’s testability to mock dependencies:
$manager = $this->createMock(SubscriptionManager::class);
$manager->method('create')->willReturn($subscription);
How can I help you explore Laravel packages today?