Overview
Eufaturo Billing is built with modern PHP patterns and best practices. Understanding the architecture will help you effectively use the package and extend it for your needs.Core Principles
1. Gateway-Agnostic Design
The billing logic is completely separated from payment gateway implementations:- ✅ Switch gateways without changing business logic
- ✅ Support multiple gateways simultaneously
- ✅ Test billing logic without real payment processing
- ✅ Add new gateways without modifying core code
2. Action-Based Architecture
All business operations use the Action pattern:- Single responsibility principle
- Easy to test in isolation
- Clear dependencies via constructor injection
- Transactional integrity (automatic rollback on error)
- Reusable across controllers, commands, jobs
3. Domain-Driven Structure
Code is organized by business domain, not technical layer:- ✅ Easy to find related code
- ✅ Clear separation of concerns
- ✅ Scales well as codebase grows
- ✅ Each domain is self-contained
Architecture Layers
Layer 1: Facade Layer
Entry point for developers:- Provides consistent API across all domains
- Hides complexity from end users
- Manages dependency resolution
- Request-scoped memoization
Layer 2: Manager Layer
Domain managers coordinate actions:- Inject and coordinate actions
- Provide friendly developer API
- Convert parameters to DTOs
- Keep actions focused
Layer 3: Action Layer
Single-responsibility business logic:- Encapsulate single business operation
- Handle database transactions
- Throw exceptions on failure (auto-rollback)
- Emit domain events
- Keep business logic testable
Layer 4: Data Layer
Models and relationships:- Database interaction only
- No business logic
- Relationships and accessors
- Type casting
The Action Pattern in Detail
Anatomy of an Action
Why readonly?
Actions are declaredreadonly for immutability:
- Thread-safe
- Prevents accidental state mutation
- Forces stateless design
- Better performance (no property reassignment)
The DTO Pattern
What are DTOs?
Data Transfer Objects are immutable containers for method parameters:Why DTOs?
Without DTOs (method hell):- ✅ Single parameter instead of many
- ✅ Type-safe at compile time
- ✅ Named parameters at call site
- ✅ Easy to add new fields (no breaking changes)
- ✅ Self-documenting
Database Design
Table Naming Convention
All billing tables are prefixed withbilling_:
- Clear separation from app tables
- No naming conflicts
- Easy to identify billing-related data
Polymorphic Relationships
Many tables use polymorphic relationships:- Gateway records (subscriptions, plans, customers)
- Discounts (subscriptions, orders)
- Transactions (subscriptions, orders)
Soft Deletes
Most models use soft deletes:- ✅ Safe deletion (can restore)
- ✅ Preserve historical data
- ✅ Audit trail intact
- ✅ Relationships preserved
Dependency Injection
Constructor Injection
All dependencies are injected via constructor:Interface Binding
Bind interfaces to implementations in service provider:Event System
Domain Events
Actions emit events after successful operations:SubscriptionCreatedSubscriptionCancelledPlanChangedPaymentReceivedPaymentFailed- … and more
Listening to Events
Testing Architecture
Action Testing
Test actions in isolation:Transaction Rollback Testing
Test that transactions rollback on error:Extending the Package
Adding Custom Actions
Create your own actions following the same pattern:Extending Managers
Managers are notfinal, so you can extend them:
Best Practices
✅ Do
- Use actions for all business logic
- Keep models thin (data only)
- Use DTOs for complex parameters
- Wrap operations in transactions
- Emit events after success
- Test actions in isolation
- Follow domain-driven structure
❌ Don’t
- Put business logic in models
- Call actions from other actions directly
- Skip transaction management
- Emit events before commit
- Bypass managers (use Billing facade)
- Mix domains in single file
Architecture Diagrams
Request Flow
Subscription Creation Flow
Performance Considerations
Memoization
Managers are memoized for request-scoped singleton:Eager Loading
Always eager load relationships:Next Steps
Billable Interface
Make any model billable
Actions & DTOs
Deep dive into the action pattern
Gateway-Agnostic
How gateway abstraction works
Quick Start
Start building with Eufaturo Billing