Installation
composer require chill-project/budget
Add the bundle to your config/bundles.php:
return [
// ...
Chill\Budget\BudgetBundle::class => ['all' => true],
];
Database Migration Run the migrations to create required tables:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Use Case Create a budget for a user (e.g., in a controller):
use Chill\Budget\Budget;
use Chill\Budget\BudgetRepository;
$budgetRepo = $this->getDoctrine()->getRepository(Budget::class);
$budget = $budgetRepo->createBudgetForUser($user, '2024', 'Monthly');
$budgetRepo->save($budget);
Key Classes to Explore
Budget (entity): Represents a budget (e.g., monthly, yearly).BudgetItem (entity): Tracks individual budget entries (income/expense).BudgetRepository: CRUD operations for budgets.BudgetService: Business logic (e.g., validation, calculations).$budget = $budgetService->createBudget($user, '2024', 'Monthly', 2000); // $2k limit
$budgetService->createBudgetsForUsers($users, '2024', 'Yearly');
$budgetItem = $budgetService->addItem($budget, 'Rent', -500, 'Expense');
$budgetItem = $budgetService->addItem($budget, 'Salary', 3000, 'Income');
$budgetService->addRule($budget, 'max_expenses', 3); // Limit to 3 expenses
$budgetService->addRule($budget, 'min_income', 2500); // Require $2.5k income
if (!$budgetService->isValid($budget)) {
$errors = $budgetService->getValidationErrors($budget);
}
$summary = $budgetService->getSummary($budget);
// Returns: ['total_income', 'total_expense', 'balance', 'items']
$monthlyReport = $budgetService->generateMonthlyReport($user, '2024-01');
User entity to include a budget relationship:
// src/Entity/User.php
/**
* @ORM\OneToOne(targetEntity="Chill\Budget\Budget", mappedBy="user")
*/
private $budget;
// config/services.yaml
Chill\Budget\EventListener\BudgetListener::class:
tags:
- { name: doctrine.event_listener, event: postPersist }
- { name: doctrine.event_listener, event: postUpdate }
Use Symfony’s ApiPlatform or FOSRestBundle to expose budgets:
# config/api_platform/resources.yaml
resources:
Chill\Budget\Entity\Budget:
collectionOperations:
get: ~
post: ~
itemOperations:
get: ~
put: ~
delete: ~
Vue/React Hooks:
Subscribe to budget changes via WebSocket (e.g., Mercure):
// Subscribe to budget updates
const eventSource = new EventSource('/.well-known/mercure?topic=/updates/budget');
eventSource.onmessage = (e) => {
const data = JSON.parse(e.data);
this.budget = data.budget;
};
Templates: Use Twig to display budgets:
{% for item in budget.items %}
<div class="budget-item">
{{ item.label }}: {{ item.amount | currency }}
<span class="type {{ item.type|lower }}">
{{ item.type }}
</span>
</div>
{% endfor %}
Circular Dependencies
Budget and User entities. Use lazy loading or explicit fetch in repositories:
$budget = $budgetRepo->findOneBy(['user' => $user], ['items' => 'LEFT']);
Validation Overhead
$budgetService->cacheValidation($budget, 3600); // Cache for 1 hour
Concurrency Issues
// In Budget.php
/**
* @ORM\Versioned
*/
private $version;
Date Handling
getPeriod() method in Budget if needed:
public function getPeriod(): string
{
return Carbon::parse($this->startDate)->format('Y-m');
}
Query Logging Enable Doctrine debugging to inspect queries:
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
logging: true
profiler: true
Common Errors
BudgetPeriodNotFoundException: Ensure the period (e.g., "2024") matches the Budget entity’s period field.ValidationFailedException: Check rules in BudgetService and validate manually:
$budgetService->validate($budget);
Event Debugging Dump events in a listener:
use Symfony\Component\HttpKernel\Event\KernelEvent;
public function onKernelRequest(KernelEvent $event)
{
if ($event->isMainRequest()) {
dump($event->getRequest()->attributes->all());
}
}
Extending Functionality
BudgetType entity and extend Budget:
// src/Entity/CustomBudget.php
class CustomBudget extends Budget
{
private $customField;
// Add getters/setters and override methods as needed.
}
CompilerPass to dynamically register services:
public function process(ContainerBuilder $container)
{
$container->register('custom_budget_plugin', CustomBudgetPlugin::class)
->addTag('chill.budget.plugin');
}
Performance
BATCH_SIZE for bulk inserts:
$em->getConnection()->getConfiguration()->setSQLLogger(null); // Disable logging
$em->flush();
$em->getConnection()->getConfiguration()->setSQLLogger($logger);
user_id, period):
/**
* @ORM\Index(name="idx_user_period", columns={"user_id", "period"})
*/
Testing
Nelmio/AliceBundle to seed test data:
# tests/fixtures/budget.yml
Chill\Budget\Entity\Budget:
budget1:
user: user1
period: '2024'
type: 'Monthly'
limit: 2000
BudgetService in unit tests:
$budgetService = $this->createMock(BudgetService::class);
$budgetService->method('isValid')->willReturn(true);
Configuration
config/packages/chill_budget.yaml:
How can I help you explore Laravel packages today?