I’m building a double entry accounting system. The balance of each account is calculated using a simple sum algorithm and maintained as a field on each account. The only way which I’ve discovered to update an accounts balance when a post happens for an account is to use a postPersist event handler to update the account. I think this is the right way to do it but I’m not 100% sure. Everything seems to work in my testing. Below is my doctrine subscriber.
Also I’m a little concerned about the race condition of two accounts being updated simultaneously. Which is a very likely case for the account(s) associated with the site rather than an individual customer. However, the only other way I can think to do this is to use triggers. However, that seems as if it would defeat the whole purpose of Doctrine in the first place.
<?php namespace Modules\Accounting\Subscribers;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Events;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Modules\Customer\Entities\Customer as CustomerEntity;
use Modules\Accounting\Entities\Account as AccountEntity;
use Modules\Sales\Entities\Sale as SaleEntity;
use Modules\Accounting\Repositories\AccountTypeRepository;
use Modules\Accounting\Repositories\PostingEventRepository;
use Modules\Accounting\Repositories\AssetTypeRepository;
use Modules\Accounting\Repositories\AccountRepository;
use Carbon\Carbon;
use Modules\Accounting\Entities\Posting as PostingEntity;
class DoctrineSubscriber implements EventSubscriber {
public function getSubscribedEvents() {
return [
Events::postPersist,
];
}
/**
* postPersist handler
*
* @param LifecycleEventArgs $event
*/
public function postPersist(LifecycleEventArgs $event) {
$em = $event->getObjectManager();
$entity = $event->getObject();
if($entity instanceof PostingEntity) {
$this->recalculateAccountBalance($event);
}
}
/**
* Recalculate the balance of the associated account.
*
* @param LifecycleEventArgs $event
*/
protected function recalculateAccountBalance(LifecycleEventArgs $event) {
$em = $event->getObjectManager();
$posting = $event->getObject();
$accountRepo = app(AccountRepository::class);
$account = $posting->getAccount();
$balance = $accountRepo->calculateAccountBalance($account);
$account->setBalance($balance);
// Is it appropriate to be calling these in postPersist :/
$em->persist($account);
$em->flush();
}
}